{*******************************************************************} { } { Developer Express Visual Component Library } { ExpressQuantumTreeList control } { } { Copyright (c) 1998-2009 Developer Express Inc. } { ALL RIGHTS RESERVED } { } { The entire contents of this file is protected by U.S. and } { International Copyright Laws. Unauthorized reproduction, } { reverse-engineering, and distribution of all or any portion of } { the code contained in this file is strictly prohibited and may } { result in severe civil and criminal penalties and will be } { prosecuted to the maximum extent possible under the law. } { } { RESTRICTIONS } { } { THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES } { (DCU, OBJ, DLL, ETC.) ARE CONFIDENTIAL AND PROPRIETARY TRADE } { SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS } { LICENSED TO DISTRIBUTE THE EXPRESSGRID AND ALL ACCOMPANYING VCL } { CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY. } { } { THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED } { FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE } { COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE } { AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT } { AND PERMISSION FROM DEVELOPER EXPRESS INC. } { } { CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON } { ADDITIONAL RESTRICTIONS. } { } {*******************************************************************} unit dxTL; interface {$I dxTLVer.inc} uses SysUtils, Messages, Windows, Classes, Graphics, Menus, Controls, Forms, StdCtrls, Mask, CommCtrl {$IFDEF DELPHI4}, ImgList{$ENDIF}, dxTLStr, Clipbrd, dxCntner, dxEditor, ComCtrls, dxUtils{$IFDEF DELPHI6}, Variants{$ENDIF}; const dxTreeListMaxResizeWidth = 4; dxclArrows = clLime; // Timer interval tiHScroll = 100; {ms} tiVScroll = 100; {ms} // Arrowa size arWidth = 11; arHeight = 9; {Colors} dxclTreeLineHighColor = clBtnFace; {clSilver} dxclTreeLineShadowColor = clBtnShadow; {clGray} crdxTreeListDeleteCursor = -1124; dxTreeListDeleteCursor = 'DXTLDELETECURSOR'; crdxTreeListFullScroll = -1131; crdxTreeListHorScroll = -1132; crdxTreeListVerScroll = -1133; crdxTreeListUpScroll = -1134; crdxTreeListRightScroll = -1135; crdxTreeListDownScroll = -1136; crdxTreeListLeftScroll = -1137; crdxTreeListDragCopy = -1138; crdxTreeListMultiDragCopy = -1139; // Draw Info constants dxGridMaxDrawItems = 100000; dxGridFixedBandLineWidth = 2; dxGridSortedShapeMinWidth = 16; dxGridPreviewMaxLineCount = 60; // Bands constants dxGridBandMinWidth = 30; dxGridBandDefaultWidth = 250; // Headers constants dxGridHeaderMinWidth = 20; dxGridHeaderTempIndex = -2; dxGridHeaderNewIndex = -3; dxGridHeaderFilterBoxWidth = 15; // Status line dxGridStatusCloseButtonSizeX = 12; dxGridStatusCloseButtonSizeY = 11; dxGridStatusCloseButtonWidth = dxGridStatusCloseButtonSizeX + 3 * 2; dxGridStatusCloseButtonMinHeight = dxGridStatusCloseButtonSizeY + 3 * 2; dxDragExapndTimerId = 101; dxWaitForExpandNodeTime = 500; dxCustomizingRowCount = 11; type {$IFDEF EGRID_DEBUG} TdxDBGridEventType = (etLoadData, etSort, etRefreshNode); TdxDBGridDebugEvent = procedure(Sender: TObject; Event: TdxDBGridEventType; Count: LongInt) of object; {$ENDIF} EInvaliddxTreeListOperation = class(Exception); TCustomdxTreeList = class; TdxTreeListNode = class; TdxBandsListBox = class; TdxHeadersListBox = class; TdxTreeListNodeAttachMode = (natlAdd, natlAddFirst, natlAddChild, natlAddChildFirst, natlInsert); TdxTreeListOption = (aoColumnSizing, aoColumnMoving, aoEditing, aoTabs, aoTabThrough, aoRowSelect, aoMultiSelect, aoImmediateEditor, aoPreview, aoDrawEndEllipsis, aoAutoWidth, aoExtMultiSelect, aoExtCustomizing, aoHideFocusRect, aoAutoSort, aoCaseInsensitive, aoStoreToRegistry, aoStoreToIniFile); TdxTreeListOptions = set of TdxTreeListOption; TdxTreeListOptionEx = (aoInvertSelect, aoUseBitmap, aoBandHeaderWidth, aoAutoCalcPreviewLines, aoBandSizing, aoBandMoving, aoHorzThrough, aoVertThrough, aoCellMultiSelect, aoEnterThrough, aoEnterShowEditor, aoFullSizing, aoDragScroll, aoDragExpand, aoDragCollapse, aoRowAutoHeight, aoShowHourGlass, aoBandButtonClicking, aoBandPanelSizing, aoHeaderButtonClicking, aoHeaderPanelSizing, aoRowSizing, aoMultiSort, aoAutoSortRefresh, aoShowButtonAlways, aoAutoHeaderPanelHeight, aoKeepColumnWidth, aoAnsiSort, aoMouseScroll, aoAutoSearch, aoHotTrack, aoAutoCopySelectedToClipboard); TdxTreeListOptionsEx = set of TdxTreeListOptionEx; TdxTreeListState = (tsNormal, tsColumnSizing, tsEditing, tsColumnDragging, tsColumnDown, tsNodeDragging, tsNodeDown, tsHeaderButtonDown, tsBandSizing, tsBandDragging, tsBandDown, tsBandButtonDown, tsBandPanelSizing, tsHeaderPanelSizing, tsRowSizing, tsDropDownButtonDown, tsStatusCloseButtonDown); TdxTreeListHitTest = (htNowhere, htColumn, htColumnEdge, htButton, htIcon, htStateIcon, htIndent, htLabel, htRight, htOutside, htGroupPanel, htBandButton, htBand, htBandEdge, htHeaderButton, htIndicator, htNewRowItem, htSummaryNodeFooter, htSummaryFooter, htBandPanelEdge, htHeaderPanelEdge, htRowEdge, htPreview, htStatusPanel); TdxTreeListHitTests = set of TdxTreeListHitTest; TdxTreeListColumnSort = (csNone, csDown, csUp); TdxTreeListPaintStyle = (psStandard, psOutlook); TdxTreeListSearchDirection = (sdNone, sdUp, sdDown); TTLExpandingEvent = procedure(Sender: TObject; Node: TdxTreeListNode; var Allow: Boolean) of object; TTLExpandedEvent = procedure(Sender: TObject; Node: TdxTreeListNode) of object; TTLChangeNodeEvent = procedure(Sender: TObject; OldNode, Node: TdxTreeListNode) of object; TTLChangeColumnEvent = procedure(Sender: TObject; Node: TdxTreeListNode; Column: Integer) of object; TTLGetImageEvent = procedure(Sender: TObject; Node: TdxTreeListNode; var Index: Integer) of object; TdxTLCanNodeSelected = procedure(Sender: TObject; ANode: TdxTreeListNode; var Allow: Boolean) of object; TdxTLCompareEvent = procedure(Sender: TObject; Node1, Node2: TdxTreeListNode; var Compare: Integer) of object; TdxTLGetEditColor = procedure(Sender: TObject; var AColor: TColor) of object; TdxTLGetPreviewText = procedure(Sender: TObject; ANode: TdxTreeListNode; var AText: string) of object; TdxTLGetPreviewLineCount = procedure(Sender: TObject; ANode: TdxTreeListNode; var LCount: Integer) of object; TdxTLIsLevelFooter = procedure(Sender: TObject; ALevel: Integer; var AExist: Boolean) of object; TdxTLIsExistFooterCell = procedure(Sender: TObject; AColumn: Integer; var AExist: Boolean) of object; TdxTLIsExistRowFooterCell = procedure(Sender: TObject; ANode: TdxTreeListNode; AColumn, AFooterIndex: Integer; var AExist: Boolean) of object; TdxTLGetFooterCellText = procedure(Sender: TObject; ANode: TdxTreeListNode; AColumn, AFooterIndex: Integer; var AText: string) of object; TdxTreeListNode = class private FData: Pointer; FDeleting: Boolean; FExpanded: Boolean; FHasChildren: Boolean; FList: TList; FOwner: TCustomdxTreeList; FParent: TdxTreeListNode; FRowHeight: Integer; FRowLineCount: Integer; // NEW function GetAbsoluteIndex: Integer; function GetCount: Integer; function GetCountValues: Integer; function GetFocused: Boolean; function GetImageIndex: Integer; function GetIndex: Integer; function GetIsLast: Boolean; function GetIsNodeVisible: Boolean; function GetItem(Index: Integer): TdxTreeListNode; function GetLevel: Integer; function GetSelected: Boolean; function GetSelectedIndex: Integer; function GetStateIndex: Integer; function GetString(Column: Integer): string; function GetValue(Column: Integer): Variant; procedure SetData(Value: Pointer); procedure SetExpanded(Value: Boolean); procedure SetFocused(Value: Boolean); procedure SetHasChildren(Value: Boolean); procedure SetImageIndex(Value: Integer); procedure SetSelected(Value: Boolean); procedure SetSelectedIndex(Value: Integer); procedure SetStateIndex(Value: Integer); procedure SetString(Column: Integer; const Value: string); procedure SetValue(Column: Integer; const Value: Variant); protected procedure InternalMove(Destination: TdxTreeListNode; Mode: TdxTreeListNodeAttachMode); procedure InternalMoveAsChild(Destination: TdxTreeListNode; AIndex: Integer); procedure InternalMoveToRoot; procedure InternalRemove; procedure MoveChildrenToRoot; public constructor Create(AOwner: TCustomdxTreeList); destructor Destroy; override; function AddChild: TdxTreeListNode; function AddChildFirst: TdxTreeListNode; procedure AddNodesToList(List: TList); function CanMove(Destination: TdxTreeListNode; Mode: TdxTreeListNodeAttachMode): Boolean; procedure Collapse(Recurse: Boolean); procedure DeleteChildren; procedure Expand(Recurse: Boolean); function GetFirstChild: TdxTreeListNode; function GetLastChild: TdxTreeListNode; function GetNext: TdxTreeListNode; function GetNextNode: TdxTreeListNode; function GetNextSibling: TdxTreeListNode; function GetPrev: TdxTreeListNode; function GetPrevSibling: TdxTreeListNode; function GetPriorNode: TdxTreeListNode; function GetPriorParentNode: TdxTreeListNode; function HasAsParent(Value: TdxTreeListNode): Boolean; function IndexOf(Value: TdxTreeListNode) : Integer; function InsertChild(BeforeNode: TdxTreeListNode): TdxTreeListNode; procedure MakeVisible; procedure MoveTo(Destination: TdxTreeListNode; Mode: TdxTreeListNodeAttachMode); property AbsoluteIndex: Integer read GetAbsoluteIndex; property Count: Integer read GetCount; property CountValues: Integer read GetCountValues; property Data: Pointer read FData write SetData; property Deleting: Boolean read FDeleting; property Expanded: Boolean read FExpanded write SetExpanded; property Focused: Boolean read GetFocused write SetFocused; property HasChildren: Boolean read FHasChildren write SetHasChildren; property ImageIndex: Integer read GetImageIndex write SetImageIndex; property Index: Integer read GetIndex; property IsLast: Boolean read GetIsLast; property IsVisible: Boolean read GetIsNodeVisible; property Items[Index: Integer]: TdxTreeListNode read GetItem; default; property Level: Integer read GetLevel; property Owner: TCustomdxTreeList read FOwner; property Parent: TdxTreeListNode read FParent; property Selected: Boolean read GetSelected write SetSelected; property SelectedIndex: Integer read GetSelectedIndex write SetSelectedIndex; property StateIndex: Integer read GetStateIndex write SetStateIndex; property Strings[Index: Integer]: string read GetString write SetString; property Values[Index: Integer]: Variant read GetValue write SetValue; end; TdxLookAndFeel = (lfStandard, lfFlat, lfUltraFlat); TdxGridDrawCellKind = (ckRow, ckFooter, ckNewItemRow, ckGroup); TdxHeaderButtonStyle = (hbNormal, hbLeft, hbRight, hbLeftRight); TdxShowButtonStyle = (sbDefault, sbAlways, sbNone); TdxHeaderDropDownButtonKind = (hdbNormal, hdbSelected, hdbPushed, hdbActive); // TODO Filter TdxHeaderDropDownButtonState = set of TdxHeaderDropDownButtonKind; TdxTreeListHitInfo = record X, Y: Integer; // Client Band: Integer; // VisibleIndex Column: Integer; // AbsoluteIndex Node: TdxTreeListNode; Row: Integer; FooterRow: Integer; hitType: TdxTreeListHitTest; end; // Draw Info TdxTreeLineStyle = (tlSolid, tlDot); TdxGridIndicatorKind = (ikNone, ikArrow, ikEdit, ikInsert, ikMultiDot, ikMultiArrow); TdxGridBandDrawInfo = record Index: Integer; BandRect: TRect; BandClipRect: TRect; end; PdxGridBandsInfo = ^TdxGridBandsInfo; TdxGridBandsInfo = array [0..dxGridMaxDrawItems - 1] of TdxGridBandDrawInfo; TdxGridHeaderDrawInfo = record AbsoluteIndex: Integer; BandIndex, RowIndex, ColIndex: Integer; // BandIndex - visible index LineCount: Integer; HeaderRect: TRect; HeaderClipRect: TRect; HeaderEmptyRect: TRect; FirstColumn: Boolean; LastColumn: Boolean; LeftEdgeColumn: Boolean; RightEdgeColumn: Boolean; MultiLine: Boolean; end; PdxGridHeadersInfo = ^TdxGridHeadersInfo; TdxGridHeadersInfo = array [0..dxGridMaxDrawItems - 1] of TdxGridHeaderDrawInfo; TdxGridEmptyRectDrawInfo = record BandIndex: Integer; // BandIndex - visible index EmptyRect: TRect; ClippingFlag: Boolean; end; PdxGridEmptyRectsInfo = ^TdxGridEmptyRectsInfo; TdxGridEmptyRectsInfo = array [0..dxGridMaxDrawItems - 1] of TdxGridEmptyRectDrawInfo; TdxGridRowDrawInfo = record Node: TdxTreeListNode; IsGroup: Boolean; IsSelected: Boolean; RowHeight: Integer; RowFooterCount: Integer; RowFooterHeight: Integer; IndicatorKind: TdxGridIndicatorKind; PreviewLineCount: Integer; RowLineCount: Integer; Indent: Integer; end; PdxGridRowsInfo = ^TdxGridRowsInfo; TdxGridRowsInfo = array [0..dxGridMaxDrawItems - 1] of TdxGridRowDrawInfo; PdxGridDrawInfo = ^TdxGridDrawInfo; TdxGridDrawInfo = record CRect: TRect; GroupPanelRect: TRect; BandRect: TRect; BandButtonRect: TRect; HeaderRect: TRect; HeaderButtonRect: TRect; IndicatorRect: TRect; NewItemRowRect: TRect; CellsRect: TRect; EmptyRectRight, EmptyRectBottom: TRect; FooterRect: TRect; StatusRect: TRect; // fixed bands FixedBandLeftRect: TRect; FixedBandRightRect: TRect; FixedBandLeftIndex: Integer; FixedBandRightIndex: Integer; FixedBandPrevRightIndex: Integer; // edges EdgeX, EdgeY: Integer; IndentLimit: Integer; RowSeparatorLineWidth: Integer; // bands BandCount: Integer; BandsInfo: PdxGridBandsInfo; // headers HeaderCount: Integer; HeadersInfo: PdxGridHeadersInfo; // empty headers rect EmptyRectCount: Integer; EmptyRectsInfo: PdxGridEmptyRectsInfo; // rows RowCount: Integer; RowsInfo: PdxGridRowsInfo; end; PdxHeaderPosInfo = ^TdxHeaderPosInfo; TdxHeaderPosInfo = record BandIndex: Integer; RowIndex: Integer; ColIndex: Integer; AbsoluteIndex: Integer; end; TdxTreeListCellViewData = 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_InvertSelect: Boolean; Cell_LeftEdge: Boolean; Cell_RightEdge: Boolean; Cell_MultiLine: Boolean; Cell_InvertText: Boolean; Cell_DrawEndEllipsis: Boolean; Cell_Node: TdxTreeListNode; Cell_IsNullNode: Boolean; Cell_SelectionColor: TColor; Cell_CellBrush: HBRUSH; Cell_CellColor: TColor; Cell_HotTrackNode: Boolean; Cell_Rect: TRect; end; TdxTreeListHeaderHotTrack = (hhtNone, hhtBody, hhtDropDownButton, hhtDropDownButtonDisabled); TdxTreeListHotTrackInfo = record Node: TdxTreeListNode; Column: Integer; // AbsoluteIndex ActiveIndex: Integer; // HotButton (TODO) HeaderHotTrack: TdxTreeListHeaderHotTrack; end; TdxInplaceTreeListEdit = class(TdxInplaceEdit) public property Text; end; TdxTLHotTrackNode = procedure (Sender: TObject; AHotTrackInfo: TdxTreeListHotTrackInfo; var ACursor: TCursor) of object; TdxTreeListNavigationMode = (tlnmFirst, tlnmPrev, tlnmNext, tlnmLast); TCustomdxTreeList = class(TCustomdxContainer) private // Structure FNodeList: TList; FLockUpdate: Integer; FFocused: TdxTreeListNode; OldFocusedNode: TdxTreeListNode; FlagCtrl, FlagSelect, FlagEditor: Boolean; FListIndexes: TList; // get index of node FListNodes: TList; // get node at index FListRealNodes: TList; // get node at index FMakeListNodesFlag: Boolean; FMakeListNode: TdxTreeListNode; FMakeListNodeVisible: Boolean; FNodeDeleteing: Boolean; // Style FArrowsColor: TColor; FBandColor: TColor; FBandFont: TFont; FBorderStyle: TBorderStyle; FDblClkExpanding: Boolean; FFixedBandLineColor: TColor; FFlat: Boolean; FFooterColor: TColor; FFooterTextColor: TColor; FGridColor: TColor; FGridLineColor: TColor; FGroupColor: TColor; FGroupTextColor: TColor; FHeaderColor: TColor; FHeaderFont: TFont; FHideFocusRect: Boolean; FHideSelection: Boolean; FHideSelectionColor: TColor; FHideSelectionTextColor: TColor; FHighlightColor: TColor; FHighlightTextColor: TColor; FLookAndFeel: TdxLookAndFeel; FPaintStandard: Boolean; FPaintStyle: TdxTreeListPaintStyle; FPreviewFont: TFont; FScrollBars: TScrollStyle; FShowBands: Boolean; FShowButtons: Boolean; FShowFooter: Boolean; FShowGrid: Boolean; FShowHeaders: Boolean; FShowIndicator: Boolean; FShowLines: Boolean; FShowNewItemRow: Boolean; FShowPreviewGrid: Boolean; FShowRoot: Boolean; FShowRowFooter: Boolean; FTreeLineColor: TColor; FTreeLineStyle: TdxTreeLineStyle; // Sizes // - group panel FGroupPanelHeight: Integer; // - bands FBandHeight: Integer; FBandRowCount: Integer; FBandTextHeight: Integer; // - headers FHeaderHeight: Integer; FHeaderLineCount: Integer; FHeaderRowCount: Integer; FHeaderRowHeight: Integer; // - new item row FNewItemRowHeight: Integer; FNewItemRowSeparatorHeight: Integer; // - row FFixedBandLineWidth: Integer; FMinRowHeight: Integer; FRowHeight: Integer; FRowHeightAssigned: Boolean; FRowSeparatorLineWidth: Integer; FTextHeight: Integer; FMaxRowLineCount: Integer; // - preview FDescTextHeight: Integer; FIndentDesc: Integer; FPreviewLines: Integer; // - indicator FIndicatorWidth: Integer; // - footer row FFooterRowHeight: Integer; FFooterRowNodeHeight: Integer; // - footer FFooterHeight: Integer; // status FStatusHeight: Integer; // - other... FDeltaHScroll: Integer; FImageH: Integer; FImageW: Integer; FImageButtonH: Integer; FImageButtonW: Integer; FImageStateH: Integer; FImageStateW: Integer; FIndent: Integer; // flags FBandButtonPushed: Boolean; FDragAbsoluteBandIndex: Integer; FDownBandIndex: Integer; FDownBandPushed: Boolean; FDownColumnIndex: Integer; // absolute index FDragAbsoluteHeaderIndex FDownColumnPushed: Boolean; FHeaderButtonPushed: Boolean; FDropDownButtonColumnIndex: Integer; FDropDownButtonColumnPushed: Boolean; FStatusCloseButtonActive: Boolean; FStatusCloseButtonPressed: Boolean; // Position FArrowsPos: TPoint; FFlagSaveArrowsRect: Boolean; FFocusedAbsoluteIndex: Integer; FFocusedColumn: Integer; FHitInfo: TdxTreeListHitInfo; FHitTest: TPoint; FLeftCoord: Integer; FPointDragging: TPoint; FSaveArrowsRect, FArrowsRect: TRect; FSizingPos: Integer; FPrevSizingPos: Integer; FTopVisibleNode: TdxTreeListNode; // DragDrop FDragExpandNode: TdxTreeListNode; FDragExpandTimerId: Integer; FDragImageList: TImageList; FDragNode: TdxTreeListNode; FDragObject: TDragObject; FShowDragImage: Boolean; FWaitForExpandNodeTime: UINT; // Other FCellViewData: TdxTreeListCellViewData; FImages: TImageList; FImageChangeLink: TChangeLink; FLockHideDragImages: Integer; FLockSelection: Integer; FNewItemRowActive: Boolean; FOptions: TdxTreeListOptions; FOptionsEx: TdxTreeListOptionsEx; FPrevSelectedCount: Integer; FSaveFont: TFont; FSelectionAnchor: TdxTreeListNode; FSelfChangingTitleFont: Boolean; FState: TdxTreeListState; FStateImages: TImageList; FStateChangeLink: TChangeLink; // Editor FCursorChange: Boolean; FDefaultCursor: TCursor; FHotTrackInfo: TdxTreeListHotTrackInfo; FInplaceEdit: TdxInplaceEdit; FInplaceColumn: Integer; FInplaceColumnIndex: Integer; FInplaceNode: TdxTreeListNode; // Customizig FCustomizingBandListBox: TdxBandsListBox; FCustomizingForm: TForm; FCustomizingHeaderListBox: TdxHeadersListBox; FCustomizingLastBandIndex: Integer; FCustomizingLastHeaderIndex: Integer; FCustomizingPos: TPoint; FCustomizingRowCount: Integer; FSimpleCustomizeBox: Boolean; FShowHiddenInCustomizeBox: Boolean; // Search FSearchColumnIndex: Integer; FAutoExpandOnSearch: Boolean; FAutoSearchColor: TColor; FAutoSearchTextColor: TColor; // Hints FHideHintTimerId: Integer; FHintWindow: TdxContainerHintWindow; FShowHintTimerId: Integer; // Events FOnBeginDragNode: TTLExpandedEvent; FOnCanNodeSelected: TdxTLCanNodeSelected; FOnChangeColumn: TTLChangeColumnEvent; FOnChangeLeftCoord: TNotifyEvent; FOnChangeNode: TTLChangeNodeEvent; FOnChangeTopVisibleNode: TNotifyEvent; FOnCollapsed: TTLExpandedEvent; FOnCollapsing: TTLExpandingEvent; FOnCompare: TdxTLCompareEvent; FOnDeletion: TTLExpandedEvent; FOnEditChange: TNotifyEvent; FOnEdited: TTLExpandedEvent; FOnEditing: TTLExpandingEvent; FOnEditValidate: TdxEditValidateEvent; FOnEndColumnsCustomizing: TNotifyEvent; FOnExpanded: TTLExpandedEvent; FOnExpanding: TTLExpandingEvent; FOnGetEditColor: TdxTLGetEditColor; FOnHotTrackNode: TdxTLHotTrackNode; FOnSelectedCountChange: TNotifyEvent; {$IFDEF EGRID_DEBUG} FOnDebugEvent: TdxDBGridDebugEvent; {$ENDIF} function FindListNode(Node: TdxTreeListNode): Integer; function GetCount: Integer; function GetFocused: TdxTreeListNode; function GetFocusedColumn: Integer; function GetFocusedNumber: Integer; function GetLastNode: TdxTreeListNode; function GetNode(Index: Integer): TdxTreeListNode; function GetOptions: TdxTreeListOptions; function GetOptionsEx: TdxTreeListOptionsEx; function GetTopIndex: Integer; function IsActiveControl: Boolean; function IsSmartNavigation: Boolean; procedure SetFocusedColumn(Value : Integer); procedure SetLeftCoord(ALeft: Integer); procedure SetOptions(Value: TdxTreeListOptions); procedure SetOptionsEx(Value: TdxTreeListOptionsEx); procedure SetTopIndex(AIndex: Integer); procedure UpdateDesigner; procedure UpdateHScrollBar; procedure UpdateTopLeftCoord; procedure UpdateVScrollBar; // size function GetDefaultRowHeight: Integer; function IsRowHeightStored: Boolean; procedure SetCustomizingRowCount(Value: Integer); procedure SetDefaultRowHeight(Value: Integer); procedure SetFixedBandLineWidth(Value: Integer); procedure SetIndentDesc(Value: Integer); procedure SetMaxRowLineCount(Value: Integer); procedure SetPreviewLines(Value: Integer); procedure SetRowSeparatorLineWidth(Value: Integer); // paint methods procedure DrawArrows(FlagHide: Boolean); procedure DrawSizingLine; function GetFooterRect(Node: TdxTreeListNode; Index, YStart, SizeGrid: Integer; const DrawInfo: TdxGridDrawInfo): TRect; procedure InvalidateBand(BandIndex: Integer); procedure InvalidateBandButton; procedure InvalidateColumn(ColumnIndex: Integer); procedure InvalidateHeaderButton; procedure InvalidateNewItemRow; // style function GetRootVisible: Boolean; procedure HeaderFontChanged(Sender: TObject); procedure ImageListChange(Sender: TObject); procedure InternalLayout; function IsHeaderFontStored: Boolean; procedure LoadButtonFaces; procedure SetBandColor(Value: TColor); procedure SetBandFont(Value: TFont); procedure SetBandVisible(Value: Boolean); procedure SetBorderStyle(Value: TBorderStyle); procedure SetButtonVisible(Value: Boolean); procedure SetFixedBandLineColor(Value: TColor); procedure SetFooterColor(Value: TColor); procedure SetFooterTextColor(Value: TColor); procedure SetFooterVisible(Value: Boolean); procedure SetGridLineColor(Value: TColor); procedure SetGridVisible(Value: Boolean); procedure SetGroupColor(Value : TColor); procedure SetGroupTextColor(Value : TColor); procedure SetHeaderColor(Value: TColor); procedure SetHeaderFont(Value: TFont); procedure SetHeaderVisible(Value: Boolean); procedure SetHideFocusRect(Value: Boolean); procedure SetHideSelection(Value: Boolean); procedure SetHideSelectionColor(Value: TColor); procedure SetHideSelectionTextColor(Value: TColor); procedure SetHighlightColor(Value: TColor); procedure SetHighlightTextColor(Value: TColor); procedure SetImages(Value: TImageList); procedure SetIndicatorVisible(Value: Boolean); procedure SetLineVisible(Value: Boolean); procedure SetLookAndFeel(Value : TdxLookAndFeel); procedure SetNewItemRowVisible(Value: Boolean); procedure SetPaintStyle(Value: TdxTreeListPaintStyle); procedure SetPreviewFont(Value: TFont); procedure SetPreviewGridVisible(Value: Boolean); procedure SetRootVisible(Value: Boolean); procedure SetRowFooterVisible(Value: Boolean); procedure SetScrollBars(Value: TScrollStyle); procedure SetStateImages(Value: TImageList); procedure SetTreeLineColor(Value: TColor); procedure SetTreeLineStyle(Value: TdxTreeLineStyle); // Other procedure ActivateCustomizingForm(Sender: TObject); procedure CloseCustomizingForm(Sender: TObject; var Action: TCloseAction); procedure SetDragObject(Value: TDragObject); procedure SetNewItemRowActive(Value: Boolean); // Editor procedure HideEdit(ABackFocus: Boolean); procedure UpdateText; procedure UpdateEdit(Activate: Boolean); // Hint procedure ShowStatusCloseButtonHint(AImmediately: Boolean); procedure HideStatusCloseButtonHint; // Messages procedure WMCancelMode(var Msg: TMessage); message WM_CANCELMODE; 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 WMIMEStartComp(var Message: TMessage); message WM_IME_STARTCOMPOSITION; 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 CMDrag(var Message: TCMDrag); message CM_DRAG; 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 CMSysColorChange(var Message: TMessage); message CM_SYSCOLORCHANGE; protected FVisibleRowCount, FRowCount: Integer; FFirstSelectedNode: TdxTreeListNode; FSelecting: Boolean; DrawBitmap: TBitmap; FlagMultiSort: Boolean; FlagClearSort: Boolean; FDragAbsoluteHeaderIndex: Integer; // property DragAbsoluteHeaderIndex FClearListNodesFlag: Boolean; FClearNodes: Boolean; FSearching: Boolean; FSearchText: string; FLockSearching: Integer; FCanceling: Boolean; // Filter FHiddenList: TList; FDropDownListVisible: Boolean; // override TCustomControl procedure CreateParams(var Params: TCreateParams); override; procedure CreateWnd; override; procedure DoExit; override; procedure KeyDown(var Key: Word; Shift: TShiftState); override; procedure KeyPress(var Key: Char); override; procedure Loaded; 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 Notification(AComponent: TComponent; Operation: TOperation); override; procedure Paint; override; procedure WndProc(var Message: TMessage); override; // routines function CalcBandHeight(LineCount: Integer): Integer; function CalcBandPanelRowCount(Y: Integer): Integer; function CalcHeaderPanelRowCount(Y: Integer): Integer; function CalcNearestRowHeight(Node: TdxTreeListNode; ResizeRowHeight: Integer): Integer; class function CalcTextRowHeight(TextHeight: Integer): Integer; procedure CancelDragSizing; virtual; procedure ChangedBandAutoWidth(BandIndex, NewWidth: Integer); procedure ChangedHeaderAutoWidth(BandIndex, AbsoluteHeaderIndex, NewWidth: Integer); procedure DoBandDragging; procedure DoHeaderDragging; procedure DoScrolling; procedure FreeImageList(var AImgList: TImageList); function GetBandMinWidth(VisibleIndex: Integer): Integer; procedure GetBandPanelResizeRanges(Y: Integer; var Min, Max: Integer); function GetBandRealWidth(VisibleIndex: Integer): Integer; procedure GetBandResizeRanges(VisibleIndex, X: Integer; var Start, Min, Max: Integer); function GetBandTotalWidth: Integer; function GetBandWidth(VisibleIndex: Integer): Integer; function GetFocusedColumnAbsoluteIndex: Integer; procedure SetFocusedColumnAbsoluteIndex(Value: Integer); function GetHeaderLineCount(BandIndex, RowIndex, ColIndex: Integer): Integer; procedure GetHeaderPanelResizeRanges(Y: Integer; var Min, Max: Integer); procedure GetHeaderResizeRanges(AbsoluteIndex, X: Integer; var Start, Min, Max: Integer); function GetHeaderTotalMinWidth(BandIndex, RowIndex: Integer): Integer; function GetHeaderTotalWidth(BandIndex, RowIndex: Integer): Integer; function GetHorzGridRect: TRect; function GetNodeFooterLevel(Node: TdxTreeListNode; Index: Integer): Integer; function GetNodeFooterRowCount(Node: TdxTreeListNode; Level: Integer): Integer; procedure GetNodeIndent(ANode: TdxTreeListNode; var AIndent, AImageIndent: Integer); function GetPreviewBoundsWidth(Node: TdxTreeListNode): Integer; function GetRowHeight(Node: TdxTreeListNode; FHeight: Integer; ReCalc: Boolean): Integer; function GetRowFooterCount(Node: TdxTreeListNode): Integer; procedure GetRowResizeRanges(Node: TdxTreeListNode; Y: Integer; var Min, Max: Integer); function GetScrollableBandWidth: Integer; function GetScrollableWidth: Integer; function GetScrollHorzGridRect: TRect; function GetStartBandCoord(VisibleIndex: Integer): Integer; function GetVisibleHeaderCount: Integer; procedure HideDragImages; function IsCalcRowAutoHeight: Boolean; function IsFixedBand(VisibleIndex: Integer): Boolean; function IsFixedBandHeader(AbsoluteIndex: Integer): Boolean; procedure PrepareArrowsRect(IsBand: Boolean); procedure PrepareDragBand(AbsoluteIndex: Integer); procedure PrepareDragHeader(AbsoluteIndex: Integer); procedure PrepareDragNode(Node: TdxTreeListNode; Column: Integer{absolute index}); virtual; procedure ResetTopFocusedNodes; procedure ScaledBandHeaderWidth(BandIndex, NewWidth: Integer); procedure ScaledHeaderBandWidth(BandIndex, AbsoluteHeaderIndex, NewWidth: Integer); procedure ScrollGridHorz(Distance: Integer); procedure ScrollGridVert(Distance: Integer); procedure ShowDragImages; procedure UpdateCustomizingColumns; procedure UpdateDragging; // Copy to text format function GetHeaderTabText: string; function GetNodeTabText(ANode: TdxtreeListNode): string; // based function AcquireFocus: Boolean; virtual; procedure AddNode(Node: TdxTreeListNode); virtual; procedure BeforeDestroy; procedure BeginCustomLayout; virtual; function CanDblClick: Boolean; virtual; function CheckHasChildren(Node: TdxTreeListNode): Boolean; virtual; procedure ClearBoundsInfo; virtual; procedure ClearListNodes; virtual; procedure ClearNodeRowHeight; virtual; procedure DoAfterCollapse(Node : TdxTreeListNode); virtual; procedure DoAfterEditing(Node : TdxTreeListNode); virtual; procedure DoAfterExpand(Node : TdxTreeListNode); virtual; procedure DoBeforeCollapse(Node : TdxTreeListNode; var AllowCollapse: Boolean); virtual; procedure DoBeforeEditing(Node : TdxTreeListNode; var AllowEditing: Boolean); virtual; procedure DoBeforeExpand(Node : TdxTreeListNode; var AllowExpand: Boolean); virtual; procedure DoBestFitBand(BandIndex: Integer); virtual; procedure DoBestFitColumn(AbsoluteIndex: Integer); virtual; procedure DoChangeColumn(Node : TdxTreeListNode; Column : Integer); virtual; procedure DoChangeLeftCoord; virtual; procedure DoChangeNode(OldNode, Node : TdxTreeListNode); virtual; procedure DoEditChange(Sender: TObject); virtual; procedure DoEditValidate(Sender: TObject; var ErrorText: string; var Accept: Boolean); virtual; procedure DoRestoreLayout; virtual; procedure DoSaveLayout; virtual; procedure DeleteNode(Node, Prior, Next: TdxTreeListNode; IsLast, Redraw: Boolean); virtual; procedure DeleteStrings(Node: TdxTreeListNode; Index: Integer); virtual; function DoMoveFocusedColumn(FlagUp, IsTest: Boolean): Boolean; virtual; procedure EndCustomLayout; virtual; function GetAbsoluteCount: Integer; function GetAbsoluteIndex(Node: TdxTreeListNode): Integer; function GetAbsoluteNode(AIndex: Integer): TdxTreeListNode; function GetRectNode(Node:TdxTreeListNode): TRect; function GetRectNodeBelow(Node:TdxTreeListNode): TRect; function GetRowNode(Node:TdxTreeListNode): Integer; function GetScrollVertGridRect: TRect; virtual; function GetTopNode: TdxTreeListNode; procedure FreeClickTimer; function IsColumnHotTrack(X, Y: Integer; Node: TdxTreeListNode; ColumnAbsoluteIndex: Integer; var ActiveIndex: Integer): Boolean; virtual; function IsHeaderHotTrack(X, Y: Integer; ColumnAbsoluteIndex: Integer; var HeaderHotTrack: TdxTreeListHeaderHotTrack): Boolean; virtual; procedure LayoutChanged; virtual; procedure MakeBandHeaderList(CalcBounds: Boolean); virtual; procedure MakeBoundsInfo; virtual; procedure MakeListNode(Node: TdxTreeListNode; Deleteing: Boolean); procedure MakeListNodes; virtual; function MakeFocused(Node: TdxTreeListNode): Boolean; virtual; function NeedShowButtonEdit(X, Y: Integer; IsCurrentNode: Boolean; ColumnAbsoluteIndex: Integer): Boolean; virtual; procedure SetEmptyNodes; procedure SetState(Value: TdxTreeListState); procedure UpdateNode(Node: TdxTreeListNode; Below: Boolean); virtual; // based virtual & abstract function CanSetData: Boolean; virtual; function CreateNode: TdxTreeListNode; virtual; abstract; function GetNodeImageIndex(Node: TdxTreeListNode): Integer; virtual; abstract; function GetNodeSelectedIndex(Node: TdxTreeListNode): Integer; virtual; abstract; function GetNodeStateIndex(Node: TdxTreeListNode): Integer; virtual; abstract; function GetNodeValue(Node: TdxTreeListNode; Column: Integer) : Variant; virtual; abstract; function GetNodeString(Node: TdxTreeListNode; Column: Integer): string; virtual; abstract; function GetNodeVariant(Node: TdxTreeListNode; Column: Integer): Variant; virtual; procedure SetFocusedNode(Node: TdxTreeListNode; Column: Integer; MakeVisibleFlag: Boolean); virtual; procedure SetFocusedNumber(AIndex: Integer); virtual; procedure SetNodeImageIndex(Node: TdxTreeListNode; Value: Integer); virtual; abstract; procedure SetNodeSelectedIndex(Node: TdxTreeListNode; Value: Integer); virtual; abstract; procedure SetNodeStateIndex(Node: TdxTreeListNode; Value: Integer); virtual; abstract; procedure SetNodeString(Node: TdxTreeListNode; Column: Integer; const Value: string); virtual; abstract; procedure SetNodeValue(Node: TdxTreeListNode; Column: Integer; const Value: Variant); virtual; abstract; procedure SetTopVisibleNode(Node: TdxTreeListNode); virtual; // GroupPanel function GetGroupPanelHeight: Integer; virtual; // Bands function GetAbsoluteBandAlignment(AbsoluteIndex: Integer): TAlignment; virtual; function GetAbsoluteBandCount: Integer; virtual; function GetAbsoluteBandIndex(VisibleIndex: Integer): Integer; virtual; function GetAbsoluteBandText(AbsoluteIndex: Integer): string; virtual; function GetAbsoluteBandWidth(AbsoluteIndex: Integer): Integer; virtual; function GetBandAlignment(VisibleIndex: Integer): TAlignment; virtual; function GetBandCount: Integer; virtual; function GetBandFixedLeft: Integer; virtual; function GetBandFixedRight: Integer; virtual; function GetBandMinWidthSize(VisibleIndex: Integer): Integer; virtual; function GetBandSizeWidth(VisibleIndex: Integer): Integer; virtual; function GetBandText(VisibleIndex: Integer): string; virtual; function GetIndentWidth: Integer; virtual; function GetVisibleBandIndex(AbsoluteIndex: Integer): Integer; virtual; function IsOwnBand(ABandIndex: Integer{VisibleIndex}): Boolean; virtual; // Headers function GetHeaderAbsoluteCount: Integer; virtual; function GetHeaderAbsoluteIndex(BandIndex, RowIndex, ColIndex: Integer): Integer; virtual; // get absolute index function GetHeaderAlignment(AbsoluteIndex: Integer): TAlignment; virtual; function GetHeaderBandIndex(AbsoluteIndex: Integer): Integer; virtual; function GetHeaderBoundsWidth(AbsoluteIndex: Integer): Integer; virtual; function GetHeaderColCount(BandIndex, RowIndex: Integer): Integer; virtual; function GetHeaderColIndex(AbsoluteIndex: Integer): Integer; virtual; function GetHeaderDropDownButtonState(AbsoluteIndex: Integer): TdxHeaderDropDownButtonState; virtual; function GetHeaderGlyph(AbsoluteIndex: Integer): TBitmap; virtual; function GetHeaderMaxLineCount(AbsoluteIndex: Integer): Integer; virtual; // 0 - while not limit function GetHeaderMinWidth(AbsoluteIndex: Integer): Integer; virtual; function GetHeaderRowCount(BandIndex: Integer): Integer; virtual; function GetHeaderRowIndex(AbsoluteIndex: Integer): Integer; virtual; function GetHeaderSorted(AbsoluteIndex: Integer): TdxTreeListColumnSort; virtual; function GetHeaderTabStop(AbsoluteIndex: Integer): Boolean; virtual; function GetHeaderText(AbsoluteIndex: Integer): string; virtual; function GetHeaderTextListBox(AbsoluteIndex: Integer): string; virtual; function GetHeaderWidth(AbsoluteIndex: Integer): Integer; virtual; function GetColumnColor(AbsoluteIndex: Integer): TColor; virtual; function GetColumnFont(AbsoluteIndex: Integer): TFont; virtual; function IsExistColumnFont(AbsoluteIndex: Integer): Boolean; virtual; function IsExistHeaderGlyph(AbsoluteIndex: Integer): Boolean; virtual; // Cells function GetCellAlignment(Node: TdxTreeListNode; AbsoluteIndex: Integer): TAlignment; virtual; function GetCellText(Node: TdxTreeListNode; AbsoluteIndex: Integer): string; virtual; function GetNewItemCellText(AbsoluteIndex: Integer): string; virtual; function IsCellMultiLine(AbsoluteIndex: Integer): Boolean; virtual; function IsNewItemRowEditing: Boolean; virtual; // Indicator function GetIndicatorWidth: Integer; virtual; // Rows function GetHeaderMaxRowHeight(ACanvas: TCanvas; AbsoluteIndex: Integer): Integer; virtual; // column (image) function GetPreviewText(Node: TdxTreeListNode): string; virtual; function GetRowIndicatorKind(Node: TdxTreeListNode; ASelected: Boolean): TdxGridIndicatorKind; virtual; function GetRowLineCount(Node: TdxTreeListNode; var LineHeight: Integer): Integer; virtual; // Status function GetStatusButtonVisible: Boolean; virtual; function GetStatusText: string; virtual; function GetStatusCloseButtonHint: string; virtual; function GetStatusCloseButtonRect: TRect; function ColumnCalcLineCount(ANode: TdxTreeListNode; AbsoluteIndex: Integer; const Text: string; BoundsWidth, TextHeight, MaxLineCount: Integer; InflateFlag{obsolete}, GridFlag{obsolete}: Boolean; var LineCount, LineHeight: Integer): Boolean; virtual; function GetRowMaxColumnHeight(ACanvas: TCanvas): Integer; virtual; function GetRowPreviewLineCount(Node: TdxTreeListNode): Integer; virtual; function GetRowSeparatorLineWidth: Integer; virtual; // 1, 2, ... 5 ? procedure HeaderPanelBestFit; virtual; function IsRowGroup(Node: TdxTreeListNode): Boolean; virtual; // Footer function GetFooterCellAlignment(Node: TdxTreeListNode; AbsoluteIndex, FooterIndex: Integer): TAlignment; virtual; function GetFooterCellText(Node: TdxTreeListNode; AbsoluteIndex, FooterIndex: Integer): string; virtual; function IsExistFooterCell(AbsoluteIndex: Integer): Boolean; virtual; function IsExistRowFooterCell(Node: TdxTreeListNode; AbsoluteIndex, FooterIndex: Integer): Boolean; virtual; function IsLevelFooter(Level: Integer): Boolean; virtual; // Style function IsAnsiSort: Boolean; virtual; function IsAutoCalcPreviewLines: Boolean; virtual; function IsAutoDragCopy: Boolean; virtual; function IsAutoFilter: Boolean; virtual; function IsAutoHeaderPanelRowCount: Boolean; virtual; function IsAutoSearch: Boolean; virtual; function IsAutoSort: Boolean; virtual; function IsAutoSortRefresh: Boolean; virtual; function IsAutoWidth: Boolean; virtual; function IsBandHeaderWidth: Boolean; virtual; function IsCaseInsensitive: Boolean; virtual; function IsCellMultiSelect: Boolean; virtual; function IsDragCollapse: Boolean; virtual; function IsDrawEndEllipsis: Boolean; virtual; function IsDragExpand: Boolean; virtual; function IsDragScroll: Boolean; virtual; function IsEditing: Boolean; virtual; function IsEnterShowEditor: Boolean; virtual; function IsEnterThrough: Boolean; virtual; function IsExtCustomizing: Boolean; virtual; function IsExtMultiSelect: Boolean; virtual; function IsFilterStatusVisible: Boolean; virtual; function IsHorzThrough: Boolean; virtual; function IsHScrollBarVisible: Boolean; virtual; function IsImmediateEditor: Boolean; override; function IsMouseScroll: Boolean; virtual; function IsMultiSelect: Boolean; virtual; function IsMultiSort: Boolean; virtual; function IsNewItemRowActive: Boolean; virtual; function IsNewItemRowVisible: Boolean; virtual; function IsRowAutoHeight: Boolean; virtual; function IsRowSelect: Boolean; virtual; function IsShowHourGlass: Boolean; virtual; function IsShowRowFooter: Boolean; virtual; function IsShowPreview: Boolean; virtual; function IsSmartRecalcRowHeight: Boolean; virtual; function IsTabs: Boolean; override; function IsTabThrough: Boolean; virtual; function IsVertThrough: Boolean; virtual; function IsVScrollBarDisableHide: Boolean; virtual; function IsVScrollBarVisible: Boolean; virtual; function IsUseBitmap: Boolean; virtual; // Sizing, Clicking function CanBandButtonClicking: Boolean; virtual; function CanBandFullSizing(VisibleIndex: Integer): Boolean; virtual; function CanBandPanelSizing: Boolean; virtual; function CanBandSizing(VisibleIndex: Integer): Boolean; virtual; function CanHeaderBandSizing: Boolean; virtual; // header width changed - > band width changed function CanHeaderButtonClicking: Boolean; virtual; function CanHeaderFullSizing(AbsoluteIndex: Integer): Boolean; virtual; function CanHeaderPanelSizing: Boolean; virtual; function CanHeaderSizing(AbsoluteIndex: Integer): Boolean; virtual; function CanHeaderReSizing(AbsoluteIndex: Integer): Boolean; virtual; function CanRowSizing: Boolean; virtual; procedure ChangedBandRowCount(BandRowCount: Integer); virtual; procedure ChangedBandWidth(VisibleIndex, Width: Integer); virtual; procedure ChangedHeaderMaxRowCount(RowCount: Integer); virtual; // header panel sizing procedure ChangedHeaderWidth(AbsoluteIndex, Width: Integer); virtual; procedure ChangeHiddenBandWidth(ScaleNum, ScaleDenom: Integer); virtual; procedure ChangeHiddenHeaderWidth(BandIndex: Integer; ScaleNum, ScaleDenom: Integer); virtual; procedure ChangedRowHeight(NewRowHeight: Integer); virtual; procedure DoBandButtonClick; virtual; procedure DoBandClick(VisibleIndex: Integer); virtual; procedure DoChangedColumnsWidth; virtual; procedure DoHeaderButtonClick; virtual; procedure DoHeaderClick(AbsoluteIndex: Integer); virtual; procedure DoHeaderDropDownButtonClick(AbsoluteIndex: Integer); virtual; procedure DoStatusCloseButtonClick; virtual; function GetBandMaxRowCount: Integer; virtual; // sizing function GetBandRowCount: Integer; virtual; function GetHeaderMaxLimitRowCount: Integer; virtual; // header panel sizing function GetHeaderMaxRowCount: Integer; virtual; function GetHeaderLineRowCount: Integer; virtual; // DragDrop procedure CalcArrowsPos(var P: TPoint; PPosInfo: Pointer; IsBand: Boolean; DownIndex, DragIndex: Integer); virtual; procedure GetDragImageCursor(P: TPoint; var ADragCursor:TCursor); virtual; function GetIsCustomizing: Boolean; virtual; function GetNodeDragText(Node: TdxTreeListNode; AbsoluteIndex: Integer): string; virtual; function IsHeaderCustomizing: Boolean; virtual; procedure SetBandInfo(PPosInfo: Pointer; AIndex: Integer); procedure SetInfo(PPosInfo: Pointer; ABandIndex, ARowIndex, AColIndex, AAbsoluteIndex: Integer); // DragDrop Bands procedure BandMoved(FromIndex, ToIndex: Integer); virtual; // visible indexes function CanBandDragging(VisibleIndex: Integer): Boolean; virtual; procedure DoDragOverBand(P: TPoint{client}; AbsoluteIndex: Integer; var Accept: Boolean); virtual; procedure DoEndDragBand(P: TPoint; AbsoluteIndex, VisibleIndex: Integer; var NewIndex: Integer; var Accept: Boolean); virtual; procedure EndDragBand(Flag: Boolean); virtual; function GetBandDisableCustomizing(AbsoluteIndex: Integer): Boolean; virtual; procedure HideBand(AbsoluteIndex: Integer); virtual; function IsBandInListBox(AbsoluteIndex: Integer): Boolean; virtual; procedure StartDragBand(AbsoluteIndex: Integer); virtual; procedure ShowBand(NewIndex{visible index}, AbsoluteIndex: Integer); virtual; // DragDrop Headers function CanHeaderDragging(AbsoluteIndex: Integer): Boolean; virtual; procedure DoDragOverHeader(P: TPoint{client}; AbsoluteIndex: Integer; var Accept: Boolean); virtual; procedure DoEndDragHeader(P: TPoint; AbsoluteIndex: Integer; var NewPosInfo: TdxHeaderPosInfo; var Accept: Boolean); virtual; procedure EndDragHeader(Flag: Boolean); virtual; function GetDragHeaderWidth(AbsoluteIndex: Integer): Integer; virtual; // UnVisible Header or Group Header function GetHeaderDisableCustomizing(AbsoluteIndex: Integer): Boolean; virtual; procedure HeaderMoved(FromAbsoluteIndex, ToBandIndex, ToRowIndex, ToColIndex: Integer); virtual; procedure HideHeader(AbsoluteIndex: Integer); virtual; function IsHeaderInListBox(AbsoluteIndex: Integer): Boolean; virtual; function IsHeaderVisible(AbsoluteIndex: Integer): Boolean; virtual; procedure StartDragHeader(AbsoluteIndex: Integer); virtual; procedure ShowColumnHeader(BandIndex, RowIndex, ColIndex, AbsoluteIndex: Integer); virtual; // DragDrop Nodes procedure DoBeginDragNode(Node: TdxTreeListNode); virtual; procedure DoEndDrag(Target: TObject; X, Y: Integer); 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; function IsLastNode(ANode: TdxTreeListNode): Boolean; virtual; function IsTopNode(ANode: TdxTreeListNode): Boolean; virtual; // Size function CalcDistance(Distance: Integer): Integer; function CalcNearTopIndex(AIndex: Integer): Integer; function CalcRowCount(ATopVisibleNode: TdxTreeListNode; AHeight: Integer; var ARowCount, AVisibleRowCount: Integer): Integer; procedure CheckSize; function GetVisibleRowCount: Integer; virtual; procedure GetVScrollInfo(var Min, Max, Pos : Integer; var Page, Mask : UINT); virtual; procedure UpdateRowCount; virtual; procedure UpdateScrollBars; virtual; //Editor function AssignEditValue(ANode: TdxTreeListNode; AColumn: Integer; AInplaceEdit: TdxInplaceEdit): Variant; virtual; function CanEditAcceptKey(Key: Char): Boolean; override; function CanEditModify: Boolean; override; function CanEditShow: Boolean; virtual; function CanTreeListAcceptKey(Key: Word; Shift: TShiftState): Boolean; virtual; procedure CheckHotTrackNode(AHitInfo: TdxTreeListHitInfo); virtual; function CreateEditor(AColumn: Integer): TdxInplaceEdit; virtual; function CreateEditStyle(AEdit: TdxInplaceEdit): TdxEditStyle; override; procedure DoBeforeEditNewItemRow(var Allow: Boolean); virtual; procedure DoBeginNewItemActive; virtual; procedure DoHotTrackNode(AHotTrackInfo: TdxTreeListHotTrackInfo; var ACursor: TCursor); virtual; function EditStyleBorderColor: TColor; function EditStyleBorderStyle: TdxEditBorderStyle; function EditStyleButtonStyle: TdxEditButtonViewStyle; function EditStyleButtonTransparence: TdxEditButtonTransparence; function EditStyleEdges: TdxEditEdges; function EditStyleHotTrack: Boolean; function EditStyleShadow: Boolean; function FindInplaceEdit(AColumn : Integer):TdxInplaceEdit; virtual; function GetEditColor: TColor; override; function GetEditFont: TFont; override; function GetEditingText : String; virtual; procedure InitEditProperties(AInplaceEdit: TdxInplaceEdit); virtual; function InitEditValue(ANode: TdxTreeListNode; AInplaceEdit: TdxInplaceEdit): Variant; virtual; // return Value for Editor procedure InvalidateEditor; function IsEditorMoved: Boolean; override; function IsHotTrackNode(ANode: TdxTreeListNode; AIndex: Integer): Boolean; virtual; procedure MoveCol(ALeft: Boolean); override; procedure RedrawSelection; override; procedure SetEditingText(Value : String); virtual; // Selected function CanFullMultiSelect: Boolean; virtual; function CanNodeSelected(ANode: TdxTreeListNode): Boolean; virtual; procedure ClearSelection; virtual; function CompareSelectionAnchor(ANode: TdxTreeListNode): Integer; virtual; procedure DeleteSelection; virtual; procedure DoSelectedCountChange; virtual; function GetFirstSelectedNode: TdxTreeListNode; function GetSelectedCount: Integer; virtual; function GetSelectedItem(AIndex: Integer): TdxTreeListNode; virtual; procedure InvalidateSelection; virtual; function IsNodeSelected(ANode: TdxTreeListNode):Boolean; virtual; procedure NodeSelected(ANode: TdxTreeListNode; ASelected: Boolean); virtual; procedure SelectNodes(N1, N2: TdxTreeListNode); virtual; procedure SetSelectionAnchor(ANode : TdxTreeListNode); virtual; // Sorting procedure ClearColumnsSorted; virtual; function CompareEqual(Node1, Node2: TdxTreeListNode): Integer; virtual; procedure DoSortColumn(StartIndex, ColIndex: Integer; FlagDesc: Boolean); virtual; procedure DoSortNodes(List: TList; Col: Integer; FlagDesc: Boolean); function GetSortedColumnCount: Integer; virtual; function GetSortedColumnDesc(Index: Integer): Boolean; virtual; function GetSortedColumnIndex(Index: Integer): Integer; virtual; // return AbsoluteIndex function IsMultiSortColumn(AbsoluteIndex: Integer): Boolean; virtual; // Paint function AssignedDrawBandEvent(VisibleIndex: Integer): Boolean; virtual; function AssignedDrawCellEvent(ANode: TdxTreeListNode; AbsoluteIndex: Integer{Column Index}): Boolean; virtual; function AssignedDrawFooterCellEvent(ANode: TdxTreeListNode; AbsoluteIndex, FooterIndex: Integer{Column Index}): Boolean; virtual; function AssignedDrawHeaderEvent(AbsoluteIndex: Integer): Boolean; virtual; function AssignedDrawPreviewEvent: Boolean; virtual; function AssignedLevelColorEvent: Boolean; virtual; procedure DoDrawBand(VisibleIndex: Integer; ACanvas: TCanvas; ARect, AClipRect: TRect; var AText: string; var AColor: TColor; AFont: TFont; var AAlignment: TAlignment; var ADone: Boolean); virtual; procedure DoDrawCell(ACanvas: TCanvas; var ARect: TRect; ANode: TdxTreeListNode; AIndex: Integer; ASelected, AFocused: Boolean; ANewItemRow: Boolean; ALeftEdge, ARightEdge: Boolean; ABrush: HBRUSH; var AText: string; var AColor: TColor; AFont: TFont; var AAlignment: TAlignment; var ADone: Boolean); virtual; procedure DoDrawFooterCell(ACanvas: TCanvas; ARect: TRect; ANode: TdxTreeListNode; AIndex, AFooterIndex: Integer; var AText: string; var AColor: TColor; AFont: TFont; var AAlignment: TAlignment; var ADone: Boolean); virtual; procedure DoDrawHeader(AbsoluteIndex: Integer; ACanvas: TCanvas; ARect, AClipRect: TRect; var AText: string; var AColor: TColor; AFont: TFont; var AAlignment: TAlignment; var ASorted: TdxTreeListColumnSort; var ADone: Boolean); virtual; procedure DoDrawPreview(ACanvas: TCanvas; ARect: TRect; ANode: TdxTreeListNode; ASelected: Boolean; var AText: string; var AColor, ATextColor: TColor; AFont: TFont; var ADone: Boolean); virtual; procedure DoGetLevelColor(ALevel: Integer; var AColor: TColor); virtual; procedure DrawCell(ACanvas: TCanvas; ARect: TRect; ABitmap: TBitmap; ANode: TdxTreeListNode; AIndex, AFooterIndex: Integer; ASelected, AFocused: Boolean; ACellColor: TColor; ABrush: HBRUSH; AMultiLine: Boolean; ACellKind: TdxGridDrawCellKind; ALeftEdge, ARightEdge: Boolean); virtual; // TODO PAINT1 procedure DefaultDrawCell(ADC: HDC; ARect: TRect; AAbsoluteIndex: Integer; ACellViewData: TdxTreeListCellViewData); virtual; procedure DrawCellEx(ACanvas: TCanvas; ARect: TRect; ABitmap: TBitmap; {temp draw bitmap} ANode: TdxTreeListNode; AIndex: Integer; ASelected, AFocused: Boolean; ACellColor, ACellTextColor: TColor; ABrush: HBRUSH; AMultiLine: Boolean; ACellKind: TdxGridDrawCellKind; ALeftEdge, ARightEdge: Boolean; ACellBkColor: TColor; ACellBkBrush: HBRUSH); virtual; procedure DrawGroupPanel(ACanvas: TCanvas; ARect: TRect; HeaderBrush, PanelBrush: HBRUSH); virtual; procedure DrawPreview(ACanvas: TCanvas; ARect: TRect; ABitmap: TBitmap; ANode: TdxTreeListNode; AColor, ATextColor: TColor; ABrush: HBRUSH; ASelected: Boolean); virtual; function GetGridColor(ABrushColor: TColor): TColor; virtual; procedure InvalidateHotTrack(AHotTrackInfo: TdxTreeListHotTrackInfo); procedure InvalidateRect(ARect: TRect); procedure PrepareNode(ANode: TdxTreeListNode); virtual; procedure UnPrepareNode(ANode: TdxTreeListNode); virtual; // Navigation function GetNodeByNavigation(ANode: TdxTreeListNode; ANavigationMode: TdxTreeListNavigationMode; AGotoHidden: Boolean): TdxTreeListNode; virtual; function GotoNodeByNavigation(ANavigationMode: TdxTreeListNavigationMode; AGotoHidden: Boolean): TdxTreeListNode; virtual; // Search procedure CheckSearchColumn; procedure DoSearch(var AText: string; ADirection: TdxTreeListSearchDirection; AExact: Boolean); virtual; function FindNodeByText(AColumnIndex: Integer; const AText: string; ADirection: TdxTreeListSearchDirection; var ANode: TdxTreeListNode): Boolean; virtual; property ArrowsColor: TColor read FArrowsColor write FArrowsColor default dxclArrows; property AutoExpandOnSearch: Boolean read FAutoExpandOnSearch write FAutoExpandOnSearch default True; property AutoSearchColor: TColor read FAutoSearchColor write FAutoSearchColor default clNone; property AutoSearchTextColor: TColor read FAutoSearchTextColor write FAutoSearchTextColor default clNone; property BandColor: TColor read FBandColor write SetBandColor default clBtnFace; property BandFont: TFont read FBandFont write SetBandFont stored IsHeaderFontStored; property BorderStyle: TBorderStyle read FBorderStyle write SetBorderStyle default bsSingle; property Color default clWindow; property DblClkExpanding: Boolean read FDblClkExpanding write FDblClkExpanding default True; property DefaultRowHeight: Integer read GetDefaultRowHeight write SetDefaultRowHeight stored IsRowHeightStored; property DragNode: TdxTreeListNode read FDragNode; property EditingText: string read GetEditingText write SetEditingText; property FixedBandLineColor: TColor read FFixedBandLineColor write SetFixedBandLineColor default clWindowFrame; property FixedBandLineWidth: Integer read FFixedBandLineWidth write SetFixedBandLineWidth default dxGridFixedBandLineWidth; property FocusedAbsoluteIndex: Integer read GetFocusedColumnAbsoluteIndex write SetFocusedColumnAbsoluteIndex; // absolute header index property FocusedColumn: Integer read GetFocusedColumn write SetFocusedColumn; property FocusedNumber: Integer read GetFocusedNumber write SetFocusedNumber; property GridLineColor: TColor read FGridLineColor write SetGridLineColor default clNone; property GroupNodeColor: TColor read FGroupColor write SetGroupColor default clBtnFace; property GroupNodeTextColor: TColor read FGroupTextColor write SetGroupTextColor default clNone; property HeaderColor: TColor read FHeaderColor write SetHeaderColor default clBtnFace; property HeaderFont: TFont read FHeaderFont write SetHeaderFont stored IsHeaderFontStored; property HideFocusRect: Boolean read FHideFocusRect write SetHideFocusRect default True; property HideSelection: Boolean read FHideSelection write SetHideSelection default True; property HideSelectionColor: TColor read FHideSelectionColor write SetHideSelectionColor default clBtnFace; property HideSelectionTextColor: TColor read FHideSelectionTextColor write SetHideSelectionTextColor default clBtnText; property HighlightColor: TColor read FHighlightColor write SetHighlightColor default clHighlight; property HighlightTextColor: TColor read FHighlightTextColor write SetHighlightTextColor default clHighlightText; property HotTrackInfo: TdxTreeListHotTrackInfo read FHotTrackInfo; property Images: TImageList read FImages write SetImages; property Indent: Integer read FIndent; property IndentDesc: Integer read FIndentDesc write SetIndentDesc default 20; property LeftCoord: Integer read FLeftCoord write SetLeftCoord; property LockUpdate: Integer read FLockUpdate; property LookAndFeel: TdxLookAndFeel read FLookAndFeel write SetLookAndFeel default lfStandard; property MaxRowLineCount: Integer read FMaxRowLineCount write SetMaxRowLineCount default -1; property NewItemRowActive: Boolean read FNewItemRowActive write SetNewItemRowActive; property PaintStyle: TdxTreeListPaintStyle read FPaintStyle write SetPaintStyle default psStandard; property ParentColor default False; property PreviewFont: TFont read FPreviewFont write SetPreviewFont stored IsHeaderFontStored; property PreviewLines: Integer read FPreviewLines write SetPreviewLines default 2; property RowCount: Integer read FRowCount; property RowFooterColor: TColor read FFooterColor write SetFooterColor default cl3DLight; property RowFooterTextColor: TColor read FFooterTextColor write SetFooterTextColor default clWindowText; property RowSeparatorLineWidth: Integer read GetRowSeparatorLineWidth write SetRowSeparatorLineWidth default 1; property ScrollBars: TScrollStyle read FScrollBars write SetScrollBars default ssBoth; property SelectedCount: Integer read GetSelectedCount; property SelectedNodes[Index:Integer] : TdxTreeListNode read GetSelectedItem; property SelectionAnchor: TdxTreeListNode read FSelectionAnchor write SetSelectionAnchor; property ShowBands: Boolean read FShowBands write SetBandVisible default False; property ShowButtons: Boolean read FShowButtons write SetButtonVisible default True; property ShowFooter: Boolean read FShowFooter write SetFooterVisible default False; property ShowGrid: Boolean read FShowGrid write SetGridVisible default False; property ShowHeader: Boolean read FShowHeaders write SetHeaderVisible default True; property ShowIndicator: Boolean read FShowIndicator write SetIndicatorVisible default False; property ShowLines: Boolean read FShowLines write SetLineVisible default True; property ShowNewItemRow: Boolean read FShowNewItemRow write SetNewItemRowVisible default False; property ShowPreviewGrid: Boolean read FShowPreviewGrid write SetPreviewGridVisible default True; property ShowRoot: Boolean read GetRootVisible write SetRootVisible default True; property ShowRowFooter: Boolean read FShowRowFooter write SetRowFooterVisible default False; property SimpleCustomizeBox: Boolean read FSimpleCustomizeBox write FSimpleCustomizeBox default False; property ShowHiddenInCustomizeBox: Boolean read FShowHiddenInCustomizeBox write FShowHiddenInCustomizeBox default False; property ShowDragImage: Boolean read FShowDragImage write FShowDragImage default True; property StateImages: TImageList read FStateImages write SetStateImages; property TopIndex: Integer read GetTopIndex write SetTopIndex; property TreeLineColor: TColor read FTreeLineColor write SetTreeLineColor default clBtnShadow; property TreeLineStyle: TdxTreeLineStyle read FTreeLineStyle write SetTreeLineStyle default tlDot; property VisibleRowCount: Integer read GetVisibleRowCount; property WaitForExpandNodeTime: UINT read FWaitForExpandNodeTime write FWaitForExpandNodeTime default dxWaitForExpandNodeTime; property OnBeginDragNode: TTLExpandedEvent read FOnBeginDragNode write FOnBeginDragNode; property OnCanNodeSelected: TdxTLCanNodeSelected read FOnCanNodeSelected write FOnCanNodeSelected; property OnChangeColumn: TTLChangeColumnEvent read FOnChangeColumn write FOnChangeColumn; property OnChangeLeftCoord: TNotifyEvent read FOnChangeLeftCoord write FOnChangeLeftCoord; property OnChangeNode: TTLChangeNodeEvent read FOnChangeNode write FOnChangeNode; property OnChangeTopVisibleNode: TNotifyEvent read FOnChangeTopVisibleNode write FOnChangeTopVisibleNode; property OnCollapsed: TTLExpandedEvent read FOnCollapsed write FOnCollapsed; property OnCollapsing: TTLExpandingEvent read FOnCollapsing write FOnCollapsing; property OnCompare: TdxTLCompareEvent read FOnCompare write FOnCompare; property OnDeletion: TTLExpandedEvent read FOnDeletion write FOnDeletion; property OnEditChange: TNotifyEvent read FOnEditChange write FOnEditChange; property OnEdited: TTLExpandedEvent read FOnEdited write FOnEdited; property OnEditing: TTLExpandingEvent read FOnEditing write FOnEditing; property OnEditValidate: TdxEditValidateEvent read FOnEditValidate write FOnEditValidate; property OnEndColumnsCustomizing: TNotifyEvent read FOnEndColumnsCustomizing write FOnEndColumnsCustomizing; property OnExpanded: TTLExpandedEvent read FOnExpanded write FOnExpanded; property OnExpanding: TTLExpandingEvent read FOnExpanding write FOnExpanding; property OnGetEditColor: TdxTLGetEditColor read FOnGetEditColor write FOnGetEditColor; property OnHotTrackNode: TdxTLHotTrackNode read FOnHotTrackNode write FOnHotTrackNode; property OnSelectedCountChange : TNotifyEvent read FOnSelectedCountChange write FOnSelectedCountChange; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; function Add: TdxTreeListNode; function AddFirst: TdxTreeListNode; procedure AdjustColumnsWidth; procedure BeginUpdate; procedure CalcDrawInfo(var DrawInfo: TdxGridDrawInfo); procedure CalcRectInfo(var DrawInfo: TdxGridDrawInfo); procedure CancelEditor; procedure CancelUpdate; function CellRect(ANode:TdxTreeListNode; AColumn : Integer): TRect; procedure ClearNodes; procedure CloseEditor; procedure ColumnsCustomizing; procedure CopyAllToClipboard; procedure CopySelectedToClipboard; procedure EndColumnsCustomizing; procedure EndUpdate; procedure FreeDrawInfo(var DrawInfo: TdxGridDrawInfo); procedure FullCollapse; procedure FullExpand; function GetEditRect(Node: TdxTreeListNode; Column: Integer): TRect; function GetFocusedAbsoluteIndex(FocusedIndex: Integer): Integer; function GetFocusedVisibleIndex(AbsoluteIndex: Integer): Integer; function GetHitInfo(Pos: TPoint): TdxTreeListHitInfo; virtual; function GetHitTestInfoAt(X, Y: Integer): TdxTreeListHitTest; function GetNextVisible(Node: TdxTreeListNode): TdxTreeListNode; function GetNodeAt(X, Y: Integer): TdxTreeListNode; procedure GotoFirst; procedure GotoLast(AGotoHidden: Boolean); function GotoNext(AGotoHidden: Boolean): Boolean; function GotoPrev(AGotoHidden: Boolean): Boolean; function HideDrawFocusRect: Boolean; override; procedure HideEditor; function IndexOf(Value: TdxTreeListNode): Integer; function Insert(BeforeNode: TdxTreeListNode): TdxTreeListNode; function IsActive: Boolean; virtual; function IsBOF: Boolean; virtual; function IsEOF: Boolean; virtual; function IsInvertSelect: Boolean; virtual; function IsNodeVisible(Node: TdxTreeListNode): Boolean; function IsShowButtonAlways: Boolean; override; procedure MakeBandVisible(VisibleIndex: Integer); procedure MakeColumnVisible(AbsoluteIndex: Integer); procedure MakeNodeVisible(Node: TdxTreeListNode); function PointInCustomizingForm(P: TPoint): Boolean; procedure SaveAllToStrings(List: TStrings); virtual; procedure SaveAllToTextFile(const FileName: String); procedure SaveSelectedToStrings(List: TStrings); virtual; procedure SaveSelectedToTextFile(const FileName: String); procedure ShowEditor; procedure ShowEditorChar(Ch: Char); procedure ShowButtonEditorMouse(X, Y: Integer); procedure ShowEditorMouse(X, Y: Integer); procedure StabilizeAutoWidth; function StartSearch(AColumnIndex: Integer; const AText: string): Boolean; procedure EndSearch; // TODO ? function GetDefaultPopupBorderStyle(AEditBorderStyle: TdxEditBorderStyle): TdxPopupBorderStyle; override; procedure BeginSelection; virtual; procedure EndSelection; virtual; property LockSelection: Integer read FLockSelection; property BandButtonPushed: Boolean read FBandButtonPushed; property BandPanelHeight: Integer read FBandHeight; property Canvas; property Count: Integer read GetCount; property CustomizingBandListBox: TdxBandsListBox read FCustomizingBandListBox; property CustomizingForm: TForm read FCustomizingForm; property CustomizingHeaderListBox: TdxHeadersListBox read FCustomizingHeaderListBox; property CustomizingPos: TPoint read FCustomizingPos write FCustomizingPos; property CustomizingRowCount: Integer read FCustomizingRowCount write SetCustomizingRowCount default dxCustomizingRowCount; property DescTextHeight: Integer read FDescTextHeight; property DownBandIndex: Integer read FDownBandIndex; property DownBandPushed: Boolean read FDownBandPushed; property DownColumnIndex: Integer read FDownColumnIndex; // absolute index property DownColumnPushed: Boolean read FDownColumnPushed; property DragAbsoluteBandIndex: Integer read FDragAbsoluteBandIndex; property DragAbsoluteHeaderIndex: Integer read FDragAbsoluteHeaderIndex; property FocusedNode: TdxTreeListNode read GetFocused; property FooterPanelHeight: Integer read FFooterHeight; property FooterRowHeight: Integer read FFooterRowHeight; property FooterRowNodeHeight: Integer read FFooterRowNodeHeight; property HeaderButtonPushed: Boolean read FHeaderButtonPushed; property HeaderHeight: Integer read FHeaderHeight; property HeaderPanelHeight: Integer read FHeaderHeight; property HeaderRowHeight: Integer read FHeaderRowHeight; property InplaceColumnIndex: Integer read FInplaceColumnIndex; property InplaceEditor: TdxInplaceEdit read FInplaceEdit; property IsCustomizing: Boolean read GetIsCustomizing; property Items[Index: Integer]: TdxTreeListNode read GetNode; property LastNode: TdxTreeListNode read GetLastNode; property NewItemRowHeight: Integer read FNewItemRowHeight; property Options: TdxTreeListOptions read GetOptions write SetOptions default [aoEditing, aoColumnSizing, aoColumnMoving, aoRowSelect, aoTabThrough]; property OptionsEx: TdxTreeListOptionsEx read GetOptionsEx write SetOptionsEx default [aoUseBitmap, aoBandHeaderWidth, aoAutoCalcPreviewLines, aoBandSizing, aoBandMoving, aoDragExpand, aoDragScroll]; property ReadOnly; property RowHeight: Integer read FRowHeight; property Searching: Boolean read FSearching; property SearchText: string read FSearchText; property State: TdxTreeListState read FState; property TopNode: TdxTreeListNode read GetTopNode; property TopVisibleNode: TdxTreeListNode read FTopVisibleNode; {$IFDEF EGRID_DEBUG} property OnDebugEvent: TdxDBGridDebugEvent read FOnDebugEvent write FOnDebugEvent; {$ENDIF} published property TabStop default True; end; {TdxCustomizingListBox} TdxCustomizingListBox = class(TListBox) private FDragFlag: Boolean; FDragItemIndex: Integer; FFlat: Boolean; FMultiLine: Boolean; FPointDragging: TPoint; FTreeList: TCustomdxTreeList; procedure DrawItem_(ACanvas: TCanvas; Index: Integer; Rect: TRect; Focused: Boolean); procedure SetFlat(Value: Boolean); procedure SetTreeList(Value: TCustomdxTreeList); // messages procedure WMCaptureChanged(var Msg: TMessage); message WM_CAPTURECHANGED; procedure WMLButtonUp(var Message : TMessage); message WM_LBUTTONUP; procedure WMMouseMove(var Message : TMessage); message WM_MOUSEMOVE; procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE; procedure WMNCPaint(var Message: TMessage); message WM_NCPaint; procedure CNDrawItem(var Message: TWMDrawItem); message CN_DRAWITEM; protected procedure CreateParams(var Params: TCreateParams); override; procedure DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState); 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; // virtual procedure BeginDragging(DragIndex: Integer); virtual; procedure DoCancelDragging; virtual; procedure DoDragging; virtual; procedure DoEndDragging(Flag: Boolean); virtual; procedure LoadItems(List: TStrings); virtual; procedure UpdateItems; virtual; public constructor Create(AOwner : TComponent); override; property DragItemIndex: Integer read FDragItemIndex; property Flat: Boolean read FFlat write SetFlat; property TreeList: TCustomdxTreeList read FTreeList write SetTreeList; end; {TdxBandsListBox} TdxBandsListBox = class(TdxCustomizingListBox) protected procedure BeginDragging(DragIndex: Integer); override; procedure DoDragging; override; procedure DoEndDragging(Flag: Boolean); override; procedure LoadItems(List: TStrings); override; procedure UpdateItems; override; end; {TdxHeadersListBox} TdxHeadersListBox = class(TdxCustomizingListBox) protected procedure BeginDragging(DragIndex: Integer); override; procedure DoDragging; override; procedure DoEndDragging(Flag: Boolean); override; procedure LoadItems(List: TStrings); override; procedure UpdateItems; override; end; {TdxTreeListTextNode} PdxTextNodeInfo = ^TdxTextNodeInfo; TdxTextNodeInfo = packed record ImageIndex: Integer; SelectedIndex: Integer; StateIndex: Integer; Data: Pointer; Count: Integer; StrCount: Integer; Str: record end; end; TdxTreeListTextNode = class(TdxTreeListNode) private procedure ReadData(Stream: TStream); procedure WriteData(Stream: TStream); protected FImageIndex: Integer; FSelectedIndex: Integer; FStateIndex: Integer; FStrings: TStrings; public constructor Create(AOwner: TCustomdxTreeList); destructor Destroy; override; end; TCustomdxTreeListControl = class; TdxTreeListColumn = class; {TdxTreeListBand} TdxGridBandFixed = (bfNone, bfLeft, bfRight); TdxTreeListBand = class(TCollectionItem) private FAlignment: TAlignment; FCaption: string; FDisableCustomizing: Boolean; FDisableDragging: Boolean; FFixed: TdxGridBandFixed; FMinWidth: Integer; FOnlyOwnColumns: Boolean; FSizing: Boolean; FVisible: Boolean; FWidth: Integer; function GetHeaderColCount(RowIndex: Integer): Integer; function GetHeaderColumn(RowIndex, ColIndex: Integer): TdxTreeListColumn; function GetHeaderRowCount: Integer; function GetVisibleIndex: Integer; procedure SetAlignment(Value: TAlignment); procedure SetCaption(const Value: string); procedure SetDisableCustomizing(Value: Boolean); procedure SetFixed(Value: TdxGridBandFixed); procedure SetMinWidth(Value: Integer); procedure SetSizing(Value: Boolean); procedure SetVisible(Value: Boolean); procedure SetWidth(Value: Integer); protected function GetdxTreeListControl: TCustomdxTreeListControl; procedure SetIndex(Value: Integer); override; public constructor Create(Collection: TCollection); override; destructor Destroy; override; procedure Assign(Source: TPersistent); override; procedure RestoreDefaults; virtual; property HeaderRowCount: Integer read GetHeaderRowCount; property HeaderColCount[RowIndex: Integer]: Integer read GetHeaderColCount; property HeaderColumn[RowIndex, ColIndex: Integer]: TdxTreeListColumn read GetHeaderColumn; property VisibleIndex: Integer read GetVisibleIndex; published property Alignment: TAlignment read FAlignment write SetAlignment default taCenter; property Caption: string read FCaption write SetCaption; property DisableCustomizing: Boolean read FDisableCustomizing write SetDisableCustomizing default False; property DisableDragging: Boolean read FDisableDragging write FDisableDragging default False; property Fixed: TdxGridBandFixed read FFixed write SetFixed default bfNone; property MinWidth: Integer read FMinWidth write SetMinWidth default dxGridBandMinWidth; property OnlyOwnColumns: Boolean read FOnlyOwnColumns write FOnlyOwnColumns default False; property Sizing: Boolean read FSizing write SetSizing default True; property Visible: Boolean read FVisible write SetVisible default True; property Width: Integer read FWidth write SetWidth default dxGridBandDefaultWidth; end; TdxTreeListBandClass = class of TdxTreeListBand; {TdxTreeListBands} TdxTreeListBands = class(TCollection) private FTreeList: TCustomdxTreeListControl; function GetItem(Index: Integer): TdxTreeListBand; function GetVisibleCount: Integer; function GetVisibleItem(Index: Integer): TdxTreeListBand; procedure SetItem(Index: Integer; Value: TdxTreeListBand); procedure SetVisibleItem(Index: Integer; Value: TdxTreeListBand); protected function GetOwner: TPersistent; {$IFDEF DELPHI3} override;{$ENDIF} procedure RefreshFixedBands; procedure Update(Item: TCollectionItem); override; public constructor Create(ATreeList: TCustomdxTreeListControl; BandClass: TdxTreeListBandClass); function Add: TdxTreeListBand; procedure RestoreDefaults; function GetAbsoluteIndex(VisibleIndex: Integer): Integer; function GetVisibleIndex(AbsoluteIndex: Integer): Integer; // -1 if UnVisible property TreeList: TCustomdxTreeListControl read FTreeList; property Items[Index: Integer]: TdxTreeListBand read GetItem write SetItem; default; property VisibleCount: Integer read GetVisibleCount; property VisibleItems[Index: Integer]: TdxTreeListBand read GetVisibleItem write SetVisibleItem; end; {TdxTreeListColumn} TdxColumnValue = (cvAlignment, cvCaption, cvReadOnly, cvWidth, cvColor, cvFont, cvMaxLength); TdxColumnValues = set of TdxColumnValue; TdxTLCustomDrawCell = procedure(Sender: TObject; ACanvas: TCanvas; ARect: TRect; ANode: TdxTreeListNode; AColumn: TdxTreeListColumn; ASelected, AFocused, ANewItemRow: Boolean; var AText: string; var AColor: TColor; AFont: TFont; var AAlignment: TAlignment; var ADone: Boolean) of object; TdxTLCustomDrawHeader = procedure(Sender: TObject; AColumn: TdxTreeListColumn; ACanvas: TCanvas; ARect: TRect; var AText: string; var AColor: TColor; AFont: TFont; var AAlignment: TAlignment; var ASorted: TdxTreeListColumnSort; var ADone: Boolean) of object; TdxInplaceTreeListTextEdit = class(TdxInplaceTextEdit); TdxTreeListColumn = class(TComponent) private FTreeList: TCustomdxTreeListControl; FAlignment: TAlignment; FCaption: string; FCharCase: TEditCharCase; FColor: TColor; FDisableCaption: Boolean; FDisableCustomizing: Boolean; FDisableEditor: Boolean; FDisableDragging: Boolean; FFont: TFont; FHeaderAlignment: TAlignment; FHeaderGlyph: TBitmap; FMaxLength: Integer; FMinWidth: Integer; FOEMConvert: Boolean; FPasswordChar: Char; FReadonly: Boolean; FSortedOrder: Integer; FSizing: Boolean; FTabStop: Boolean; FVertAlignment: TTextLayout; FVisible: Boolean; FWidth: Integer; FAssignedValues: TdxColumnValues; FOnChangeName: TNotifyEvent; FBandIndex: Integer; FRowIndex: Integer; FHeaderMaxLineCount: Integer; FStoredRowIndex: Integer; FViewData: TdxEditViewData; FDisableFilter: Boolean; FOnChange: TNotifyEvent; FOnCustomDrawCell: TdxTLCustomDrawCell; FOnCustomDrawColumnHeader: TdxTLCustomDrawHeader; FOnValidate: TdxEditValidateEvent; function GetAlignment: TAlignment; function GetCaption: string; function GetColor: TColor; function GetFont: TFont; function GetHeaderGlyph: TBitmap; function GetMaxLength: Integer; function GetReadOnly: Boolean; function GetVisible: Boolean; function GetWidth: Integer; function IsAlignmentStored: Boolean; function IsCaptionStored: Boolean; function IsColorStored: Boolean; function IsFontStored: Boolean; function IsMaxLengthStored: Boolean; function IsReadOnlyStored: Boolean; function IsWidthStored: Boolean; procedure SetAlignment(Value: TAlignment); procedure SetCaption(const Value: string); procedure SetCharCase(Value: TEditCharCase); procedure SetColor(Value: TColor); procedure SetDisableCaption(Value: Boolean); procedure SetDisableCustomizing(Value: Boolean); procedure SetDisableFilter(Value: Boolean); procedure SetFont(Value: TFont); procedure SetHeaderAlignment(Value: TAlignment); procedure SetHeaderGlyph(Value: TBitmap); procedure SetMaxLength(Value: Integer); procedure SetMinWidth(Value: Integer); procedure SetOEMConvert(Value: Boolean); procedure SetPasswordChar(Value: Char); procedure SetReadOnly(Value: Boolean); procedure SetSizing(Value: Boolean); procedure SetSorted(Value: TdxTreeListColumnSort); procedure SetVertAlignment(Value: TTextLayout); procedure SetVisible(Value: Boolean); procedure SetWidth(Value: Integer); procedure SetTreeList(TreeList: TCustomdxTreeListControl); function GetBandIndex: Integer; function GetRowIndex: Integer; function GetColIndex: Integer; function GetHeaderMaxLineCount: Integer; procedure SetBandIndex(Value: Integer); procedure SetRowIndex(Value: Integer); procedure SetColIndex(Value: Integer); procedure SetHeaderMaxLineCount(Value: Integer); function GetSortedOrder: Integer; procedure ReadSortedOrder(Reader: TReader); procedure WriteSortedOrder(Writer: TWriter); procedure ReadStoredRowIndex(Reader: TReader); procedure WriteStoredRowIndex(Writer: TWriter); protected FSorted: TdxTreeListColumnSort; // TODO Wrapper Column FActualIndex: Integer; FActualNode: TdxTreeListNode; // override TComponent procedure DefineProperties(Filer: TFiler); override; procedure ReadState(Reader: TReader); override; procedure SetName(const Value: TComponentName); override; procedure SetParentComponent(AParent: TComponent); override; // original function AssignEditValue(ANode: TdxTreeListNode; AInplaceEdit: TdxInplaceEdit): Variant; virtual; function AssignedDrawCellEvent: Boolean; virtual; procedure Changed(AllItems: Boolean); procedure ChangedWidth(Value: Integer); procedure DoChange(Sender: TObject); virtual; procedure DoDrawCell(ACanvas: TCanvas; var ARect: TRect; ANode: TdxTreeListNode; ASelected, AFocused: Boolean; ANewItemRow: Boolean; ALeftEdge, ARightEdge: Boolean; ABrush: HBRUSH; var AText: string; var AColor: TColor; AFont: TFont; var AAlignment: TAlignment; var ADone: Boolean); virtual; procedure DoValidate(Sender: TObject; var ErrorText: string; var Accept: Boolean); virtual; procedure DrawColumnIndent(DC: HDC; var ARect: TRect; ALeftEdge, ARightEdge: Boolean; ABrush: HBRUSH); procedure FontChanged(Sender: TObject); virtual; function GetdxInplaceEditClass: TdxInplaceEditClass; virtual; function GetDisplayText(ANode: TdxTreeListNode): string; virtual; function GetEnableEditor: Boolean; virtual; procedure GetHotTrackCursor(ANode: TdxTreeListNode; var ACursor: TCursor); virtual; function GetIndex: Integer; virtual; function GetMaxRowHeight(ACanvas: TCanvas): Integer; virtual; function GetViewData: TdxEditViewData; virtual; procedure InitEditProperties(AInplaceEdit: TdxInplaceEdit); virtual; function InitEditValue(ANode: TdxTreeListNode; AInplaceEdit: TdxInplaceEdit): Variant; virtual; function IsColumnHotTrack(X, Y: Integer; Node: TdxTreeListNode; var ActiveIndex: Integer): Boolean; virtual; function IsHeaderHotTrack(X, Y: Integer; var HeaderHotTrack: TdxTreeListHeaderHotTrack): Boolean; virtual; function IsColumnMultiLine: Boolean; virtual; function NeedShowButtonEdit(X, Y: Integer; IsCurrentNode: Boolean): Boolean; virtual; procedure PrepareViewData(AViewData: TdxEditViewData; ACellViewData: TdxTreeListCellViewData); virtual; procedure RefreshDefaultFont; procedure RefreshDefaultWidth; procedure SetIndex(Value: Integer); virtual; property SortedOrder: Integer read GetSortedOrder write FSortedOrder; property StoredRowIndex: Integer read FStoredRowIndex write FStoredRowIndex; property ViewData: TdxEditViewData read GetViewData; property DisableFilter: Boolean read FDisableFilter write SetDisableFilter default False; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure Assign(Source: TPersistent); override; function ConvertExportValue(var Value: Variant; IsHTML: Boolean): Boolean; virtual; function DefaultAlignment: TAlignment; virtual; function DefaultCaption: string; virtual; function DefaultColor: TColor; function DefaultFont: TFont; function DefaultMaxLength: Integer; virtual; function DefaultReadOnly: Boolean; virtual; function DefaultWidth: Integer; virtual; function GetBestFit(ACanvas: TCanvas; ANode: TdxTreeListNode): Integer; virtual; function GetDisplayValue(Node: TdxTreeListNode; const Value: string): string; virtual; function GetParentComponent: TComponent; override; function HasParent: Boolean; override; procedure RestoreDefaults; virtual; procedure RestoreDefaultWidth; property AssignedValues: TdxColumnValues read FAssignedValues; property TreeList: TCustomdxTreeListControl read FTreeList write SetTreeList; property Index: Integer read GetIndex write SetIndex; property OnChangeName: TNotifyEvent read FOnChangeName write FOnChangeName; published property Alignment: TAlignment read GetAlignment write SetAlignment stored IsAlignmentStored; property Caption: string read GetCaption write SetCaption stored IsCaptionStored; property CharCase: TEditCharCase read FCharCase write SetCharCase default ecNormal; property Color: TColor read GetColor write SetColor stored IsColorStored; property DisableCaption: Boolean read FDisableCaption write SetDisableCaption default False; property DisableCustomizing: Boolean read FDisableCustomizing write SetDisableCustomizing default False; property DisableDragging: Boolean read FDisableDragging write FDisableDragging default False; property DisableEditor: Boolean read FDisableEditor write FDisableEditor default False; property Font: TFont read GetFont write SetFont stored IsFontStored; property HeaderAlignment: TAlignment read FHeaderAlignment write SetHeaderAlignment default taLeftJustify; property HeaderGlyph: TBitmap read GetHeaderGlyph write SetHeaderGlyph; property MaxLength: Integer read GetMaxLength write SetMaxLength stored IsMaxLengthStored; property MinWidth: Integer read FMinWidth write SetMinWidth default dxGridHeaderMinWidth; property OEMConvert: Boolean read FOEMConvert write SetOEMConvert default False; property PasswordChar: Char read FPasswordChar write SetPasswordChar default #0; property ReadOnly: Boolean read GetReadOnly write SetReadOnly stored IsReadOnlyStored; property Sizing: Boolean read FSizing write SetSizing default True; property Sorted: TdxTreeListColumnSort read FSorted write SetSorted default csNone; property TabStop: Boolean read FTabStop write FTabStop default True; property VertAlignment: TTextLayout read FVertAlignment write SetVertAlignment default tlTop; property Visible: Boolean read GetVisible write SetVisible default True; property Width: Integer read GetWidth write SetWidth stored IsWidthStored; property BandIndex: Integer read GetBandIndex write SetBandIndex; property RowIndex: Integer read GetRowIndex write SetRowIndex; property ColIndex: Integer read GetColIndex write SetColIndex stored False; property HeaderMaxLineCount: Integer read GetHeaderMaxLineCount write SetHeaderMaxLineCount default 1; property OnChange: TNotifyEvent read FOnChange write FOnChange; property OnCustomDrawCell: TdxTLCustomDrawCell read FOnCustomDrawCell write FOnCustomDrawCell; property OnCustomDrawColumnHeader: TdxTLCustomDrawHeader read FOnCustomDrawColumnHeader write FOnCustomDrawColumnHeader; property OnValidate: TdxEditValidateEvent read FOnValidate write FOnValidate; end; TdxTreeListColumnClass = class of TdxTreeListColumn; TdxTreeListDesigner = class; TdxTLCustomDrawBand = procedure(Sender: TObject; ABand: TdxTreeListBand; ACanvas: TCanvas; ARect: TRect; var AText: string; var AColor: TColor; AFont: TFont; var AAlignment: TAlignment; var ADone: Boolean) of object; TdxTLCustomDrawFooterNode = procedure(Sender: TObject; ACanvas: TCanvas; ARect: TRect; ANode: TdxTreeListNode; AColumn: TdxTreeListColumn; AFooterIndex: Integer; var AText: string; var AColor: TColor; AFont: TFont; var AAlignment: TAlignment; var ADone: Boolean) of object; TdxTLCustomDrawFooter = procedure(Sender: TObject; ACanvas: TCanvas; ARect: TRect; ANode: TdxTreeListNode; AColumn: TdxTreeListColumn; var AText: string; var AColor: TColor; AFont: TFont; var AAlignment: TAlignment; var ADone: Boolean) of object; TdxTLCustomDrawPreview = procedure(Sender : TObject; ACanvas: TCanvas; ARect: TRect; ANode: TdxTreeListNode; ASelected: Boolean; var AText: string; var AColor, ATextColor: TColor; AFont: TFont; var ADone: Boolean) of object; TdxTLGetLevelColor = procedure(Sender: TObject; ALevel: Integer; var AColor: TColor) of object; TdxTLCanBandDragging = procedure(Sender: TObject; ABand: TdxTreeListBand; var Allow: Boolean) of object; TdxTLStartBandDragging = procedure(Sender: TObject; ABand: TdxTreeListBand) of object; TdxTLDragOverBand = procedure(Sender: TObject; ABand: TdxTreeListBand; P: TPoint; var Accept: Boolean) of object; TdxTLDragEndBand = procedure(Sender: TObject; ABand: TdxTreeListBand; P: TPoint; AbsoluteIndex, VisibleIndex: Integer; var NewIndex: Integer; var Accept: Boolean) of object; TdxTLShowBand = procedure(Sender: TObject; ABand: TdxTreeListBand; NewIndex: Integer) of object; TdxTLCanHeaderDragging = procedure(Sender: TObject; AColumn: TdxTreeListColumn; var Allow: Boolean) of object; TdxTLStartHeaderDragging = procedure(Sender: TObject; AColumn: TdxTreeListColumn) of object; TdxTLDragOverHeader = procedure(Sender: TObject; AColumn: TdxTreeListColumn; P: TPoint; var Accept: Boolean) of object; TdxTLDragEndHeader = procedure(Sender: TObject; AColumn: TdxTreeListColumn; P: TPoint; var NewPosInfo: TdxHeaderPosInfo; var Accept: Boolean) of object; TdxTLShowHeader = procedure(Sender: TObject; AColumn: TdxTreeListColumn; BandIndex, RowIndex, ColIndex: Integer) of object; TdxTreeListColumnSorting = procedure(Sender: TObject; Column: TdxTreeListColumn; var Allow: Boolean) of object; // obsolete TTLColumnMovedEvent = procedure(Sender: TObject; FromIndex, ToIndex: Longint) of object; TTLCustomDrawEvent = procedure(Sender: TObject; ACanvas: TCanvas; ARect: TRect; ANode: TdxTreeListNode; AColumn: TdxTreeListColumn; const AText: String; AFont: TFont; var AColor: TColor; ASelected, AFocused: Boolean; var ADone: Boolean ) of object; TTLColumnClick = procedure(Sender : TObject; Column : TdxTreeListColumn) of object; TTLColumnSorted = procedure (Sender: TObject; Column: TdxTreeListColumn; var Sorted : TdxTreeListColumnSort) of object; TTLCustomDrawPreviewEvent = procedure(Sender: TObject; ACanvas: TCanvas; ARect: TRect; ANode: TdxTreeListNode; ASelected: Boolean; const AText: String; var ADone : Boolean ) of object; TdxTLEndDragColumn = procedure(Sender : TObject; X, Y: Integer; Column: TdxTreeListColumn; var NewPosition: Integer) of object; TdxTLHeaderMoved = procedure(Sender: TObject; Column: TdxTreeListColumn) of object; // new TdxTLCalcRowLineHeight = procedure(Sender: TObject; Node: TdxTreeListNode; Column: TdxTreeListColumn; const Text: string; BoundsWidth, TextHeight, MaxLineCount: Integer; InflateFlag{obsolete}, GridFlag{obsolete}: Boolean; var LineCount, LineHeight: Integer; var Done: Boolean) of object; TdxTLGetNodeDragText = procedure(Sender: TObject; Node: TdxTreeListNode; Column: TdxTreeListColumn; var AText: string) of object; {TCustomdxTreeListControl} TCustomdxTreeListControl = class(TCustomdxTreeList) private FBands: TdxTreeListBands; FBandMaxRowCount: Integer; FBandRowCount: Integer; FColumns: TList; FDefaultLayout: Boolean; FDesigner: TdxTreeListDesigner; FEditors: TList; FHeaderMinRowCount: Integer; FHeaderPanelMaxRowCount: Integer; FHeaderPanelRowCount: Integer; FIniFileName: string; FIniSectionName: string; FLockSorting: Integer; FParentFormName: string; FRegistryPath: string; FSetAutoHeaderPanelRowCount: Boolean; FSortedColumns: TList; // customize layout FCustomStoring: Boolean; FSavedLayout: Boolean; FLoadedLayout: Boolean; // Events FOnGetImageIndex: TTLGetImageEvent; FOnGetSelectedIndex: TTLGetImageEvent; FOnGetStateIndex: TTLGetImageEvent; FOnCustomDrawBand: TdxTLCustomDrawBand; FOnCustomDrawColumnHeader: TdxTLCustomDrawHeader; FOnCustomDrawCell: TdxTLCustomDrawCell; FOnCustomDrawFooterNode: TdxTLCustomDrawFooterNode; FOnCustomDrawFooter: TdxTLCustomDrawFooter; FOnCustomDrawPreviewCell: TdxTLCustomDrawPreview; FOnGetLevelColor: TdxTLGetLevelColor; FOnIsExistFooterCell: TdxTLIsExistFooterCell; FOnChangedColumnsWidth: TNotifyEvent; FOnCanBandDragging: TdxTLCanBandDragging; FOnStartBandDragging: TdxTLStartBandDragging; FOnDragOverBand: TdxTLDragOverBand; FOnDragEndBand: TdxTLDragEndBand; FOnShowBand: TdxTLShowBand; FOnHideBand: TdxTLStartBandDragging; FOnBandClick: TdxTLStartBandDragging; FOnCanHeaderDragging: TdxTLCanHeaderDragging; FOnStartHeaderDragging: TdxTLStartHeaderDragging; FOnDragOverHeader: TdxTLDragOverHeader; FOnDragEndHeader: TdxTLDragEndHeader; FOnShowHeader: TdxTLShowHeader; FOnHideHeader: TdxTLStartHeaderDragging; FOnColumnClick: TTLColumnClick; FOnBandButtonClick: TNotifyEvent; FOnHeaderButtonClick: TNotifyEvent; FOnColumnSorting: TdxTreeListColumnSorting; FOnColumnSorted : TTLColumnSorted; FOnHeaderMoved: TdxTLHeaderMoved; // obsolete FOnColumnMoved: TTLColumnMovedEvent; FOnCustomDraw: TTLCustomDrawEvent; FOnCustomDrawPreview: TTLCustomDrawPreviewEvent; FOnEndDragColumn: TdxTLEndDragColumn; //new FOnCalcRowLineHeight: TdxTLCalcRowLineHeight; FOnGetNodeDragText: TdxTLGetNodeDragText; procedure AddColumn(Column: TdxTreeListColumn); function GetColumn(Index: Integer): TdxTreeListColumn; function GetColumnCount: Integer; function GetDefaultLayout: Boolean; function GetSortedColumns(Index: Integer): TdxTreeListColumn; function GetVisibleColumn(Index: Integer): TdxTreeListColumn; function GetVisibleColumnCount: Integer; function IsHeaderPanelRowCountStored: Boolean; procedure MakeDefaultLayout; procedure SetBands(Value: TdxTreeListBands); procedure SetBandMaxRowCount(Value: Integer); procedure SetBandRowCount(Value: Integer); procedure SetColumn(Index: Integer; Value: TdxTreeListColumn); procedure SetHeaderPanelMaxRowCount(Value: Integer); procedure SetHeaderPanelRowCount(Value: Integer); procedure SetHeaderRowCount(Value: Integer); procedure RefreshRowIndexes; procedure SetDefaultLayout(Value: Boolean); procedure SetVisibleColumn(Index: Integer; Value: TdxTreeListColumn); // messages procedure CMCursorChanged(var Message: TMessage); message CM_CURSORCHANGED; procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED; protected // speed FBandList: TList; FBandVisibleList: TList; FBandListLoading: Boolean; FHeaderAbsoluteList: TList; FHeaderListLoading: Boolean; FHeaderBounds: TList; FHeaderBoundsLoading: Boolean; FLockRefreshRowIndexes: Integer; // Bands (size) function GetAbsoluteBandAlignment(AbsoluteIndex: Integer): TAlignment; override; function GetAbsoluteBandCount: Integer; override; function GetAbsoluteBandIndex(VisibleIndex: Integer): Integer; override; function GetAbsoluteBandText(AbsoluteIndex: Integer): string; override; function GetAbsoluteBandWidth(AbsoluteIndex: Integer): Integer; override; function GetBandAlignment(VisibleIndex: Integer): TAlignment; override; function GetBandCount: Integer; override; function GetBandFixedLeft: Integer; override; function GetBandFixedRight: Integer; override; function GetBandMinWidthSize(VisibleIndex: Integer): Integer; override; function GetBandText(VisibleIndex: Integer): string; override; function GetBandSizeWidth(VisibleIndex: Integer): Integer; override; function GetVisibleBandIndex(AbsoluteIndex: Integer): Integer; override; function IsOwnBand(ABandIndex: Integer{VisibleIndex}): Boolean; override; // Headers (size) function GetColumnColor(AbsoluteIndex: Integer): TColor; override; function GetColumnFont(AbsoluteIndex: Integer): TFont; override; function GetHeaderAbsoluteCount: Integer; override; function GetHeaderAbsoluteIndex(BandIndex, RowIndex, ColIndex: Integer): Integer; override; function GetHeaderAlignment(AbsoluteIndex: Integer): TAlignment; override; function GetHeaderBandIndex(AbsoluteIndex: Integer): Integer; override; function GetHeaderBoundsWidth(AbsoluteIndex: Integer): Integer; override; function GetHeaderColCount(BandIndex, RowIndex: Integer): Integer; override; function GetHeaderColIndex(AbsoluteIndex: Integer): Integer; override; function GetHeaderDropDownButtonState(AbsoluteIndex: Integer): TdxHeaderDropDownButtonState; override; function GetHeaderGlyph(AbsoluteIndex: Integer): TBitmap; override; function GetHeaderMaxLineCount(AbsoluteIndex: Integer): Integer; override; function GetHeaderMaxRowHeight(ACanvas: TCanvas; AbsoluteIndex: Integer): Integer; override; // column (image) function GetHeaderMinWidth(AbsoluteIndex: Integer): Integer; override; function GetHeaderRowCount(BandIndex: Integer): Integer; override; function GetHeaderRowIndex(AbsoluteIndex: Integer): Integer; override; function GetHeaderSorted(AbsoluteIndex: Integer): TdxTreeListColumnSort; override; function GetHeaderTabStop(AbsoluteIndex: Integer): Boolean; override; function GetHeaderText(AbsoluteIndex: Integer): string; override; function GetHeaderTextListBox(AbsoluteIndex: Integer): string; override; function GetHeaderWidth(AbsoluteIndex: Integer): Integer; override; function IsExistColumnFont(AbsoluteIndex: Integer): Boolean; override; function IsExistHeaderGlyph(AbsoluteIndex: Integer): Boolean; override; // Cells function GetCellAlignment(Node: TdxTreeListNode; AbsoluteIndex: Integer): TAlignment; override; function GetCellText(Node: TdxTreeListNode; AbsoluteIndex: Integer): string; override; function IsCellMultiLine(AbsoluteIndex: Integer): Boolean; override; // Sizing, Clicking function CanBandSizing(VisibleIndex: Integer): Boolean; override; function CanHeaderSizing(AbsoluteIndex: Integer): Boolean; override; procedure ChangedBandRowCount(BandRowCount: Integer); override; procedure ChangedBandWidth(VisibleIndex, Width: Integer); override; procedure ChangedHeaderMaxRowCount(RowCount: Integer); override; procedure ChangedHeaderWidth(AbsoluteIndex, Width: Integer); override; procedure ChangeHiddenBandWidth(ScaleNum, ScaleDenom: Integer); override; procedure ChangeHiddenHeaderWidth(BandIndex: Integer; ScaleNum, ScaleDenom: Integer); override; function GetBandMaxRowCount: Integer; override; function GetBandRowCount: Integer; override; function GetHeaderMaxLimitRowCount: Integer; override; function GetHeaderMaxRowCount: Integer; override; function GetHeaderLineRowCount: Integer; override; procedure DoBandButtonClick; override; procedure DoBandClick(VisibleIndex: Integer); override; procedure DoBestFitBand(BandIndex: Integer); override; procedure DoBestFitColumn(AbsoluteIndex: Integer); override; procedure DoChangedColumnsWidth; override; procedure DoHeaderButtonClick; override; procedure DoHeaderClick(AbsoluteIndex: Integer); override; function IsBandHeaderWidth: Boolean; override; // DragDrop function GetNodeDragText(Node: TdxTreeListNode; AbsoluteIndex: Integer): string; override; // DragDrop Bands procedure BandMoved(FromIndex, ToIndex: Integer); override; function CanBandDragging(VisibleIndex: Integer): Boolean; override; procedure DoDragOverBand(P: TPoint; AbsoluteIndex: Integer; var Accept: Boolean); override; procedure DoEndDragBand(P: TPoint; AbsoluteIndex, VisibleIndex: Integer; var NewIndex: Integer; var Accept: Boolean); override; function GetBandDisableCustomizing(AbsoluteIndex: Integer): Boolean; override; procedure HideBand(AbsoluteIndex: Integer); override; function IsBandInListBox(AbsoluteIndex: Integer): Boolean; override; procedure ShowBand(NewIndex{visible index}, AbsoluteIndex: Integer); override; procedure StartDragBand(AbsoluteIndex: Integer); override; // DragDrop Headers function CanHeaderDragging(AbsoluteIndex: Integer): Boolean; override; procedure DoDragOverHeader(P: TPoint; AbsoluteIndex: Integer; var Accept: Boolean); override; procedure DoEndDragHeader(P: TPoint; AbsoluteIndex: Integer; var NewPosInfo: TdxHeaderPosInfo; var Accept: Boolean); override; function GetHeaderDisableCustomizing(AbsoluteIndex: Integer): Boolean; override; procedure HeaderMoved(FromAbsoluteIndex, ToBandIndex, ToRowIndex, ToColIndex: Integer); override; procedure HideHeader(AbsoluteIndex: Integer); override; function IsHeaderInListBox(AbsoluteIndex: Integer): Boolean; override; function IsHeaderVisible(AbsoluteIndex: Integer): Boolean; override; procedure ShowColumnHeader(BandIndex, RowIndex, ColIndex, AbsoluteIndex: Integer); override; procedure StartDragHeader(AbsoluteIndex: Integer); override; // Editor function CreateEditor(AColumn: Integer): TdxInplaceEdit; override; procedure DoBeforeEditing(Node : TdxTreeListNode; var AllowEditing: Boolean); override; procedure DoHotTrackNode(AHotTrackInfo: TdxTreeListHotTrackInfo; var ACursor: TCursor); override; function FindInplaceEdit(AColumn: Integer): TdxInplaceEdit; override; procedure InitEditProperties(AInplaceEdit: TdxInplaceEdit); override; function InitEditValue(ANode: TdxTreeListNode; AInplaceEdit: TdxInplaceEdit): Variant; override; // virtual procedure ClearBoundsInfo; override; procedure ClearListNodes; override; procedure ClearNodeRowHeight; override; function IsColumnHotTrack(X, Y: Integer; Node: TdxTreeListNode; ColumnAbsoluteIndex: Integer; var ActiveIndex: Integer): Boolean; override; function IsHeaderHotTrack(X, Y: Integer; ColumnAbsoluteIndex: Integer; var HeaderHotTrack: TdxTreeListHeaderHotTrack): Boolean; override; procedure MakeBandHeaderList(CalcBounds: Boolean); override; procedure MakeBoundsInfo; override; procedure MakeListNodes; override; procedure MoveNodeValues(FromIndex, ToIndex: Integer); virtual; function NeedShowButtonEdit(X, Y: Integer; IsCurrentNode: Boolean; ColumnAbsoluteIndex: Integer): Boolean; override; procedure ResetAutoHeaderPanelRowCountOption; virtual; procedure UpdateBands; virtual; procedure UpdateColumn(Column: TdxTreeListColumn); virtual; procedure UpdateHeaders; virtual; // Sorting procedure AddSortedColumn(Column: TdxTreeListColumn); virtual; function CanColumnSorting(Column: TdxTreeListColumn): Boolean; virtual; procedure DoColumnSort(Column: TdxTreeListColumn); virtual; procedure PrepareColumnSorted(Column: TdxTreeListColumn); virtual; procedure RefreshSortedList; procedure RemoveSortedColumn(Column: TdxTreeListColumn); virtual; procedure SetColumnSorted(Column: TdxTreeListColumn); virtual; // based procedure BeginCustomLayout; override; function CanEditModify: Boolean; override; function CreateNode: TdxTreeListNode; override; procedure DoRestoreLayout; override; procedure DoSaveLayout; override; function GetSortedColumnCount: Integer; override; function GetSortedColumnDesc(Index: Integer): Boolean; override; function GetSortedColumnIndex(Index: Integer): Integer; override; function GetNodeImageIndex(Node : TdxTreeListNode) : Integer; override; function GetNodeSelectedIndex(Node : TdxTreeListNode) : Integer; override; function GetNodeStateIndex(Node : TdxTreeListNode) : Integer; override; function GetNodeValue(Node : TdxTreeListNode; Column : Integer) : Variant; override; function GetNodeString(Node: TdxTreeListNode; Column: Integer): string; override; function LockSorting: Boolean; procedure RemoveColumn(Column: TdxTreeListColumn); virtual; procedure SetNodeImageIndex(Node : TdxTreeListNode; Value : Integer); override; procedure SetNodeSelectedIndex(Node : TdxTreeListNode; Value : Integer); override; procedure SetNodeStateIndex(Node : TdxTreeListNode; Value : Integer); override; procedure SetNodeString(Node: TdxTreeListNode; Column: Integer; const Value: string); override; procedure SetNodeValue(Node: TdxTreeListNode; Column: Integer; const Value: Variant); override; // Save/Load procedure BeginReadSettings(ARegIniWrapper: TdxRegIniWrapper); virtual; procedure EndReadSettings(ARegIniWrapper: TdxRegIniWrapper); virtual; procedure LoadFromRegIni(ARegIniObject: TObject; APath: string); procedure ReadColumn(ARegIniWrapper: TdxRegIniWrapper; const APathCol: string; AColumn: TdxTreeListColumn); virtual; procedure ReadSettings(ARegIniWrapper: TdxRegIniWrapper; const APath: string); virtual; procedure SaveToRegIni(ARegIniObject: TObject; APath: string); procedure WriteColumn(ARegIniWrapper: TdxRegIniWrapper; const APathCol: string; AColumn: TdxTreeListColumn); virtual; procedure WriteSettings(ARegIniWrapper: TdxRegIniWrapper; const APath: string); virtual; // TComponent procedure GetChildren(Proc: TGetChildProc{$IFDEF DELPHI3}; Root: TComponent{$ENDIF}); override; procedure SetChildOrder(Component: TComponent; Order: Integer); override; procedure Loaded; override; procedure SetParent(AParent: TWinControl); override; // Draw function AssignedDrawBandEvent(VisibleIndex: Integer): Boolean; override; function AssignedDrawCellEvent(ANode: TdxTreeListNode; AbsoluteIndex: Integer): Boolean; override; function AssignedDrawFooterCellEvent(ANode: TdxTreeListNode; AbsoluteIndex, FooterIndex: Integer): Boolean; override; function AssignedDrawHeaderEvent(AbsoluteIndex: Integer): Boolean; override; function AssignedDrawPreviewEvent: Boolean; override; function AssignedLevelColorEvent: Boolean; override; procedure DoDrawBand(VisibleIndex: Integer; ACanvas: TCanvas; ARect, AClipRect: TRect; var AText: string; var AColor: TColor; AFont: TFont; var AAlignment: TAlignment; var ADone: Boolean); override; procedure DoDrawCell(ACanvas: TCanvas; var ARect: TRect; ANode: TdxTreeListNode; AIndex: Integer; ASelected, AFocused: Boolean; ANewItemRow: Boolean; ALeftEdge, ARightEdge: Boolean; ABrush: HBRUSH; var AText: string; var AColor: TColor; AFont: TFont; var AAlignment: TAlignment; var ADone: Boolean); override; procedure DoDrawFooterCell(ACanvas: TCanvas; ARect: TRect; ANode: TdxTreeListNode; AIndex, AFooterIndex: Integer; var AText: string; var AColor: TColor; AFont: TFont; var AAlignment: TAlignment; var ADone: Boolean); override; procedure DoDrawHeader(AbsoluteIndex: Integer; ACanvas: TCanvas; ARect, AClipRect: TRect; var AText: string; var AColor: TColor; AFont: TFont; var AAlignment: TAlignment; var ASorted: TdxTreeListColumnSort; var ADone: Boolean); override; procedure DoDrawPreview(ACanvas: TCanvas; ARect: TRect; ANode: TdxTreeListNode; ASelected: Boolean; var AText: string; var AColor, ATextColor: TColor; AFont: TFont; var ADone: Boolean); override; procedure DoGetLevelColor(ALevel: Integer; var AColor: TColor); override; function IsExistFooterCell(AbsoluteIndex: Integer): Boolean; override; // TODO PAINT1 procedure DefaultDrawCell(ADC: HDC; ARect: TRect; AAbsoluteIndex: Integer; ACellViewData: TdxTreeListCellViewData); override; procedure CalcCellViewBoundsRect(const ACellRect: TRect; var AViewRect: TRect); virtual; property IniFileName: string read FIniFileName write FIniFileName; property IniSectionName: string read FIniSectionName write FIniSectionName; property IsCustomStoring: Boolean read FCustomStoring write FCustomStoring; property LoadedLayout: Boolean read FLoadedLayout write FLoadedLayout; property RegistryPath: string read FRegistryPath write FRegistryPath; // Events property OnGetImageIndex: TTLGetImageEvent read FOnGetImageIndex write FOnGetImageIndex; property OnGetSelectedIndex: TTLGetImageEvent read FOnGetSelectedIndex write FOnGetSelectedIndex; property OnGetStateIndex: TTLGetImageEvent read FOnGetStateIndex write FOnGetStateIndex; property OnCustomDrawBand: TdxTLCustomDrawBand read FOnCustomDrawBand write FOnCustomDrawBand; property OnCustomDrawColumnHeader: TdxTLCustomDrawHeader read FOnCustomDrawColumnHeader write FOnCustomDrawColumnHeader; property OnCustomDrawCell: TdxTLCustomDrawCell read FOnCustomDrawCell write FOnCustomDrawCell; property OnCustomDrawFooterNode: TdxTLCustomDrawFooterNode read FOnCustomDrawFooterNode write FOnCustomDrawFooterNode; property OnCustomDrawFooter: TdxTLCustomDrawFooter read FOnCustomDrawFooter write FOnCustomDrawFooter; property OnCustomDrawPreviewCell: TdxTLCustomDrawPreview read FOnCustomDrawPreviewCell write FOnCustomDrawPreviewCell; property OnGetLevelColor: TdxTLGetLevelColor read FOnGetLevelColor write FOnGetLevelColor; property OnIsExistFooterCell: TdxTLIsExistFooterCell read FOnIsExistFooterCell write FOnIsExistFooterCell; property OnCanBandDragging: TdxTLCanBandDragging read FOnCanBandDragging write FOnCanBandDragging; property OnChangedColumnsWidth: TNotifyEvent read FOnChangedColumnsWidth write FOnChangedColumnsWidth; property OnStartBandDragging: TdxTLStartBandDragging read FOnStartBandDragging write FOnStartBandDragging; property OnDragOverBand: TdxTLDragOverBand read FOnDragOverBand write FOnDragOverBand; property OnDragEndBand: TdxTLDragEndBand read FOnDragEndBand write FOnDragEndBand; property OnShowBand: TdxTLShowBand read FOnShowBand write FOnShowBand; property OnHideBand: TdxTLStartBandDragging read FOnHideBand write FOnHideBand; property OnBandClick: TdxTLStartBandDragging read FOnBandClick write FOnBandClick; property OnCanHeaderDragging: TdxTLCanHeaderDragging read FOnCanHeaderDragging write FOnCanHeaderDragging; property OnStartHeaderDragging: TdxTLStartHeaderDragging read FOnStartHeaderDragging write FOnStartHeaderDragging; property OnDragOverHeader: TdxTLDragOverHeader read FOnDragOverHeader write FOnDragOverHeader; property OnDragEndHeader: TdxTLDragEndHeader read FOnDragEndHeader write FOnDragEndHeader; property OnShowHeader: TdxTLShowHeader read FOnShowHeader write FOnShowHeader; property OnHideHeader: TdxTLStartHeaderDragging read FOnHideHeader write FOnHideHeader; property OnColumnClick: TTLColumnClick read FOnColumnClick write FOnColumnClick; property OnBandButtonClick: TNotifyEvent read FOnBandButtonClick write FOnBandButtonClick; property OnHeaderButtonClick: TNotifyEvent read FOnHeaderButtonClick write FOnHeaderButtonClick; property OnColumnSorting: TdxTreeListColumnSorting read FOnColumnSorting write FOnColumnSorting; property OnColumnSorted: TTLColumnSorted read FOnColumnSorted write FOnColumnSorted; property OnHeaderMoved: TdxTLHeaderMoved read FOnHeaderMoved write FOnHeaderMoved; // obsolete property OnColumnMoved: TTLColumnMovedEvent read FOnColumnMoved write FOnColumnMoved; property OnCustomDraw: TTLCustomDrawEvent read FOnCustomDraw write FOnCustomDraw; property OnCustomDrawPreview: TTLCustomDrawPreviewEvent read FOnCustomDrawPreview write FOnCustomDrawPreview; property OnEndDragColumn: TdxTLEndDragColumn read FOnEndDragColumn write FOnEndDragColumn; // new property OnCalcRowLineHeight: TdxTLCalcRowLineHeight read FOnCalcRowLineHeight write FOnCalcRowLineHeight; property OnGetNodeDragText: TdxTLGetNodeDragText read FOnGetNodeDragText write FOnGetNodeDragText; public constructor Create(AOwner : TComponent); override; destructor Destroy; override; procedure ApplyBestFit(AColumn: TdxTreeListColumn); virtual; // nil - all columns procedure AssignColumns(ATreeListControl: TCustomdxTreeListControl); virtual; function ColumnByName(const AName: string): TdxTreeListColumn; function CreateColumn(ColumnClass: TdxTreeListColumnClass): TdxTreeListColumn; function CreateColumnEx(ColumnClass: TdxTreeListColumnClass; AOwner: TComponent): TdxTreeListColumn; procedure DestroyColumns; virtual; function GetAbsoluteColumnIndex(VisibleIndex: Integer): Integer; function GetDisplayValue(Node: TdxTreeListNode; AbsoluteIndex: Integer): string; function GetVisibleColumnIndex(AbsoluteIndex: Integer): Integer; procedure RefreshDefaultColumnsWidths; procedure RestoreColumnsDefaults; // hit test functions function GetBandAt(X, Y: Integer): TdxTreeListBand; function GetColumnAt(X, Y: Integer): TdxTreeListColumn; function GetFooterColumnAt(X, Y: Integer): TdxTreeListColumn; function GetHeaderColumnAt(X, Y: Integer): TdxTreeListColumn; function GetNodeFooterColumnAt(X, Y: Integer): TdxTreeListColumn; // multi sort procedure BeginSorting; procedure ClearColumnsSorted; override; procedure EndSorting; procedure RefreshSorting; virtual; // multi headers procedure HeaderPanelBestFit; override; // new function ColumnCalcLineCount(ANode: TdxTreeListNode; AbsoluteIndex: Integer; const Text: string; BoundsWidth, TextHeight, MaxLineCount: Integer; InflateFlag{obsolete}, GridFlag{obsolete}: Boolean; var LineCount, LineHeight: Integer): Boolean; override; // Save/Restore Layout procedure LoadFromIniFile(const AFileName: string); procedure LoadFromRegistry(const ARegPath: string); procedure SaveToIniFile(const AFileName: string); procedure SaveToRegistry(const ARegPath: string); property ColumnCount: Integer read GetColumnCount; property Columns[Index: Integer]: TdxTreeListColumn read GetColumn write SetColumn; property Designer: TdxTreeListDesigner read FDesigner; property SortedColumnCount: Integer read GetSortedColumnCount; property SortedColumns[Index: Integer]: TdxTreeListColumn read GetSortedColumns; property VisibleColumnCount: Integer read GetVisibleColumnCount; property VisibleColumns[Index: Integer]: TdxTreeListColumn read GetVisibleColumn write SetVisibleColumn; property FocusedAbsoluteIndex; property FocusedColumn; property LeftCoord; property OnGetEditColor; published property BandMaxRowCount: Integer read FBandMaxRowCount write SetBandMaxRowCount default 5; property BandRowCount: Integer read FBandRowCount write SetBandRowCount default 1; property Bands: TdxTreeListBands read FBands write SetBands; property DefaultLayout: Boolean read GetDefaultLayout write SetDefaultLayout{ default True}; property HeaderMinRowCount: Integer read FHeaderMinRowCount write SetHeaderRowCount default 1; property HeaderPanelMaxRowCount: Integer read FHeaderPanelMaxRowCount write SetHeaderPanelMaxRowCount default 5; property HeaderPanelRowCount: Integer read FHeaderPanelRowCount write SetHeaderPanelRowCount stored IsHeaderPanelRowCountStored{default 1}; end; {TdxTreeListDesigner} TdxTreeListDesigner = class private FTreeList: TCustomdxTreeListControl; public constructor Create(ATreeList: TCustomdxTreeListControl); destructor Destroy; override; procedure LayoutChanged; virtual; property TreeList: TCustomdxTreeListControl read FTreeList; end; {TdxTreeList} TdxTreeList = class(TCustomdxTreeListControl) private FNeededSortRefresh: Boolean; FSelectedNodes: TList; FStreamVersion: Integer; // Events FOnGetFooterCellText: TdxTLGetFooterCellText; FOnGetPreviewLineCount: TdxTLGetPreviewLineCount; FOnGetPreviewText: TdxTLGetPreviewText; FOnGetRowLineCount: TdxTLGetPreviewLineCount; FOnIsExistRowFooterCell: TdxTLIsExistRowFooterCell; FOnIsLevelFooter: TdxTLIsLevelFooter; procedure CheckRefreshSorting; function GetSortedColumn: TdxTreeListColumn; function FindSelectedNode(Node: TdxTreeListNode; var Index: Integer): Boolean; procedure ReadData(Stream: TStream); procedure WriteData(Stream: TStream); protected // override TComponent procedure DefineProperties(Filer: TFiler); override; // Rows function GetPreviewText(Node: TdxTreeListNode): string; override; function GetRowIndicatorKind(Node: TdxTreeListNode; ASelected: Boolean): TdxGridIndicatorKind; override; function GetRowLineCount(Node: TdxTreeListNode; var LineHeight: Integer): Integer; override; function GetRowPreviewLineCount(Node: TdxTreeListNode): Integer; override; // Footer function GetFooterCellText(Node: TdxTreeListNode; AbsoluteIndex, FooterIndex: Integer): string; override; function IsExistRowFooterCell(Node: TdxTreeListNode; AbsoluteIndex, FooterIndex: Integer): Boolean; override; function IsLevelFooter(Level: Integer): Boolean; override; // based procedure AddNode(Node: TdxTreeListNode); override; procedure BeginCustomLayout; override; procedure DeleteNode(Node, Prior, Next: TdxTreeListNode; IsLast, Redraw: Boolean); override; function GetNodeVariant(Node: TdxTreeListNode; Column: Integer) : Variant; override; procedure PrepareColumnSorted(Column: TdxTreeListColumn); override; procedure SetColumnSorted(Column: TdxTreeListColumn); override; procedure SetNodeString(Node: TdxTreeListNode; Column: Integer; const Value: string); override; //Editor function AssignEditValue(ANode: TdxTreeListNode; AColumn: Integer; AInplaceEdit: TdxInplaceEdit): Variant; override; //Selected function GetSelectedCount: Integer; override; function GetSelectedItem(AIndex: Integer): TdxTreeListNode; override; function IsNodeSelected(ANode: TdxTreeListNode): Boolean; override; procedure NodeSelected(ANode: TdxTreeListNode; ASelected: Boolean); override; procedure SelectNodes(N1, N2: TdxTreeListNode); override; public constructor Create(AOwner : TComponent); override; destructor Destroy; override; procedure AssignNodes(Source: TPersistent); procedure ClearColumnsSorted; override; procedure ClearSelection; override; procedure DeleteSelection; override; procedure LoadFromFile(const FileName: string); procedure LoadFromStream(Stream: TStream); procedure RefreshSorting; override; procedure SaveToFile(const FileName: string); procedure SaveToStream(Stream: TStream); procedure SelectAll; property DragNode; property EditingText; property FocusedColumn; property FocusedNumber; property HotTrackInfo; property RowCount; property SelectedCount; property SelectedNodes; property SortedColumn: TdxTreeListColumn read GetSortedColumn; property TopIndex; property VisibleRowCount; 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 TabStop; property Visible; property ArrowsColor; property AutoExpandOnSearch; property AutoSearchColor; property AutoSearchTextColor; property DblClkExpanding; property GroupNodeColor; property GroupNodeTextColor; property RowFooterColor; property RowFooterTextColor; property HeaderColor; property BandColor; property BandFont; property HeaderFont; property HideFocusRect; property HideSelection; property Images; property IndentDesc; property IniFileName; property IniSectionName; property RegistryPath; property FixedBandLineColor; property FixedBandLineWidth; property LookAndFeel; property MaxRowLineCount; property Options; property OptionsEx; property PaintStyle; property StateImages; property DefaultRowHeight; property RowSeparatorLineWidth; property PreviewLines; property PreviewFont; property HighlightColor; property HighlightTextColor; property TreeLineColor; property TreeLineStyle; property HideSelectionColor; property HideSelectionTextColor; property WaitForExpandNodeTime; property ScrollBars; property CustomizingRowCount; property ShowBands; property ShowButtons; property ShowGrid; property ShowPreviewGrid; property ShowHeader; property ShowLines; property ShowRoot; property ShowRowFooter; property SimpleCustomizeBox; property ShowHiddenInCustomizeBox; property ShowIndicator; property ShowFooter; property GridLineColor; 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 OnGetImageIndex; property OnGetSelectedIndex; property OnGetStateIndex; property OnCustomDrawBand; property OnCustomDrawColumnHeader; property OnCustomDrawCell; property OnCustomDrawFooterNode; property OnCustomDrawFooter; property OnCustomDrawPreviewCell; property OnGetLevelColor; property OnChangedColumnsWidth; property OnCanBandDragging; property OnStartBandDragging; property OnDragOverBand; property OnDragEndBand; property OnShowBand; property OnHideBand; property OnBandClick; property OnCanHeaderDragging; property OnStartHeaderDragging; property OnDragOverHeader; property OnDragEndHeader; property OnShowHeader; property OnHideHeader; property OnColumnClick; property OnBandButtonClick; property OnHeaderButtonClick; property OnColumnSorting; property OnColumnSorted; property OnHeaderMoved; // obsolete property OnColumnMoved; property OnCustomDraw; property OnCustomDrawPreview; property OnEndDragColumn; // new property OnCalcRowLineHeight; property OnGetNodeDragText; property OnBeginDragNode; property OnCanNodeSelected; property OnChangeColumn; property OnChangeLeftCoord; property OnChangeNode; property OnChangeTopVisibleNode; property OnCollapsed; property OnCollapsing; property OnCompare; property OnDeletion; property OnEditChange; property OnEdited; property OnEditing; property OnEditValidate; property OnEndColumnsCustomizing; property OnExpanded; property OnExpanding; property OnGetEditColor; property OnGetFooterCellText: TdxTLGetFooterCellText read FOnGetFooterCellText write FOnGetFooterCellText; property OnGetPreviewLineCount: TdxTLGetPreviewLineCount read FOnGetPreviewLineCount write FOnGetPreviewLineCount; property OnGetPreviewText: TdxTLGetPreviewText read FOnGetPreviewText write FOnGetPreviewText; property OnGetRowLineCount: TdxTLGetPreviewLineCount read FOnGetRowLineCount write FOnGetRowLineCount; property OnHotTrackNode; property OnIsExistRowFooterCell: TdxTLIsExistRowFooterCell read FOnIsExistRowFooterCell write FOnIsExistRowFooterCell; property OnIsExistFooterCell; property OnIsLevelFooter: TdxTLIsLevelFooter read FOnIsLevelFooter write FOnIsLevelFooter; property OnSelectedCountChange; {$IFDEF DELPHI4} property Anchors; property Constraints; {$ENDIF} {$IFDEF DELPHI5} property OnContextPopup; {$ENDIF} end; // TODO *** { TdxTreeListEditStyle } TdxTreeListEditStyle = class(TdxEditStyle) private FTreeList: TCustomdxTreeList; protected property TreeList: TCustomdxTreeList read FTreeList; public constructor Create(AEdit: TdxInplaceEdit; ATreeList: TCustomdxTreeList); 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; { TdxTreeListMaskColumn } TdxInplaceTreeListMaskEdit = class(TdxInplaceMaskEdit) end; TdxTreeListMaskColumn = class(TdxTreeListColumn) private FEditMask: string; FIgnoreMaskBlank: Boolean; protected function GetdxInplaceEditClass: TdxInplaceEditClass; override; procedure InitEditProperties(AInplaceEdit: TdxInplaceEdit); override; public procedure Assign(Source: TPersistent); override; procedure RestoreDefaults; override; published property EditMask: string read FEditMask write FEditMask; property IgnoreMaskBlank: Boolean read FIgnoreMaskBlank write FIgnoreMaskBlank default False; end; const NodeHitTests: TdxTreeListHitTests = [htIcon, htStateIcon, htLabel, htSummaryNodeFooter, htPreview, htNewRowItem]; RowHitTests: TdxTreeListHitTests = [htButton, htIcon, htStateIcon, htIndent, htLabel, htRight, htSummaryNodeFooter, htPreview]; DragExpandHitTests: TdxTreeListHitTests = [htButton]; HotTrackHitTests: TdxTreeListHitTests = [htIcon, htStateIcon, htLabel, htNewRowItem]; var sdxGrColumns: string; // 'Customize' sdxGrBandsCaption: string; // ' Bands ' sdxGrHeadersCaption: string; // ' Headers ' function VarCompare(const V1, V2: Variant): Integer; procedure DrawButton(ACanvas: TCanvas; ARect: TRect; YCenter: Integer; IsPlus: Boolean); procedure DrawOutButton(ACanvas: TCanvas; ARect: TRect; IsPlus: Boolean); procedure DrawUltraFlatButton(ADC: HDC; ARect: TRect; AIsPlus: Boolean); procedure DrawSortedShape(DC: HDC; ARect: TRect; IsUp: Boolean); {min width rect -> dxGridSortedShapeMinWidth} procedure DrawBandButton(DC: HDC; var ARect: TRect; ABrush: HBRUSH; ADown: Boolean; AStyle: TdxHeaderButtonStyle; ALookAndFeel: TdxLookAndFeel); procedure DrawBandButtonEx(DC: HDC; var ARect: TRect; ABrush: HBRUSH; ADown: Boolean; AStyle: TdxHeaderButtonStyle; ALookAndFeel: TdxLookAndFeel); procedure DrawFlatButton(ADC: HDC; ARect: TRect; ADropDownButtonState: TdxHeaderDropDownButtonState); procedure DrawBand(DC: HDC; ARect: TRect; ABrush: HBRUSH; const AText: string; ADown: Boolean; AMultiLine: Boolean; AAlignment: TAlignment; ASorted: TdxTreeListColumnSort; AGlyph: TBitmap; AStyle: TdxHeaderButtonStyle; ALookAndFeel: TdxLookAndFeel; ADropDownButtonState: TdxHeaderDropDownButtonState); procedure DrawUltraBandButton(ADC: HDC; var ARect: TRect; ABrush: HBRUSH); procedure DrawIndicatorEx(DC: HDC; ARect, AClipRect: TRect; ABrush: HBRUSH; ABitmap: TBitmap; AKind: TdxGridIndicatorKind; ALookAndFeel: TdxLookAndFeel); procedure DrawFocused(DC: HDC; R: TRect); procedure DrawFramed(DC: HDC; const R: TRect); procedure DrawBandEx(DC: HDC; ARect, AClipRect: TRect; ABrush: HBRUSH; ABitmap: TBitmap; const AText: string; ADown: Boolean; AMultiLine: Boolean; AAlignment: TAlignment; ASorted: TdxTreeListColumnSort; AGlyph: TBitmap; AStyle: TdxHeaderButtonStyle; ALookAndFeel: TdxLookAndFeel; ADropDownButtonState: TdxHeaderDropDownButtonState); procedure InvaliddxTreeListOperation(const Id: string); procedure WriteImage(ACanvas: TCanvas; ARect: TRect; ImageList: TImageList; Index: Integer); procedure WriteBmp(ACanvas: TCanvas; ARect: TRect; ABitmap: TBitmap); // row auto height function GetTextLineCount(const S: string; BoundsWidth, TextHeight, MaxLineCount: Integer; Font: HFONT; InflateFlag, GridFlag: Boolean; var LineHeight: Integer): Integer; // multi select function CompareByAbsoluteIndex(Node1, Node2: TdxTreeListNode): Integer; function CompareNodes(Item1, Item2: Pointer): Integer; function IsEqualText(const S1, S2: string): Boolean; implementation uses Registry, IniFiles; {$R dxTL.Res} type PIntArray = ^TIntArray; TIntArray = array[0..MaxListSize] of Integer; PdxNodeInfo = ^TdxNodeInfo; TdxNodeInfo = record Node: TdxTreeListNode; Index: Integer; end; PNextVariant = ^TNextVariant; PNodeVariant = ^TNodeVariant; TNodeVariant = record Node: TdxTreeListNode; Value: Variant; Desc: Boolean; PNext: PNextVariant; end; TNextVariant = TNodeVariant; { sizing band/header width} TSizingInfo = record AIndex: Integer; Width: Integer; end; PSizingInfoArray = ^TSizingInfoArray; TSizingInfoArray = array [0..dxGridMaxDrawItems - 1] of TSizingInfo; const bmArrow = 'DXGRID_ARROW'; bmEdit = 'DXGRID_EDIT'; bmInsert = 'DXGRID_INSERT'; bmMultiDot = 'DXGRID_MULTIDOT'; bmMultiArrow = 'DXGRID_MULTIARROW'; SaveArrowsBitmap : TBitmap = nil; OutButtonPlus : TBitmap = nil; OutButtonMinus : TBitmap = nil; dxIndicatorImages: TImageList = nil; const ShowHintTimerId = 110; HideHintTimerId = 111; WaitForShowHintTime = 1000; WaitForHideHintTime = 5000; var ClickTimerID: Integer; ScrollTimerID: Integer; ScrollTimerLeftFlag: Boolean; ScrollNodeTimerID: Integer; ScrollNodeTimerTopFlag: Boolean; TempDC: HDC; // temporal DC for calc line count {$IFNDEF DELPHI6} function VarCompare(const V1, V2: Variant): Integer; begin if not VarIsEmpty(V1) and not VarIsEmpty(V2) then try if V1 = V2 then Result := 0 else if V1 < V2 then Result := -1 else Result := 1; except on EVariantError do Result := -1; end else Result := -1; end; {$ELSE} function VarCompare(const V1, V2: Variant): Integer; begin try if V1 = V2 then Result := 0 else if VarIsNull(V1) then Result := -1 else if VarIsNull(V2) then Result := 1 else if V1 < V2 then Result := -1 else Result := 1; except on EVariantError do Result := -1; end end; {$ENDIF} function CompareByAbsoluteIndex(Node1, Node2: TdxTreeListNode): Integer; begin if Node1.HasAsParent(Node2) then Result := 1 else if Node2.HasAsParent(Node1) then Result := -1 else begin while Node1.Level > Node2.Level do Node1 := Node1.Parent; while Node2.Level > Node1.Level do Node2 := Node2.Parent; while Node1.Parent <> Node2.Parent do begin Node1 := Node1.Parent; Node2 := Node2.Parent; end; Result := (Node1.Index - Node2.Index); end; end; function CompareNodes(Item1, Item2: Pointer): Integer; begin Result := Integer(Item1) - Integer(Item2); end; procedure CreateBitmaps; var Bmp: TBitmap; begin SaveArrowsBitmap := TBitmap.Create; OutButtonPlus := TBitmap.Create; OutButtonMinus := TBitmap.Create; // indicator Bmp := TBitmap.Create; try Bmp.LoadFromResourceName(HInstance, bmArrow); dxIndicatorImages := TImageList.CreateSize(Bmp.Width, Bmp.Height); dxIndicatorImages.AddMasked(Bmp, clWhite); Bmp.LoadFromResourceName(HInstance, bmEdit); dxIndicatorImages.AddMasked(Bmp, clWhite); Bmp.LoadFromResourceName(HInstance, bmInsert); dxIndicatorImages.AddMasked(Bmp, clWhite); Bmp.LoadFromResourceName(HInstance, bmMultiDot); dxIndicatorImages.AddMasked(Bmp, clWhite); Bmp.LoadFromResourceName(HInstance, bmMultiArrow); dxIndicatorImages.AddMasked(Bmp, clWhite); finally Bmp.Free; end; end; procedure DestroyBitmaps; begin if dxIndicatorImages <> nil then dxIndicatorImages.Free; dxIndicatorImages := nil; if SaveArrowsBitmap <> nil then SaveArrowsBitmap.Free; if OutButtonPlus <> nil then OutButtonPlus.Free; if OutButtonMinus <> nil then OutButtonMinus.Free; SaveArrowsBitmap := nil; OutButtonPlus := nil; OutButtonMinus := nil; end; function GetTextLineCount(const S: string; BoundsWidth, TextHeight, MaxLineCount: Integer; Font: HFONT; InflateFlag, GridFlag: Boolean; var LineHeight: Integer): Integer; var L: Integer; R: TRect; PrevFont: HFONT; TextYOffset: Integer; SizeText: TSize; begin Result := 0; L := Length(S); if (L > 0) and (MaxLineCount <> 0) then begin R := Bounds(0, 0, BoundsWidth - Byte(GridFlag), TextHeight); if InflateFlag then TextYOffset := 2 else TextYOffset := 1; InflateRect(R, -2{TextXOffset}, -TextYOffset); PrevFont := SelectObject(TempDC, Font); LineHeight := DrawText(TempDC, PChar(S), L, R, DT_LEFT or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX or DT_CALCRECT); if TextHeight <> 0 then Result := LineHeight div TextHeight else begin GetTextExtentPoint(TempDC, 'Wg', Length('Wg'), SizeText); Result := LineHeight div SizeText.cy; end; SelectObject(TempDC, PrevFont); if (MaxLineCount <> -1) and (Result > MaxLineCount) then begin Result := MaxLineCount; if TextHeight <> 0 then LineHeight := Result * TextHeight else LineHeight := Result * SizeText.cy; end; LineHeight := TCustomdxTreeList.CalcTextRowHeight(LineHeight); end; end; function IsRectEmptyEx(const R: TRect): Boolean; begin Result := (R.Left = R.Right) and (R.Top = R.Bottom); end; function Max(X, Y: Integer): Integer; begin Result := Y; if X > Y then Result := X; end; procedure ScrollTimerProc(Wnd: HWND; Msg, TimerID, SysTime: Longint); stdcall; var TreeList: TCustomdxTreeList; begin TreeList := TCustomdxTreeList(FindControl(Wnd)); if TreeList <> nil then with TreeList do begin if ((State in [tsColumnDragging, tsNodeDragging, tsBandDragging]) or (TreeList.FDragObject <> nil)) and ((ScrollTimerLeftFlag and (LeftCoord > 0)) or (not ScrollTimerLeftFlag and (LeftCoord < (GetScrollableBandWidth - GetScrollableWidth)))) then begin if ScrollTimerLeftFlag then LeftCoord := LeftCoord - 32{8} else LeftCoord := LeftCoord + 32{8}; {new modification} UpdateDragging; end else begin KillTimer(Handle, ScrollTimerID); ScrollTimerID := -1; end; end; end; procedure ScrollNodeTimerProc(Wnd: HWnd; Msg, TimerID, SysTime: Longint); stdcall; var TreeList : TCustomdxTreeList; P: TPoint; begin TreeList := TCustomdxTreeList(FindControl(wnd)); if (TreeList.State in [tsNodeDragging]) or (TreeList.FDragObject <> nil) then begin GetCursorPos(P); if WindowFromPoint(P) = TreeList.Handle then if ScrollNodeTimerTopFlag then TreeList.FocusedNumber := TreeList.FocusedNumber - 1 else TreeList.FocusedNumber := TreeList.FocusedNumber + 1; {new modification} TreeList.UpdateDragging; end else begin KillTimer(TreeList.Handle, ScrollNodeTimerID); ScrollNodeTimerID := -1; end; end; procedure MouseScrollTimerProc(Wnd: HWnd; Msg, TimerID, SysTime: Longint); stdcall; var TreeList : TCustomdxTreeList; begin TreeList := TCustomdxTreeList(FindControl(wnd)); if (TreeList.State in [tsNodeDown]) then begin if ScrollNodeTimerTopFlag then TreeList.FocusedNumber := TreeList.FocusedNumber - 1 else TreeList.FocusedNumber := TreeList.FocusedNumber + 1; end else begin KillTimer(TreeList.Handle, ScrollNodeTimerID); ScrollNodeTimerID := -1; end; end; procedure WriteImage(ACanvas: TCanvas; ARect: TRect; ImageList : TImageList; Index : Integer); begin if (ImageList = nil) or (Index >= ImageList.Count) or (Index < 0) then Exit; ImageList.Draw(ACanvas, (ARect.Left + ARect.Right - ImageList.Width + 1) div 2, (ARect.Top + ARect.Bottom - ImageList.Height + 1) div 2, Index); end; procedure WriteBmp(ACanvas: TCanvas; ARect: TRect; ABitmap: TBitmap); begin if ABitmap <> nil then ACanvas.Draw((ARect.Left + ARect.Right - ABitmap.Width + 1) div 2, (ARect.Top + ARect.Bottom - ABitmap.Height + 1) div 2, ABitmap); end; function CustomCompareNodes(Item1, Item2: Pointer): Integer; begin Result := 0; with PNodeVariant(Item1)^.Node do begin Owner.OnCompare(Owner, PNodeVariant(Item1)^.Node, PNodeVariant(Item2)^.Node, Result); if Result = 0 then Result := Owner.CompareEqual(PNodeVariant(Item1)^.Node, PNodeVariant(Item2)^.Node); end; end; function CompareItems(Item1, Item2: Pointer): Integer; begin Result := Integer(PdxNodeInfo(Item1)^.Node) - Integer(PdxNodeInfo(Item2)^.Node); end; // multi sorting function CompareNextVariantValues(PNext1, PNext2: PNextVariant): Integer; begin if PNext1 = nil then Result := 0 else begin if PNext1^.Value = PNext2^.Value then Result := CompareNextVariantValues(PNext1^.PNext, PNext2^.PNext) else begin {$IFNDEF DELPHI6} if PNext1^.Value < PNext2^.Value then Result := -1 else Result := 1; {$ELSE} Result := VarCompare(PNext1^.Value, PNext2^.Value); {$ENDIF} if PNext1^.Desc then Result := - Result; end; end; end; function CompareVariantValues(Item1, Item2: Pointer): Integer; begin if PNodeVariant(Item1)^.Value = PNodeVariant(Item2)^.Value then begin Result := CompareNextVariantValues(PNodeVariant(Item1)^.PNext, PNodeVariant(Item2)^.PNext); if Result = 0 then Result := PNodeVariant(Item1)^.Node.FOwner.CompareEqual(PNodeVariant(Item1)^.Node, PNodeVariant(Item2)^.Node); end else begin {$IFNDEF DELPHI6} if PNodeVariant(Item1)^.Value < PNodeVariant(Item2)^.Value then Result := -1 else Result := 1; {$ELSE} Result := VarCompare(PNodeVariant(Item1)^.Value, PNodeVariant(Item2)^.Value); {$ENDIF} if PNodeVariant(Item1)^.Desc then Result := - Result; end; end; function CompareNextAnsiVariantValues(PNext1, PNext2: PNextVariant): Integer; begin if PNext1 = nil then Result := 0 else begin if PNext1^.Value = PNext2^.Value then Result := CompareNextAnsiVariantValues(PNext1^.PNext, PNext2^.PNext) else begin if PNext1^.Node.FOwner.IsAnsiSort and (VarType(PNext1^.Value) = varString) then Result := AnsiCompareStr(PNext1^.Value, PNext2^.Value) else {$IFNDEF DELPHI6} if PNext1^.Value < PNext2^.Value then Result := -1 else Result := 1; {$ELSE} Result := VarCompare(PNext1^.Value, PNext2^.Value); {$ENDIF} if PNext1^.Desc then Result := - Result; end; end; end; function CompareAnsiVariantValues(Item1, Item2: Pointer): Integer; begin if PNodeVariant(Item1)^.Value = PNodeVariant(Item2)^.Value then begin Result := CompareNextAnsiVariantValues(PNodeVariant(Item1)^.PNext, PNodeVariant(Item2)^.PNext); if Result = 0 then Result := PNodeVariant(Item1)^.Node.FOwner.CompareEqual(PNodeVariant(Item1)^.Node, PNodeVariant(Item2)^.Node); end else begin if PNodeVariant(Item1)^.Node.FOwner.IsAnsiSort and (VarType(PNodeVariant(Item1)^.Value) = varString) then Result := AnsiCompareStr(PNodeVariant(Item1)^.Value, PNodeVariant(Item2)^.Value) else {$IFNDEF DELPHI6} if PNodeVariant(Item1)^.Value < PNodeVariant(Item2)^.Value then Result := -1 else Result := 1; {$ELSE} Result := VarCompare(PNodeVariant(Item1)^.Value, PNodeVariant(Item2)^.Value); {$ENDIF} if PNodeVariant(Item1)^.Desc then Result := - Result; end; end; function CompareSortedOrderColumns(Item1, Item2: Pointer): Integer; begin Result := TdxTreeListColumn(Item1).FSortedOrder - TdxTreeListColumn(Item2).FSortedOrder; end; // button 9x9 procedure DrawButton(ACanvas: TCanvas; ARect: TRect; YCenter: Integer; IsPlus: Boolean); const btSize = 9; begin with ACanvas do begin // calc rect with ARect do begin Left := (Left + Right - btSize) div 2; Top := YCenter - btSize div 2; Right := Left + btSize; Bottom := Top + btSize; end; // draw Windows.FrameRect(Handle, ARect, GetSysColorBrush(COLOR_GRAYTEXT)); {BTNSHADOW} with ARect do begin Windows.FillRect(Handle, Rect(Left + 2, Top + 4, Right - 2{Left + 7}, Top + 4 + 1), {-} GetSysColorBrush(COLOR_WINDOWTEXT)); if IsPlus then Windows.FillRect(Handle, Rect(Left + 4, Top + 2, Left + 4 + 1, Bottom - 2{Top + 7}), {|} GetSysColorBrush(COLOR_WINDOWTEXT)); end; end; end; // button 12x12 procedure DrawOutButton(ACanvas: TCanvas; ARect: TRect; IsPlus: Boolean); begin if IsPlus then WriteBmp(ACanvas, ARect, OutButtonPlus) else WriteBmp(ACanvas, ARect, OutButtonMinus); end; procedure DrawUltraFlatButton(ADC: HDC; ARect: TRect; AIsPlus: Boolean); begin OffsetRect(ARect, (ARect.Right - ARect.Left - 11) div 2, (ARect.Bottom - ARect.Top - 11) div 2); ARect.Right := ARect.Left + 11; ARect.Bottom := ARect.Top + 11; OffsetRect(ARect, 1, 1); DrawEdge(ADC, ARect, BDR_RAISEDOUTER, BF_RIGHT or BF_BOTTOM or BF_FLAT{ or BF_ADJUST}); OffsetRect(ARect, -1, -1); FrameRect(ADC, ARect, GetSysColorBrush(COLOR_WINDOWFRAME)); Dec(ARect.Right); Dec(ARect.Bottom); // Windows.FillRect(Handle, ARect, COLOR_BTNFACE + 1); FillRect(ADC, Rect(ARect.Left + 3, ARect.Top + 5, ARect.Left + 8, ARect.Top + 5 + 1), GetSysColorBrush(COLOR_WINDOWFRAME)); if AIsPlus then FillRect(ADC, Rect(ARect.Left + 5, ARect.Top + 3, ARect.Left + 5 + 1, ARect.Top + 8), GetSysColorBrush(COLOR_WINDOWFRAME)); end; procedure DrawSortedShape(DC: HDC; ARect: TRect; IsUp: Boolean); {min width rect -> dxGridSortedShapeMinWidth} const Width = 8; Height = 7; var PrevPen: HPEN; Points: array [0..2] of TPoint; begin with ARect do begin Left := ((Left + Right) div 2) - (Width div 2); Right := Left + Width; Top := ((Top + Bottom) div 2) - (Height div 2); Bottom := Top + Height; if IsUp then begin // shadow PrevPen := SelectObject(DC, CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW))); Points[0] := Point(Left + Width div 2 - 1, Top); Points[1] := Point(Left, Bottom); Polyline(DC, Points, 2); Points[0] := Point(Left + Width div 2 - 2, Top + 1); Points[1] := Point(Left, Bottom - 1); Polyline(DC, Points, 2); // highlight DeleteObject(SelectObject(DC, CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNHIGHLIGHT)))); Points[0] := Point(Left + 1, Bottom - 1); Points[1] := Point(Left + Width - 1, Bottom - 1); Points[2] := Point(Left + Width div 2, Top - 1); Polyline(DC, Points, 3); Points[0] := Point(Left + Width div 2, Top + 1); Points[1] := Point(Left + Width - 1, Bottom - 1); Polyline(DC, Points, 2); DeleteObject(SelectObject(DC, PrevPen)); end else begin // shadow PrevPen := SelectObject(DC, CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW))); Points[0] := Point(Left + Width - 1, Top); Points[1] := Point(Left, Top); Points[2] := Point(Left + Width div 2 - 1, Bottom); Polyline(DC, Points, 3); Points[0] := Point(Left + 1, Top + 1); Points[1] := Point(Left + Width div 2 - 1, Bottom - 1); Polyline(DC, Points, 2); // highlight DeleteObject(SelectObject(DC, CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNHIGHLIGHT)))); Points[0] := Point(Left + Width - 1, Top + 1); Points[1] := Point(Left + Width div 2, Bottom); Polyline(DC, Points, 2); Points[0] := Point(Left + Width - 2, Top + 1); Points[1] := Point(Left + Width div 2, Bottom - 1); Polyline(DC, Points, 2); DeleteObject(SelectObject(DC, PrevPen)); end; end; end; procedure DrawBandButton(DC: HDC; var ARect: TRect; ABrush: HBRUSH; ADown: Boolean; AStyle: TdxHeaderButtonStyle; ALookAndFeel: TdxLookAndFeel); var R: TRect; begin // Draw Frame if ALookAndFeel = lfStandard then begin DrawEdge(DC, ARect, BDR_RAISEDOUTER, BF_BOTTOMRIGHT or BF_ADJUST); // Draw 3D frame if not ADown then begin DrawEdge(DC, ARect, BDR_RAISEDINNER, BF_BOTTOMRIGHT or BF_ADJUST); DrawEdge(DC, ARect, BDR_RAISEDINNER, BF_TOPLEFT or BF_ADJUST); end else DrawEdge(DC, ARect, BDR_SUNKENOUTER, BF_TOPLEFT or BF_ADJUST); // Fill Background FillRect(DC, ARect, ABrush); end else begin if AStyle = hbNormal then begin if ALookAndFeel = lfUltraFlat then begin FrameRect(DC, ARect, GetSysColorBrush(COLOR_BTNSHADOW)); InflateRect(ARect, -1, -1); end else DrawEdge(DC, ARect, BDR_RAISEDINNER, BF_RECT or BF_ADJUST); FillRect(DC, ARect, ABrush); InflateRect(ARect, -1, 0); end else begin FillRect(DC, ARect, ABrush); R := ARect; if ALookAndFeel = lfUltraFlat then begin DrawEdge(DC, R, BDR_SUNKENOUTER, BF_TOP or BF_FLAT); DrawEdge(DC, R, BDR_SUNKENOUTER, BF_BOTTOM or BF_FLAT); end else begin DrawEdge(DC, R, BDR_RAISEDINNER, BF_TOP); DrawEdge(DC, R, BDR_RAISEDINNER, BF_BOTTOM); end; if AStyle in [hbLeft, hbLeftRight] then begin R.Top := ARect.Top + 2; R.Bottom := ARect.Bottom - 2; end else begin R.Top := ARect.Top + 1; R.Bottom := ARect.Bottom - 1; end; if ALookAndFeel = lfFlat then DrawEdge(DC, R, BDR_RAISEDINNER, BF_LEFT); if AStyle in [hbRight, hbLeftRight] then begin R.Top := ARect.Top + 2; R.Bottom := ARect.Bottom - 2; end else begin R.Top := ARect.Top; R.Bottom := ARect.Bottom - 1; end; DrawEdge(DC, R, BDR_RAISEDINNER, BF_RIGHT); InflateRect(ARect, -2, -1); end; end; end; procedure DrawBandButtonEx(DC: HDC; var ARect: TRect; ABrush: HBRUSH; ADown: Boolean; AStyle: TdxHeaderButtonStyle; ALookAndFeel: TdxLookAndFeel); var R: TRect; begin R := ARect; DrawBandButton(DC, ARect, ABrush, ADown, AStyle, ALookAndFeel); if (ALookAndFeel <> lfStandard) and ADown then with R do BitBlt(DC, Left, Top, Right-Left, Bottom-Top, 0, 0, 0, DSTINVERT); end; procedure DrawFlatButton(ADC: HDC; ARect: TRect; ADropDownButtonState: TdxHeaderDropDownButtonState); var ABkBrush: HBRUSH; APen: HPEN; APenColor: TColorRef; X, Y, Size: Integer; P: array[1..3] of TPoint; begin FrameRect(ADC, ARect, GetSysColorBrush(COLOR_BTNSHADOW)); InflateRect(ARect, -1, -1); if (hdbPushed in ADropDownButtonState) then ABkBrush := GetSysColorBrush(COLOR_BTNTEXT) else if (hdbSelected in ADropDownButtonState) then ABkBrush := GetSysColorBrush(COLOR_BTNSHADOW) else ABkBrush := GetSysColorBrush(COLOR_BTNFACE); FillRect(ADC, ARect, ABkBrush); if ([hdbSelected, hdbPushed] * ADropDownButtonState <> []) then APenColor := GetSysColor(COLOR_WINDOW) else if (hdbActive in ADropDownButtonState) then APenColor := ColorToRGB(clBlue) else APenColor := GetSysColor(COLOR_BTNTEXT); with ARect do begin Size := (Right - Left) div 2; if not Odd(Size) then Inc(Size); X := (Left + Right - Size) div 2; Y := (Top + Bottom - Size div 2) div 2 - Byte(Odd(Bottom - Top)){1}; P[1] := Point(X, Y); P[2] := Point(X + Size - 1, Y); P[3] := Point(X + Size div 2, Y + Size div 2); APen := SelectObject(ADC, CreatePen(PS_SOLID, 1, APenColor)); ABkBrush := SelectObject(ADC, CreateSolidBrush(APenColor)); Polygon(ADC, P, 3); DeleteObject(SelectObject(ADC, ABkBrush)); DeleteObject(SelectObject(ADC, APen)); end; end; procedure DrawBand(DC: HDC; ARect: TRect; ABrush: HBRUSH; const AText: string; ADown: Boolean; AMultiLine: Boolean; AAlignment: TAlignment; ASorted: TdxTreeListColumnSort; AGlyph: TBitmap; AStyle: TdxHeaderButtonStyle; ALookAndFeel: TdxLookAndFeel; ADropDownButtonState: TdxHeaderDropDownButtonState); const DrawFlags: array [Boolean] of Integer = ( DT_EXPANDTABS or DT_NOPREFIX or DT_END_ELLIPSIS or DT_VCENTER or DT_SINGLELINE, DT_EXPANDTABS or DT_NOPREFIX or DT_WORDBREAK); AlignFlags: array [TAlignment] of Integer = (DT_LEFT, DT_RIGHT, DT_CENTER); var R: TRect; Flag: Integer; Size: TSize; AFlat: Boolean; begin // Draw 3D Frame DrawBandButton(DC, ARect, ABrush, ADown, AStyle, ALookAndFeel); AFlat := ALookAndFeel <> lfStandard; // Draw text if not ADown or AFlat then begin InflateRect(ARect, -1, -1); Dec(ARect.Bottom); end else with ARect do begin Inc(Left, 3); Inc(Top, 3); Dec(Bottom); end; if ADropDownButtonState <> [] then begin with ARect do begin if (Right - Left) >= dxGridHeaderFilterBoxWidth then begin R := Rect(Right - dxGridHeaderFilterBoxWidth, Top, Right, Bottom); Dec(Right, dxGridHeaderFilterBoxWidth); Inc(R.Bottom); // Combo Button DrawFlatButton(DC, R, ADropDownButtonState); end; end; end; if ASorted <> csNone then with ARect do begin if (Right - Left) >= dxGridSortedShapeMinWidth then begin R := Rect(Right - dxGridSortedShapeMinWidth, Top, Right, Bottom); Dec(Right, dxGridSortedShapeMinWidth); DrawSortedShape(DC, R, ASorted = csUp); end; end; if (AGlyph <> nil) and not AGlyph.Empty then with ARect do begin if (Right - Left) > 0 then begin R := Rect(Left - 1, Top - 1, Left + AGlyph.Width, Bottom + 2 - Byte(ADown and not AFlat)); if AFlat then OffsetRect(R, -1 , 0); if R.Right > Right + Byte(not ADown or AFlat) + Byte(AFlat) then R.Right := Right + Byte(not ADown or AFlat) + Byte(AFlat); Left := R.Right; TransparentDraw(DC, ABrush, R, AGlyph); end; end; SetBkMode(DC, TRANSPARENT); Flag := 0; if not AMultiLine then begin GetTextExtentPoint32(DC, PChar(AText), Length(AText), Size); if Size.CX <= (ARect.Right - ARect.Left) then Flag := DT_NOCLIP; end; DrawText(DC, PChar(AText), Length(AText), ARect, DrawFlags[AMultiLine] or AlignFlags[AAlignment] or Flag); end; procedure DrawBandEx(DC: HDC; ARect, AClipRect: TRect; ABrush: HBRUSH; ABitmap: TBitmap; {temp draw bitmap} const AText: string; ADown: Boolean; AMultiLine: Boolean; AAlignment: TAlignment; ASorted: TdxTreeListColumnSort; AGlyph: TBitmap; AStyle: TdxHeaderButtonStyle; ALookAndFeel: TdxLookAndFeel; ADropDownButtonState: TdxHeaderDropDownButtonState); var R: TRect; bmpDC: HDC; PrevFont: HFONT; PrevTextColor: TColorRef; begin R := ARect; OffsetRect(R, -R.Left, -R.Top); CheckDrawBitmap(ABitmap, R.Right - R.Left, R.Bottom - R.Top); bmpDC := ABitmap.Canvas.Handle; PrevFont := SelectObject(bmpDC, GetCurrentObject(DC, OBJ_FONT)); PrevTextColor := SetTextColor(bmpDC, GetTextColor(DC)); DrawBand(bmpDC, R, ABrush, AText, ADown, AMultiLine, AAlignment, ASorted, AGlyph, AStyle, ALookAndFeel, ADropDownButtonState); SetTextColor(bmpDC, PrevTextColor); SelectObject(bmpDC, PrevFont); if (ALookAndFeel <> lfStandard) and ADown then with R do BitBlt(bmpDC, Left, Top, Right-Left, Bottom-Top, 0, 0, 0, DSTINVERT); with AClipRect do BitBlt(DC, Left, Top, Right-Left, Bottom-Top, bmpDC, Left - ARect.Left, Top - ARect.Top, SRCCOPY); end; procedure DrawUltraBandButton(ADC: HDC; var ARect: TRect; ABrush: HBRUSH); begin DrawEdge(ADC, ARect, BDR_SUNKENOUTER, BF_BOTTOM or BF_RIGHT or BF_FLAT or BF_ADJUST); FillRect(ADC, ARect, ABrush); InflateRect(ARect, -1, 0); end; procedure DrawIndicatorEx(DC: HDC; ARect, AClipRect: TRect; ABrush: HBRUSH; ABitmap: TBitmap; AKind: TdxGridIndicatorKind; ALookAndFeel: TdxLookAndFeel); var R: TRect; begin R := ARect; OffsetRect(R, -R.Left, -R.Top); CheckDrawBitmap(ABitmap, R.Right - R.Left, R.Bottom - R.Top); // Draw 3D Frame if ALookAndFeel = lfUltraFlat then DrawUltraBandButton(ABitmap.Canvas.Handle, R, ABrush) else DrawBandButton(ABitmap.Canvas.Handle, R, ABrush, False, hbNormal, ALookAndFeel); if AKind <> ikNone then begin with R, dxIndicatorImages do Draw(ABitmap.Canvas, (Left + Right - Width) shr 1, (Top + Bottom - Height) shr 1, Integer(AKind) - 1); end; with AClipRect do BitBlt(DC, Left, Top, Right-Left, Bottom-Top, ABitmap.Canvas.Handle, Left - ARect.Left, Top - ARect.Top, SRCCOPY); end; procedure DrawCellText(DC: HDC; ARect: TRect; ABrush: HBRUSH; AColor: TColor; ABitmap: TBitmap; {temp draw bitmap} const AText: string; ATextLen: Integer; AMultiLine: Boolean; AEndEllipsis: Boolean; AAlignment: TAlignment; UseBitmap, InflateFlag, SearchFlag: Boolean); const DrawFlags: array [Boolean] of Integer = (DT_EXPANDTABS or DT_NOPREFIX or DT_VCENTER or DT_SINGLELINE, DT_EXPANDTABS or DT_NOPREFIX or DT_WORDBREAK); EllipsisFlags: array [Boolean] of Integer = (0, DT_END_ELLIPSIS); AlignFlags: array [TAlignment] of Integer = (DT_LEFT, DT_RIGHT, DT_CENTER); TextXOffset = 2; var R: TRect; bmpDC: HDC; PrevFont: HFONT; I: TColorRef; LeftOffset: Integer; LRect, RRect: TRect; SizeText: TSize; TextYOffset: Integer; procedure Draw(DC: HDC; R: TRect); begin Windows.FillRect(DC, R, ABrush); SetBkMode(DC, TRANSPARENT); InflateRect(R, -TextXOffset, -TextYOffset); DrawText(DC, PChar(AText), ATextLen{Length(AText)}, R, DrawFlags[AMultiLine] or EllipsisFlags[AEndEllipsis] or AlignFlags[AAlignment]); end; begin if InflateFlag then TextYOffset := 2 else TextYOffset := 1; I := ColorToRGB(AColor); if SearchFlag or (not AEndEllipsis and not AMultiLine and (GetNearestColor(DC, I) = I)) then begin SetRectEmpty(LRect); SetRectEmpty(RRect); with ARect do begin RRect := Rect(Right - TextXOffset, Top, Right, Bottom); if RRect.Left < ARect.Left then RRect.Left := ARect.Left; ARect.Right := RRect.Left; if AAlignment in [taRightJustify, taCenter] then begin LRect := Rect(Left, Top, Left + TextXOffset, Bottom); if LRect.Right > ARect.Right then LRect.Right := ARect.Right; ARect.Left := LRect.Right; end; end; case AAlignment of taLeftJustify: with ARect do begin LeftOffset := TextXOffset; end; taRightJustify: with ARect do begin GetTextExtentPoint(DC, PChar(AText), Length(AText), SizeText); LeftOffset := (Right - Left) - SizeText.CX{ - TextXOffset}; end; else {taCenter:} with ARect do begin GetTextExtentPoint(DC, PChar(AText), Length(AText), SizeText); LeftOffset := (ARect.Right - ARect.Left) shr 1 - (SizeText.CX shr 1); end; end; if SearchFlag then SetBkMode(DC, OPAQUE); ExtTextOut(DC, ARect.Left + LeftOffset, ARect.Top + TextYOffset, ETO_CLIPPED or Byte(not SearchFlag)*ETO_OPAQUE, @ARect, PChar(AText), ATextLen{Length(AText)}, nil); if not SearchFlag then begin if not IsRectEmpty(LRect) then FillRect(DC, LRect, ABrush); if not IsRectEmpty(RRect) then FillRect(DC, RRect, ABrush); end; end else {DrawText use Bitmap} begin if UseBitmap then begin R := ARect; OffsetRect(R, -R.Left, -R.Top); CheckDrawBitmap(ABitmap, R.Right - R.Left, R.Bottom - R.Top); bmpDC := ABitmap.Canvas.Handle; PrevFont := SelectObject(bmpDC, GetCurrentObject(DC, OBJ_FONT)); SetTextColor(bmpDC, GetTextColor(DC)); Draw(bmpDC, R); SelectObject(bmpDC, PrevFont); with ARect do BitBlt(DC, Left, Top, Right-Left, Bottom-Top, bmpDC, 0, 0, SRCCOPY); end else begin Draw(DC, ARect); end; end; end; procedure DrawPreviewText(DC: HDC; ARect: TRect; ABrush: HBRUSH; AFont: HFONT; ABitmap: TBitmap; {temp draw bitmap} ATextColor: TColor; const AText: string; AIndent: Integer; UseBitmap: Boolean); const AlignFlag : Integer = DT_LEFT or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX or DT_END_ELLIPSIS; var PrevFont: HFONT; procedure Draw(DC: HDC; R: TRect); begin Windows.FillRect(DC, R, ABrush); SetBkMode(DC, TRANSPARENT); InflateRect(R, -1, -1); Inc(R.Left, AIndent); SetTextColor(DC, ColorToRGB(ATextColor)); PrevFont := SelectObject(DC, AFont); DrawText(DC, PChar(AText), Length(AText), R, AlignFlag); SelectObject(DC, PrevFont); end; var R: TRect; bmpDC: HDC; begin if UseBitmap then begin R := ARect; OffsetRect(R, -R.Left, -R.Top); CheckDrawBitmap(ABitmap, R.Right - R.Left, R.Bottom - R.Top); bmpDC := ABitmap.Canvas.Handle; Draw(bmpDC, R); with ARect do BitBlt(DC, Left, Top, Right-Left, Bottom-Top, bmpDC, 0, 0, SRCCOPY); end else begin Draw(DC, ARect); end; end; procedure DrawFocused(DC: HDC; R: TRect); var PrevBkColor, PrevTextColor: TColorRef; begin PrevBkColor := SetBkColor(DC, clBlack); PrevTextColor := SetTextColor(DC, clWhite); Windows.DrawFocusRect(DC, R); SetBkColor(DC, PrevBkColor); SetTextColor(DC, PrevTextColor); end; procedure DrawFramed(DC: HDC; const R: TRect); begin with R do begin InvertRect(DC, Rect(Left, Top, Right, Top + 1)); InvertRect(DC, Rect(Right - 1, Top + 1, Right, Bottom)); InvertRect(DC, Rect(Left, Top + 1, Left + 1, Bottom{ + 1})); InvertRect(DC, Rect(Left + 1, Bottom - 1, Right - 1, Bottom)); end; end; function IsEqualText(const S1, S2: string): Boolean; begin Result := AnsiUpperCase(S1) = AnsiUpperCase(S2); end; {TdxTreeListNode} procedure InvaliddxTreeListOperation(const Id: string); begin raise EInvaliddxTreeListOperation.Create(Id); end; constructor TdxTreeListNode.Create(AOwner: TCustomdxTreeList); begin // inherited Create; FOwner := AOwner; {if AOwner is Nil - raise exception and destroy yourself} if AOwner = nil then begin InvaliddxTreeListOperation(LoadStr(dxSInvalidOwner)); Exit; end; end; destructor TdxTreeListNode.Destroy; var Prior, Next: TdxTreeListNode; fgLast, fgRedraw: Boolean; begin if FOwner <> nil then begin FDeleting := True; DeleteChildren; if not FOwner.FClearNodes then begin Prior := GetPriorParentNode; Next := FOwner.GetNextVisible(Self); fgLast := IsLast; fgRedraw := IsVisible; FOwner.FMakeListNodeVisible := fgRedraw; if (Parent <> nil) and Parent.Deleting then fgRedraw := False; end else begin Prior := nil; Next := nil; fgLast := False; fgRedraw := False; FOwner.FMakeListNodeVisible := False; end; 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.HasChildren := FOwner.CheckHasChildren(Parent); Parent.FExpanded := False; end; end; end else if (FOwner <> nil) and not FOwner.FClearNodes then FOwner.FNodeList.Remove(self); if FList <> nil then FList.Free; FOwner.DeleteNode(Self, Prior, Next, fgLast, fgRedraw); end; inherited Destroy; end; function TdxTreeListNode.AddChild: TdxTreeListNode; begin Result := InsertChild(nil); end; function TdxTreeListNode.AddChildFirst: TdxTreeListNode; begin Result := FOwner.CreateNode; Result.FParent := self; if FList = nil then begin FList := TList.Create; FList.Add(Result); end else FList.Insert(0, Result); HasChildren := True; FOwner.AddNode(Result); end; procedure TdxTreeListNode.AddNodesToList(List: TList); var I: Integer; begin if FList <> nil then begin I := List.Count; List.Count := List.Count + Self.Count; System.Move(FList.List^[0], List.List^[I], (Self.Count) * SizeOf(Pointer)); end; end; function TdxTreeListNode.CanMove(Destination: TdxTreeListNode; Mode: TdxTreeListNodeAttachMode): Boolean; begin if (Destination = nil) or ((Destination = Self) and (Mode in [natlAddChild, natlAddChildFirst, natlInsert])) or Destination.HasAsParent(Self) then Result := False else Result := True; end; procedure TdxTreeListNode.Collapse(Recurse: Boolean); var I: Integer; Flag: Boolean; begin if not HasChildren then Exit; Flag := FOwner.LockUpdate = 0; if Flag then FOwner.BeginUpdate; try Expanded := False; if Recurse then for I := 0 to Count - 1 do Items[I].Collapse(Recurse); finally if Flag then FOwner.EndUpdate; end; end; procedure TdxTreeListNode.DeleteChildren; var I: Integer; L: TList; begin if (FOwner = nil) or FOwner.FClearNodes then begin if FList <> nil then begin L := FList; FList := nil; try for I := 0 to L.Count - 1 do TdxTreeListNode(L[I]).Free; finally L.Free; end; end; end else while Count > 0 do Items[0].Free; end; procedure TdxTreeListNode.Expand(Recurse: Boolean); var I: Integer; Flag: Boolean; begin if not HasChildren then Exit; Flag := FOwner.LockUpdate = 0; if Flag then FOwner.BeginUpdate; try Expanded := True; if Recurse then for I := 0 to Count - 1 do Items[I].Expand(Recurse); finally if Flag then FOwner.EndUpdate; end; end; function TdxTreeListNode.GetFirstChild: TdxTreeListNode; begin Result := Items[0]; end; function TdxTreeListNode.GetLastChild: TdxTreeListNode; var Node: TdxTreeListNode; begin Result := GetFirstChild; if Result <> nil then begin Node := Result; repeat Result := Node; Node := Result.GetNextSibling; until Node = nil; end; end; function TdxTreeListNode.GetNext: TdxTreeListNode; var Node: TdxTreeListNode; begin Result := GetFirstChild; if Result = nil then begin Result := GetNextSibling; if (Result = nil) and (Parent <> nil) then begin Result := Parent; repeat Node := Result.GetNextSibling; Result := Result.Parent; until (Node <> nil) or (Result = nil); Result := Node; end; end; end; function TdxTreeListNode.GetNextNode: TdxTreeListNode; begin Result := FOwner.GetNextVisible(Self); end; function TdxTreeListNode.GetNextSibling: TdxTreeListNode; var I: Integer; begin Result := nil; I := Index; if Parent = nil then if I < FOwner.Count then Result := FOwner.Items[I + 1] else else if I < Parent.Count then Result := Parent.Items[I + 1]; end; function TdxTreeListNode.GetPrev: TdxTreeListNode; var Node: TdxTreeListNode; begin Result := GetPrevSibling; if Result <> nil then begin Node := Result; repeat Result := Node; Node := Result.GetLastChild; until Node = nil; end else Result := Parent; end; function TdxTreeListNode.GetPrevSibling: TdxTreeListNode; var I: Integer; begin Result := nil; I := Index; if (I > 0) then if Parent = nil then Result := FOwner.Items[I - 1] else Result := Parent.Items[I - 1]; end; function TdxTreeListNode.GetPriorNode: TdxTreeListNode; function GetPrior(ANode: TdxTreeListNode): TdxTreeListNode; begin if not ANode.Expanded or (ANode.Count = 0) then Result := ANode else Result := GetPrior(ANode[ANode.Count-1]); end; var i: Integer; begin with FOwner do if IsSmartNavigation then begin i := FindListNode(Self); Result := nil; if i <> -1 then begin i := Integer(FListIndexes[i]); Dec(i); if i >= 0 then Result := TdxTreeListNode(FListRealNodes[i]); end; Exit; end; I := Index; if I > 0 then begin if Parent <> nil then Result := GetPrior(Parent.Items[I - 1]) else Result := GetPrior(FOwner.Items[I - 1]); end else Result := Parent; end; function TdxTreeListNode.GetPriorParentNode: TdxTreeListNode; 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 TdxTreeListNode.HasAsParent(Value: TdxTreeListNode): Boolean; var ANode: TdxTreeListNode; 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 TdxTreeListNode.IndexOf(Value: TdxTreeListNode): Integer; begin Result := -1; if Count > 0 then Result := FList.IndexOf(Value); end; function TdxTreeListNode.InsertChild(BeforeNode: TdxTreeListNode) : TdxTreeListNode; 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; HasChildren := True; FOwner.AddNode(Result); end; procedure TdxTreeListNode.MakeVisible; begin FOwner.MakeNodeVisible(self); end; procedure TdxTreeListNode.MoveTo(Destination: TdxTreeListNode; Mode: TdxTreeListNodeAttachMode); begin // Check Destination if not CanMove(Destination, Mode) then Exit; FOwner.BeginUpdate; try InternalMove(Destination, Mode); FOwner.FFocused := Self; FOwner.MakeListNodes; MakeVisible; finally FOwner.EndUpdate; end; end; // protected TdxTreeListNode procedure TdxTreeListNode.InternalMove(Destination: TdxTreeListNode; Mode: TdxTreeListNodeAttachMode); procedure CheckList(Node: TdxTreeListNode); begin if Node.FList = nil then Node.FList := TList.Create; end; begin InternalRemove; // InternalAdd if (Destination.Parent = nil) or (Mode in [natlAddChild, natlAddChildFirst]) then begin case Mode of natlAdd: FOwner.FNodeList.Add(Self); natlAddFirst: FOwner.FNodeList.Insert(0, Self); natlInsert: FOwner.FNodeList.Insert(Destination.Index, Self); else {Mode in [natlAddChild, natlAddChildFirst]} begin CheckList(Destination); if Mode = natlAddChild then Destination.FList.Add(Self) else Destination.FList.Insert(0, Self); end; end; {case} if (Mode in [natlAddChild, natlAddChildFirst]) then begin FParent := Destination; Parent.FHasChildren := True; end else FParent := nil; end else begin {Parent <> Nil} CheckList(Destination.Parent); case Mode of natlAdd: Destination.Parent.FList.Add(Self); natlAddFirst: Destination.Parent.FList.Insert(0, Self); natlInsert: Destination.Parent.FList.Insert(Destination.Index, Self); end; FParent := Destination.Parent; end; end; procedure TdxTreeListNode.InternalMoveAsChild(Destination: TdxTreeListNode; AIndex: Integer); begin System.Move(FOwner.FNodeList.List^[AIndex+1], FOwner.FNodeList.List^[AIndex], (FOwner.FNodeList.Count - AIndex - 1) * SizeOf(Pointer)); FOwner.FNodeList.Count := FOwner.FNodeList.Count - 1; if Destination.FList = nil then Destination.FList := TList.Create; Destination.FList.Add(Self); FParent := Destination; Parent.FHasChildren := True; end; procedure TdxTreeListNode.InternalMoveToRoot; begin FOwner.FNodeList.Add(Self); end; procedure TdxTreeListNode.InternalRemove; begin 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.HasChildren := FOwner.CheckHasChildren(Parent); Parent.FExpanded := False; end; end; FParent := nil; end; procedure TdxTreeListNode.MoveChildrenToRoot; var i: Integer; begin // move all detail nodes (not has children) to root for i := 0 to FList.Count - 1 do begin FOwner.FNodeList.Add(Items[i]); Items[i].FParent := nil; end; // Clear FList FList.Free; FList := nil; HasChildren := FOwner.CheckHasChildren(Self); FExpanded := False; FOwner.FFocused := Self; end; // private TdxTreeListNode function TdxTreeListNode.GetAbsoluteIndex: Integer; begin Result := FOwner.GetAbsoluteIndex(Self); end; function TdxTreeListNode.GetCount: Integer; begin if FList = nil then Result := 0 else Result := FList.Count; end; function TdxTreeListNode.GetCountValues: Integer; begin Result := FOwner.GetHeaderAbsoluteCount; end; function TdxTreeListNode.GetFocused: Boolean; begin Result := FOwner.FocusedNode = Self; end; function TdxTreeListNode.GetImageIndex: Integer; begin Result := FOwner.GetNodeImageIndex(Self); end; function TdxTreeListNode.GetIndex: Integer; begin if Parent <> nil then Result := Parent.IndexOf(Self) else Result := FOwner.IndexOf(Self); end; function TdxTreeListNode.GetIsLast: Boolean; begin if Parent <> nil then Result := Self = (Parent.Items[Parent.Count-1]) else Result := Self = FOwner.Items[FOwner.Count-1]; end; function TdxTreeListNode.GetIsNodeVisible: Boolean; begin Result := FOwner.IsNodeVisible(Self); end; function TdxTreeListNode.GetItem(Index: Integer): TdxTreeListNode; begin Result := nil; if (Index > -1) and (Index < Count) then Result := FList.List^[Index]; end; function TdxTreeListNode.GetLevel: Integer; var ANode: TdxTreeListNode; begin Result := 0; ANode := Parent; while ANode <> nil do begin Inc(Result); ANode := ANode.Parent; end; end; function TdxTreeListNode.GetSelected: Boolean; begin if FOwner.IsMultiSelect then Result := FOwner.IsNodeSelected(Self) else Result := Focused; end; function TdxTreeListNode.GetSelectedIndex: Integer; begin Result := FOwner.GetNodeSelectedIndex(Self); end; function TdxTreeListNode.GetStateIndex: Integer; begin Result := FOwner.GetNodeStateIndex(Self); end; function TdxTreeListNode.GetString(Column: Integer): string; begin Result := FOwner.GetNodeString(Self, Column); end; function TdxTreeListNode.GetValue(Column: Integer): Variant; begin Result := FOwner.GetNodeValue(Self, Column); end; procedure TdxTreeListNode.SetData(Value : Pointer); begin if FOwner.CanSetData then FData := Value; end; procedure TdxTreeListNode.SetExpanded(Value: Boolean); var Allow: Boolean; begin if not HasChildren then Exit; if Value <> Expanded then begin {DoBeforeExpand <- Loading Nodes } Allow := True; if Value then FOwner.DoBeforeExpand(Self, Allow) else FOwner.DoBeforeCollapse(Self, Allow); if not Allow then Exit; // check TopVisibleNode if not Value and (FOwner.FTopVisibleNode <> nil) and FOwner.FTopVisibleNode.HasAsParent(Self) then FOwner.SetTopVisibleNode(Self); // check FocusedNode if not Value and (FOwner.FocusedNode <> nil) and FOwner.FocusedNode.HasAsParent(Self) then //Focused := True; if not FOwner.MakeFocused(Self) then Exit; // DB FExpanded := Value; {**} if (FOwner.FLockUpdate = 0) and not (csDestroying in FOwner.ComponentState) then FOwner.MakeListNodes; {**} FOwner.UpdateNode(Self, True {Below}); {DoAfterExpand} if Value then FOwner.DoAfterExpand(Self) else FOwner.DoAfterCollapse(Self); end; end; function TCustomdxTreeList.MakeFocused(Node: TdxTreeListNode): Boolean; begin Node.Focused := True; Result := True; end; procedure TdxTreeListNode.SetFocused(Value: Boolean); begin if Focused = Value then Exit; if Value then FOwner.SetFocusedNode(Self, FOwner.FocusedColumn, True) else FOwner.SetFocusedNode(nil, FOwner.FocusedColumn, True); end; procedure TdxTreeListNode.SetHasChildren(Value: Boolean); begin if FHasChildren = Value then Exit; FHasChildren := Value or (Count > 0); FOwner.UpdateNode(Self, False{no Below}); end; procedure TdxTreeListNode.SetImageIndex(Value: Integer); begin FOwner.SetNodeImageIndex(Self, Value); end; procedure TdxTreeListNode.SetSelected(Value: Boolean); begin // if Selected = Value then Exit; // if FOwner.CanNodeSelected(Self) then FOwner.NodeSelected(Self, Value); end; procedure TdxTreeListNode.SetSelectedIndex(Value: Integer); begin FOwner.SetNodeSelectedIndex(Self, Value); end; procedure TdxTreeListNode.SetStateIndex(Value: Integer); begin FOwner.SetNodeStateIndex(Self, Value); end; procedure TdxTreeListNode.SetString(Column: Integer; const Value: string); begin FOwner.SetNodeString(Self, Column, Value); end; procedure TdxTreeListNode.SetValue(Column: Integer; const Value: Variant); begin FOwner.SetNodeValue(Self, Column, Value); end; {TCustomdxTreeList} constructor TCustomdxTreeList.Create(AOwner: TComponent); const ListStyle = [csCaptureMouse, csOpaque, csDoubleClicks, csDisplayDragImage]; begin inherited Create(AOwner); FNodeList := TList.Create; {**} FListIndexes := TList.Create; FListNodes := TList.Create; FListRealNodes := TList.Create; {**} // Control Style if NewStyleControls then ControlStyle := ListStyle else ControlStyle := ListStyle + [csFramed]; // Initial installation Width := 250; Height := 150; Color := clWindow; ParentColor := False; TabStop := True; // Colors FArrowsColor := dxclArrows; FBandColor := clBtnFace; FGridColor := dxclTreeLineShadowColor; FGridLineColor := clNone; FGroupColor := clBtnFace; FGroupTextColor := clNone; FHeaderColor := clBtnFace; FHighlightColor := clHighlight; FHighlightTextColor := clHighlightText; FTreeLineColor := clGrayText{clBtnShadow}; FTreeLineStyle := tlDot; FHideSelectionColor := clBtnFace; FHideSelectionTextColor := clBtnText; FFixedBandLineColor := clWindowFrame; FFooterColor := cl3DLight; FFooterTextColor := clWindowText; // Fonts FBandFont := TFont.Create; FBandFont.OnChange := HeaderFontChanged; FHeaderFont := TFont.Create; FHeaderFont.OnChange := HeaderFontChanged; FPreviewFont := TFont.Create; FPreviewFont.Color := clBlue; FPreviewFont.OnChange := HeaderFontChanged; FSaveFont := TFont.Create; // Indexes and positions FCustomizingPos := Point(-1000, -1000); FCustomizingLastBandIndex := -1; FCustomizingLastHeaderIndex := -1; FDownBandIndex := -1; FDownColumnIndex := -1; FFocusedColumn := -1; FFocusedAbsoluteIndex := -1; FOptions := [aoEditing, aoColumnSizing, aoColumnMoving, aoRowSelect, aoTabThrough]; FOptionsEx := [aoUseBitmap, aoBandHeaderWidth, aoAutoCalcPreviewLines, aoBandSizing, aoBandMoving, aoDragExpand, aoDragScroll]; FState := tsNormal; // Size FDescTextHeight := 11; FHeaderHeight := 18; FIndentDesc := 20; FRowCount := 1; FRowHeight := 18; FRowSeparatorLineWidth := 1; FTextHeight := 11; FVisibleRowCount := 1; FPreviewLines := 2; FMaxRowLineCount := -1; FCustomizingRowCount := dxCustomizingRowCount; FFixedBandLineWidth := dxGridFixedBandLineWidth; FDragAbsoluteHeaderIndex := -1; // Style FAutoExpandOnSearch := True; FAutoSearchColor := clNone; FAutoSearchTextColor := clNone; FBorderStyle := bsSingle; FDblClkExpanding := True; FHideFocusRect := True; FHideSelection := True; FShowButtons := True; FShowHeaders := True; FShowLines := True; FShowPreviewGrid := True; FShowRoot := True; FWaitForExpandNodeTime := dxWaitForExpandNodeTime; FScrollBars := ssBoth; FShowDragImage := True; // Links FImageChangeLink := TChangeLink.Create; FImageChangeLink.OnChange := ImageListChange; FStateChangeLink := TChangeLink.Create; FStateChangeLink.OnChange := ImageListChange; // draw buttons LoadButtonFaces; FCellViewData := TdxTreeListCellViewData.Create; // Filter FHiddenList := TList.Create; end; destructor TCustomdxTreeList.Destroy; begin BeforeDestroy; {**} ClearListNodes; FListIndexes.Free; FListIndexes := nil; FListNodes.Free; FListNodes := nil; FListRealNodes.Free; FListRealNodes := nil; {**} if FCustomizingForm <> nil then FCustomizingForm.Free; ClearNodes; FHiddenList.Free; FHiddenList := nil; FPreviewFont.Free; FPreviewFont := nil; FNodeList.Free; FImageChangeLink.Free; FStateChangeLink.Free; FHeaderFont.Free; FHeaderFont := nil; FBandFont.Free; FBandFont := nil; FSaveFont.Free; FSaveFont := nil; FCellViewData.Free; inherited Destroy; end; function TCustomdxTreeList.Add: TdxTreeListNode; begin Result := CreateNode; FNodeList.Add(Result); AddNode(Result); end; function TCustomdxTreeList.AddFirst : TdxTreeListNode; begin Result := CreateNode; FNodeList.Insert(0, Result); AddNode(Result); end; procedure TCustomdxTreeList.AdjustColumnsWidth; begin if IsAutoWidth then Exit; BeginUpdate; try Options := Options + [aoAutoWidth]; try MakeBandHeaderList(True); StabilizeAutoWidth; finally Options := Options - [aoAutoWidth]; end; finally EndUpdate; end; end; procedure TCustomdxTreeList.BeginUpdate; begin Inc(FLockUpdate); //CancelEditor; if FState = tsNodeDown then FlagEditor := True; FInplaceColumn := -1; FInplaceNode := Nil; SetState(tsNormal); HideEdit(False); {**} // if FLockUpdate = 1 then ClearListNodes; {**} BeginSelection; end; procedure TCustomdxTreeList.CalcDrawInfo(var DrawInfo: TdxGridDrawInfo); function IntersectCoords(Point1, Point2, Range1, Range2: Integer): Boolean; begin Result := ((Point1 >= Range1) and (Point1 <= Range2)) or ((Point2 >= Range1) and (Point2 <= Range2)) or ((Point1 < Range1) and (Point2 > Range2)); end; var i, j, k, c, rCount, rMaxCount, iStart, iEnd, FixedLeft, FixedRight, BandLeftCoord, BandRightCoord, BandCoord, BandWidth, BandTotalWidth: Integer; Y, L, W, H, HeaderLeftCoord, HeaderTotalWidth: Integer; R: TRect; CurNode: TdxTreeListNode; cCount: Integer; AIndex: Integer; HeaderTotalMinWidth, RealBandWidth, ScaledWidth, MinW, CalcWidth: Integer; FlagScaled: Boolean; // new calc AHWList, AFixedHWList: TList; AVisibleWidth, AWidth, AScalableWidth: Integer; ARecalcNeeded, ACalculation: Boolean; begin CalcRectInfo(DrawInfo); with DrawInfo do begin // bands info BandCount := GetBandCount; GetMem(BandsInfo, BandCount * SizeOf(TdxGridBandDrawInfo)); FixedLeft := GetBandFixedLeft; FixedRight := GetBandFixedRight; iStart := 0; iEnd := BandCount - 1; BandCount := 0; BandTotalWidth := GetBandTotalWidth; FixedBandLeftIndex := -1; FixedBandRightIndex:= -1; FixedBandPrevRightIndex := -1; with BandRect do begin BandLeftCoord := Left; BandRightCoord := Right; if FixedLeft <> -1 then begin BandWidth := GetBandWidth(iStart) + GetIndentWidth; // Indent Inc(BandLeftCoord, BandWidth); FixedBandLeftRect := Rect(Left, Top, Left + BandWidth, CellsRect.Top); if FNewItemRowHeight > 0 then Dec(FixedBandLeftRect.Bottom, FNewItemRowSeparatorHeight); BandsInfo^[BandCount].Index := iStart; BandsInfo^[BandCount].BandRect := Rect(Left, Top, FixedBandLeftRect.Right - FFixedBandLineWidth, Bottom); BandsInfo^[BandCount].BandClipRect := BandsInfo^[BandCount].BandRect; FixedBandLeftIndex := iStart; Inc(iStart); Inc(BandCount); end; if (Right - Left){BandRect} > BandTotalWidth then // empty rect begin Right := Left + BandTotalWidth; HeaderRect.Right := Right; // correct HeaderRect EmptyRectRight := Rect(Right, Top, CRect.Right, CellsRect.Bottom); if not IsRectEmpty(NewItemRowRect) then NewItemRowRect.Right := EmptyRectRight.Left; end; if FixedRight <> -1 then begin BandWidth := GetBandWidth(FixedRight); FixedBandRightRect := Rect(Right - BandWidth, Top, Right, CellsRect.Top); if FNewItemRowHeight > 0 then Dec(FixedBandRightRect.Bottom, FNewItemRowSeparatorHeight); BandCoord := Max(FixedBandLeftRect.Right, IndicatorRect.Right); if FixedBandRightRect.Left < BandCoord then begin FixedBandRightRect.Left := BandCoord; FixedBandRightRect.Right := FixedBandRightRect.Left + BandWidth; end; FixedBandRightIndex := iEnd; Dec(iEnd); BandRightCoord := FixedBandRightRect.Left; end; BandCoord := - LeftCoord; for i := iStart to iEnd do begin BandWidth := GetBandWidth(i); if i = 0 then Inc(BandWidth, GetIndentWidth); // Indent if IntersectCoords(BandCoord, BandCoord + BandWidth, 0, BandRightCoord - BandLeftCoord) then begin BandsInfo^[BandCount].Index := i; BandsInfo^[BandCount].BandRect := Rect(BandLeftCoord + BandCoord, Top, BandLeftCoord + BandCoord + BandWidth, Bottom); BandsInfo^[BandCount].BandClipRect := BandsInfo^[BandCount].BandRect; if BandsInfo^[BandCount].BandClipRect.Left < BandLeftCoord then BandsInfo^[BandCount].BandClipRect.Left := BandLeftCoord; if BandsInfo^[BandCount].BandClipRect.Right > BandRightCoord then BandsInfo^[BandCount].BandClipRect.Right := BandRightCoord; Inc(BandCount); end; Inc(BandCoord, BandWidth); if FixedBandRightIndex <> -1 then FixedBandPrevRightIndex := i; if BandCoord > BandRightCoord then Break; end; if FixedRight <> -1 then begin BandsInfo^[BandCount].Index := FixedRight; BandsInfo^[BandCount].BandRect := Rect(FixedBandRightRect.Left + FFixedBandLineWidth, Top, FixedBandRightRect.Right, Bottom); with BandsInfo^[BandCount].BandRect do BandsInfo^[BandCount].BandClipRect := Rect(Left, Top, BandRect.Right, Bottom); Inc(BandCount); end; end; // headers info HeaderCount := 0; EmptyRectCount := 0; for i := 0 to BandCount - 1 do begin k := BandsInfo^[i].Index; rCount := GetHeaderRowCount(k); if rCount > 0 then begin for j := 0 to rCount - 1 do Inc(HeaderCount, GetHeaderColCount(k, j)) end else Inc(EmptyRectCount); end; HeadersInfo := AllocMem(HeaderCount * SizeOf(TdxGridHeaderDrawInfo)); HeaderCount := 0; EmptyRectsInfo := AllocMem(EmptyRectCount * SizeOf(TdxGridEmptyRectDrawInfo)); EmptyRectCount := 0; rMaxCount := GetHeaderMaxRowCount; for i := 0 to BandCount - 1 do begin k := BandsInfo^[i].Index; rCount := GetHeaderRowCount(k); if rCount > 0 then begin for j := 0 to rCount - 1 do begin // * AHWList := TList.Create; AFixedHWList := TList.Create; try BandWidth := BandsInfo^[i].BandRect.Right - BandsInfo^[i].BandRect.Left; RealBandWidth := BandWidth - Byte(k = 0)*GetIndentWidth; HeaderTotalWidth := GetHeaderTotalWidth(k, j); HeaderTotalMinWidth := GetHeaderTotalMinWidth(k, j); CCount := GetHeaderColCount(k, j); // calc widths AVisibleWidth := RealBandWidth; AHWList.Count := cCount; AFixedHWList.Count := cCount; for c := 0 to cCount - 1 do begin AIndex := GetHeaderAbsoluteIndex(k, j, c); AWidth := GetHeaderWidth(AIndex); AHWList[c] := Pointer(AWidth); AFixedHWList[c] := Pointer(not CanHeaderSizing(AIndex)); if Boolean(AFixedHWList[c]) then Dec(AVisibleWidth, AWidth); end; // scale widths if AVisibleWidth < 0 then AVisibleWidth := 0; ACalculation := True; repeat ARecalcNeeded := False; AScalableWidth := 0; for c := 0 to cCount - 1 do if not Boolean(AFixedHWList[c]) then Inc(AScalableWidth, Integer(AHWList[c])); for c := 0 to cCount - 1 do begin AIndex := GetHeaderAbsoluteIndex(k, j, c); if not Boolean(AFixedHWList[c]) then begin if AScalableWidth > 0 then AWidth := Integer(AHWList[c]) * AVisibleWidth div AScalableWidth else AWidth := 0; if ACalculation then begin if AWidth < GetHeaderMinWidth(AIndex) then begin AHWList[c] := Pointer(GetHeaderMinWidth(AIndex)); AFixedHWList[c] := Pointer(True); Dec(AVisibleWidth, Integer(AHWList[c])); ARecalcNeeded := True; Break; end; end else AHWList[c] := Pointer(AWidth); end; end; if not ACalculation then Break; if not ARecalcNeeded then ACalculation := False; until False; // fill array HeaderLeftCoord := 0; for c := 0 to cCount - 1 do begin AIndex := GetHeaderAbsoluteIndex(k, j, c); if c <> (cCount - 1) {not last} then W := Integer(AHWList[c]) else W := BandWidth - HeaderLeftCoord; if (k = 0) and (c = 0) and (cCount > 1) then Inc(W, GetIndentWidth); // Indent L := GetHeaderLineCount(k, j, c); H := FHeaderRowHeight * L; with BandsInfo^[i].BandRect do R := Rect(Left + HeaderLeftCoord, Bottom + FHeaderRowHeight*j, Left + HeaderLeftCoord + W, Bottom + FHeaderRowHeight*j + H); Inc(HeaderLeftCoord, W); with BandsInfo^[i] do if IntersectCoords(R.Left, R.Right, BandClipRect.Left, BandClipRect.Right) then with HeadersInfo^[HeaderCount] do begin BandIndex := k; RowIndex := j; ColIndex := c; AbsoluteIndex := AIndex; //GetHeaderAbsoluteIndex(BandIndex, RowIndex, ColIndex); LineCount := L; MultiLine := IsCellMultiLine(AIndex); FirstColumn := c = 0; LastColumn := c = (cCount - 1); // if invert select LeftEdgeColumn := (c = 0) and (k = 0); RightEdgeColumn := (c = (cCount - 1)) and (k = iEnd); HeaderRect := R; HeaderClipRect := HeaderRect; if HeaderClipRect.Right > BandClipRect.Right then HeaderClipRect.Right := BandClipRect.Right; if HeaderClipRect.Left < BandClipRect.Left then HeaderClipRect.Left := BandClipRect.Left; Inc(HeaderCount); // exist empty rect ? if (j = (rCount - 1)) and ((j + L) < rMaxCount) then // last row begin with BandsInfo^[i].BandRect do HeaderEmptyRect := Rect(HeaderClipRect.Left, Bottom + FHeaderRowHeight * (j + L), HeaderClipRect.Right, Bottom + FHeaderRowHeight * rMaxCount); end; end; end; // end fill array finally AFixedHWList.Free; AHWList.Free; end; // * end; end else begin W := BandsInfo^[i].BandRect.Right - BandsInfo^[i].BandRect.Left; with BandsInfo^[i].BandRect do R := Rect(Left, Bottom, Left + W, Bottom + FHeaderRowHeight * rMaxCount); with BandsInfo^[i] do if IntersectCoords(R.Left, R.Right, BandClipRect.Left, BandClipRect.Right) then with EmptyRectsInfo^[EmptyRectCount] do begin BandIndex := k; EmptyRect := R; if EmptyRect.Right > BandClipRect.Right then EmptyRect.Right := BandClipRect.Right; if EmptyRect.Left < BandClipRect.Left then EmptyRect.Left := BandClipRect.Left; if (BandsInfo^[i].BandRect.Right > BandsInfo^[i].BandClipRect.Right) then ClippingFlag := True; Inc(EmptyRectCount); end; end; end; // cells info RowCount := (CellsRect.Bottom - CellsRect.Top) div FRowHeight + 1; RowsInfo := AllocMem(RowCount * SizeOf(TdxGridRowDrawInfo)); RowCount := 0; CurNode := TopVisibleNode; Y := CellsRect.Top; while (CurNode <> nil) and (Y < CellsRect.Bottom) do begin with RowsInfo^[RowCount] do begin Node := CurNode; IsGroup := IsRowGroup(CurNode); IsSelected := CurNode.Selected; RowHeight := GetRowHeight(CurNode, FRowHeight, False{ReCalc}); RowFooterCount := GetRowFooterCount(CurNode); RowFooterHeight := RowFooterCount * FFooterRowNodeHeight; IndicatorKind := GetRowIndicatorKind(CurNode, IsSelected); if IsShowPreview then PreviewLineCount := GetRowPreviewLineCount(CurNode); if IsCalcRowAutoHeight then begin H := FRowHeight; RowLineCount := GetRowLineCount(CurNode, H) end else RowLineCount := -1; CurNode := GetNextVisible(CurNode); Inc(Y, RowHeight); end; Inc(RowCount); end; // edges EdgeX := CellsRect.Left + GetBandTotalWidth - 1; if IsRectEmptyEx(FixedBandLeftRect) then Dec(EdgeX, LeftCoord); if not IsRectEmptyEx(FixedBandRightRect) and (EdgeX > CellsRect.Right - 1) then EdgeX := CellsRect.Right - 1; EdgeY := -1; if Y < CellsRect.Bottom then // Y contains last coord of cells begin EdgeY := Y - 1; // empty bottom rect EmptyRectBottom := Rect(CRect.Left, EdgeY + 1, EdgeX + 1, CellsRect.Bottom); // correct Indicator IndicatorRect.Bottom := EmptyRectBottom.Top; end; if GetBandCount > 0 then IndentLimit := GetBandWidth(0) + GetIndentWidth else IndentLimit := 0; if not IsRectEmptyEx(FixedBandLeftRect) and ((CellsRect.Left + IndentLimit) > (FixedBandLeftRect.Right - FFixedBandLineWidth)) then IndentLimit := FixedBandLeftRect.Right - FFixedBandLineWidth - CellsRect.Left; if IsRectEmptyEx(FixedBandLeftRect) then W := LeftCoord else W := 0; if not IsRectEmptyEx(FixedBandRightRect) and ((CellsRect.Left + IndentLimit - W) > FixedBandRightRect.Left) then IndentLimit := FixedBandRightRect.Left - CellsRect.Left + W; if FShowGrid then RowSeparatorLineWidth := GetRowSeparatorLineWidth; // check empty rect if BandRect.Top = BandRect.Bottom then SetRectEmpty(BandRect); if BandButtonRect.Top = BandButtonRect.Bottom then SetRectEmpty(BandButtonRect); if HeaderRect.Top = HeaderRect.Bottom then SetRectEmpty(HeaderRect); if HeaderButtonRect.Top = HeaderButtonRect.Bottom then SetRectEmpty(HeaderButtonRect); end; end; procedure TCustomdxTreeList.CalcRectInfo(var DrawInfo: TdxGridDrawInfo); begin FillChar(DrawInfo, SizeOf(DrawInfo), 0); with DrawInfo do begin (* if (Parent = nil) {not HandleAllocated} then CRect := Rect(0, 0, 0, 0) else*) CRect := Self.ClientRect; // GroupPanel if FGroupPanelHeight > 0 then with CRect do GroupPanelRect := Rect(Left, Top, Right, Top + FGroupPanelHeight); // Band with CRect do BandRect := Rect(Left + FIndicatorWidth, Top + FGroupPanelHeight, Right, Top + FGroupPanelHeight + FBandHeight); if FIndicatorWidth > 0 then // band button with BandRect do BandButtonRect := Rect(Left - FIndicatorWidth, Top, Left, Bottom); // Header with CRect do HeaderRect := Rect(Left + FIndicatorWidth, Top + FGroupPanelHeight + FBandHeight, Right, Top + FGroupPanelHeight + FBandHeight + FHeaderHeight); if FIndicatorWidth > 0 then // header button with HeaderRect do HeaderButtonRect := Rect(Left - FIndicatorWidth, Top, Left, Bottom); // New Item Row Height if (FNewItemRowHeight > 0) then with CRect do NewItemRowRect := Rect(Left, Top + FGroupPanelHeight + FBandHeight + FHeaderHeight, Right, Top + FGroupPanelHeight + FBandHeight + FHeaderHeight + FNewItemRowHeight); // Cells with CRect do CellsRect := Rect(Left + FIndicatorWidth, Top + FGroupPanelHeight + FBandHeight + FHeaderHeight + FNewItemRowHeight, Right, Bottom - FFooterHeight - FStatusHeight); with CellsRect do if Top > Bottom then Bottom := Top; // Indicator with CellsRect do IndicatorRect := Rect(CRect.Left, Top, Left, Bottom); // Footer FooterRect := Rect(CRect.Left, CellsRect.Bottom, CRect.Right, CRect.Bottom); FooterRect.Bottom := FooterRect.Top + FFooterHeight; // Filter (Status) StatusRect := Rect(FooterRect.Left, FooterRect.Bottom, FooterRect.Right, FooterRect.Bottom); StatusRect.Bottom := StatusRect.Top + FStatusHeight; end; end; procedure TCustomdxTreeList.CancelEditor; begin FInplaceColumn := -1; FInplaceNode := Nil; if (csDestroying in ComponentState) {or (FLockUpdate <> 0)} then Exit; CloseEditor; end; procedure TCustomdxTreeList.CancelUpdate; begin Dec(FLockUpdate); EndSelection; end; function TCustomdxTreeList.CellRect(ANode: TdxTreeListNode; AColumn: Integer): TRect; var DrawInfo: TdxGridDrawInfo; I, K, X, Ind, Ind1, CorrectY, SizeGrid: Integer; R: TRect; begin Result := Rect(-1, -1, -1, -1); K := GetFocusedAbsoluteIndex(AColumn); CalcDrawInfo(DrawInfo); try R := GetRectNode(ANode); with DrawInfo do for i := 0 to HeaderCount - 1 do begin if HeadersInfo^[i].AbsoluteIndex = K then with HeadersInfo^[i] do begin // calc indent GetNodeIndent(ANode, Ind, Ind1); X := HeaderRect.Left; if IsRectEmptyEx(FixedBandLeftRect) then Inc(X, LeftCoord); if (BandIndex = 0) and (X - CellsRect.Left < Ind) then Ind := Ind - (X - CellsRect.Left) else Ind := 0; CorrectY := Byte(not FShowGrid and ANode.HasChildren and not FPaintStandard); if FShowGrid then SizeGrid := 1 else SizeGrid := 0; Result := Rect(HeaderRect.Left + Ind, R.Top + FRowHeight * RowIndex + CorrectY, HeaderRect.Right, R.Top + FRowHeight * RowIndex + LineCount * FRowHeight - SizeGrid * Byte(FShowPreviewGrid) + CorrectY); if IsCalcRowAutoHeight then begin for X := 0 to DrawInfo.RowCount - 1 do if (RowsInfo^[X].Node = ANode) then begin Result.Bottom := Result.Top + RowsInfo^[X].RowHeight - RowSeparatorLineWidth - RowsInfo^[X].RowFooterHeight; Break; end; end; Break; end; end; finally FreeDrawInfo(DrawInfo); end; end; procedure TCustomdxTreeList.ClearNodes; var PrevFlag: Boolean; I: Integer; begin if not (csDestroying in ComponentState) then BeginUpdate; try FClearNodes := True; ClearListNodes; PrevFlag := FClearListNodesFlag; FClearListNodesFlag := True; // FClearNodes := True; try ClearSelection; SetEmptyNodes; for I := 0 to Count - 1 do Items[I].Free; FNodeList.Clear; // Hidden for I := 0 to FHiddenList.Count - 1 do TdxTreeListNode(FHiddenList[I]).Free; FHiddenList.Clear; finally FClearListNodesFlag := PrevFlag; FClearNodes := False; end; finally if not (csDestroying in ComponentState) then EndUpdate; end; end; procedure TCustomdxTreeList.CloseEditor; begin if FState <> tsEditing then Exit; if not (csDestroying in ComponentState) then if InplaceEditor <> Nil then InplaceEditor.ValidateEdit; SetState(tsNormal); HideEdit(True); end; type TCustomizeForm = class(TForm) private FParentForm: TCustomForm; protected procedure CreateParams(var Params: TCreateParams); override; public constructor CreateForm(AOwner: TComponent; AParentForm: TCustomForm); end; constructor TCustomizeForm.CreateForm(AOwner: TComponent; AParentForm: TCustomForm); begin inherited CreateNew(AOwner); FParentForm := AParentForm; end; procedure TCustomizeForm.CreateParams(var Params: TCreateParams); begin inherited CreateParams(Params); if FParentForm <> nil then with Params do begin WndParent := FParentForm.Handle; end; end; procedure TCustomdxTreeList.ColumnsCustomizing; const dXY = 4; dWidth = 28; var AParentForm: {$IFDEF DELPHI3}TCustomForm{$else}TForm{$ENDIF}; APageControl: TPageControl; ATabSheet: TTabSheet; H: Integer; SysMenu: HMENU; FlagSimple: Boolean; R: TRect; begin if (FCustomizingForm <> nil) then FCustomizingForm.Close; if not ShowBands and not ShowHeader or ((GetAbsoluteBandCount = 0) and (GetHeaderAbsoluteCount = 0)) then Exit; FlagSimple := SimpleCustomizeBox or ((GetAbsoluteBandCount = 1) and not ShowBands); // FCustomizingForm := TForm.Create(nil); FCustomizingForm := TCustomizeForm.CreateForm(nil, GetParentForm(Self)); with FCustomizingForm do begin //ParentWindow := GetDesktopWindow; // Windows.GetParent(GetParentForm(Self).Handle); Caption := sdxGrColumns; BorderStyle := bsToolWindow; BorderIcons := [biSystemMenu]; FormStyle := fsStayOnTop; Font.Assign(Self.Font); H := FTextHeight + 3{indent} + 2 + Byte(not FFlat); ClientWidth := dWidth * Canvas.TextWidth('0'); ClientHeight := FCustomizingRowCount * H + dXY; Color := clBtnFace; AParentForm := GetParentForm(Self); OnClose := CloseCustomizingForm; OnActivate := ActivateCustomizingForm; // Clear SysMenu SysMenu := GetSystemMenu(Handle, False); DeleteMenu(SysMenu, 7, MF_BYPOSITION); DeleteMenu(SysMenu, 5, MF_BYPOSITION); DeleteMenu(SysMenu, SC_MAXIMIZE, MF_BYCOMMAND); DeleteMenu(SysMenu, SC_MINIMIZE, MF_BYCOMMAND); DeleteMenu(SysMenu, SC_SIZE, MF_BYCOMMAND); DeleteMenu(SysMenu, SC_RESTORE, MF_BYCOMMAND); end; if FlagSimple then begin FCustomizingHeaderListBox := TdxHeadersListBox.Create(FCustomizingForm); with FCustomizingHeaderListBox do begin Parent := FCustomizingForm; Align := alClient; TreeList := Self; Sorted := True; Color := FCustomizingForm.Color{HeaderColor}; Flat := Boolean(Self.LookAndFeel <> lfStandard); // correct size FCustomizingForm.ClientWidth := FCustomizingForm.ClientWidth + dWidth * Canvas.TextWidth('0') - FCustomizingHeaderListBox.ClientWidth; FCustomizingForm.ClientHeight := FCustomizingForm.ClientHeight + FCustomizingRowCount * H + - FCustomizingHeaderListBox.ClientHeight; end; end else begin // Page Control APageControl := TPageControl.Create(FCustomizingForm); with APageControl do begin Parent := FCustomizingForm; Align := alClient; HotTrack := True; Name := 'PageControl'; // Bands ATabSheet := TTabSheet.Create(APageControl); with ATabSheet do begin Align := alClient; Caption := sdxGrBandsCaption; Name := 'tsBands'; PageControl := APageControl; FCustomizingBandListBox := TdxBandsListBox.Create(ATabSheet); with FCustomizingBandListBox do begin Parent := ATabSheet; Align := alClient; TreeList := Self; Sorted := True; Color := FCustomizingForm.Color{BandColor}; Flat := Boolean(Self.LookAndFeel <> lfStandard); // correct size FCustomizingForm.ClientWidth := FCustomizingForm.ClientWidth + dWidth * Canvas.TextWidth('0') - FCustomizingBandListBox.ClientWidth; FCustomizingForm.ClientHeight := FCustomizingForm.ClientHeight + FCustomizingRowCount * H + - FCustomizingBandListBox.ClientHeight; end; end; // Headers ATabSheet := TTabSheet.Create(APageControl); with ATabSheet do begin Align := alClient; Caption := sdxGrHeadersCaption; Name := 'tsHeaders'; PageControl := APageControl; FCustomizingHeaderListBox := TdxHeadersListBox.Create(ATabSheet); with FCustomizingHeaderListBox do begin Parent := ATabSheet; Align := alClient; TreeList := Self; Sorted := True; Color := FCustomizingForm.Color{HeaderColor}; Flat := Boolean(Self.LookAndFeel <> lfStandard); end; end; end; end; // Calc Position with FCustomizingForm do begin if (FCustomizingPos.X <> -1000) and (FCustomizingPos.Y <> -1000) then begin Left := FCustomizingPos.X; Top := FCustomizingPos.Y; end else begin Windows.GetWindowRect(AParentForm.Handle, R); // Left := R.Left + AParentForm.Width - FCustomizingForm.Width; // Top := R.Top + AParentForm.Height - FCustomizingForm.Height; Left := R.Right - FCustomizingForm.Width; Top := R.Bottom - FCustomizingForm.Height; if Left < 0 then Left := 0; if Top < 0 then Top := 0; end; if (FCustomizingBandListBox <> nil) and (0 <= FCustomizingLastBandIndex) and (FCustomizingLastBandIndex < FCustomizingBandListBox.Items.Count) then FCustomizingBandListBox.ItemIndex := FCustomizingLastBandIndex; if (FCustomizingHeaderListBox <> nil) and (0 <= FCustomizingLastHeaderIndex) and (FCustomizingLastHeaderIndex < FCustomizingHeaderListBox.Items.Count) then FCustomizingHeaderListBox.ItemIndex := FCustomizingLastHeaderIndex; Show; end; end; procedure TCustomdxTreeList.CopyAllToClipboard; var L: TStrings; begin L := TStringList.Create; try SaveAllToStrings(L); Clipboard.AsText := L.Text; finally L.Free; end; end; procedure TCustomdxTreeList.CopySelectedToClipboard; var L : TStrings; begin L := TStringList.Create; try SaveSelectedToStrings(L); Clipboard.AsText := L.Text; finally L.Free; end; end; procedure TCustomdxTreeList.EndColumnsCustomizing; begin if (FCustomizingForm <> nil) then FCustomizingForm.Close; end; procedure TCustomdxTreeList.EndUpdate; begin Dec(FLockUpdate); LayoutChanged; EndSelection; end; procedure TCustomdxTreeList.FreeDrawInfo(var DrawInfo: TdxGridDrawInfo); begin with DrawInfo do begin if RowsInfo <> nil then begin FreeMem(RowsInfo); RowsInfo := nil; end; if EmptyRectsInfo <> nil then begin FreeMem(EmptyRectsInfo); EmptyRectsInfo := nil; end; if HeadersInfo <> nil then begin FreeMem(HeadersInfo); HeadersInfo := nil; end; if BandsInfo <> nil then begin FreeMem(BandsInfo); BandsInfo := nil; end; end; end; procedure TCustomdxTreeList.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 TCustomdxTreeList.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 TCustomdxTreeList.GetEditRect(Node: TdxTreeListNode; Column: Integer): TRect; var AIndex, BIndex, RIndex, CIndex, CCount: Integer; Ind, Ind1: Integer; DrawInfo: TdxGridDrawInfo; begin Result := CellRect(Node, Column); AIndex := GetFocusedAbsoluteIndex(Column); BIndex := GetVisibleBandIndex(GetHeaderBandIndex(AIndex)); RIndex := GetHeaderRowIndex(AIndex); CIndex := GetHeaderColIndex(AIndex); CCount := GetHeaderColCount(BIndex, RIndex); if FShowGrid and FShowPreviewGrid then begin if not ((CIndex = (CCount - 1)) and ((BIndex = GetBandFixedLeft) or ((GetBandFixedRight <> -1) and (BIndex = (GetBandFixedRight - 1))))) then Dec(Result.Right); end else begin if (BIndex = (GetBandCount - 1)) and (CIndex = (CCount - 1)) and (not IsInvertSelect or FShowGrid) then Dec(Result.Right); end; GetNodeIndent(Node, Ind, Ind1); CalcRectInfo(DrawInfo); if (BIndex = 0) and (CIndex = 0) and (Result.Left < (DrawInfo.CellsRect.Left + Ind1)) then Result.Left := DrawInfo.CellsRect.Left + Ind1; if IsNewItemRowActive and (BIndex = 0) and (CIndex = 0) then Dec(Result.Left, Ind1); // in NewItemRow if IsNewItemRowActive then with DrawInfo do begin Result.Top := NewItemRowRect.Top; Result.Bottom := NewItemRowRect.Top + FRowHeight - Byte(FShowGrid and FShowPreviewGrid); end; if IsInvertSelect then begin InflateRect(Result, 0, -1); if (BIndex = 0) and (CIndex = 0) then Inc(Result.Left); if (BIndex = (GetBandCount - 1)) and (CIndex = (CCount - 1)) then Dec(Result.Right); end; end; function TCustomdxTreeList.GetFocusedAbsoluteIndex(FocusedIndex: Integer): Integer; var I, J, FIndex, RIndex, MaxRowCount: Integer; begin Result := -1; FIndex := -1; MaxRowCount := GetHeaderMaxRowCount; for RIndex := 0 to MaxRowCount - 1 do begin for I := 0 to GetBandCount - 1 do begin if RIndex < GetHeaderRowCount(I) then for J := 0 to GetHeaderColCount(I, RIndex) - 1 do begin Inc(FIndex); if FIndex = FocusedIndex then begin Result := GetHeaderAbsoluteIndex(I, RIndex, J); Break; end; end; end; end; end; function TCustomdxTreeList.GetFocusedVisibleIndex(AbsoluteIndex: Integer): Integer; var I, J: Integer; begin Result := 0; for I := 0 to GetVisibleHeaderCount - 1 do begin J := GetFocusedAbsoluteIndex(I); if J = AbsoluteIndex then begin Result := I; Break; end; end; end; function TCustomdxTreeList.GetHitInfo(Pos: TPoint): TdxTreeListHitInfo; var DrawInfo: TdxGridDrawInfo; R, RClip: TRect; I, J, K, Y, Ind, Ind1: Integer; procedure GetNodeIndentInfo(Node: TdxTreeListNode; IsSelected: Boolean; YTop, YBottom: Integer; var IndentRect, ButtonRect, StateImageRect, ImageRect: TRect); procedure CheckRect(var R: TRect); begin {.} if not ShowRoot then OffsetRect(R, - FIndent, 0); with DrawInfo do if R.Left < IndentLimit then begin if R.Right > IndentLimit then R.Right := IndentLimit; end else SetRectEmpty(R); end; var X, I: Integer; begin FillChar(IndentRect, SizeOf(IndentRect), 0); FillChar(ButtonRect, SizeOf(ButtonRect), 0); FillChar(StateImageRect, SizeOf(StateImageRect), 0); FillChar(ImageRect, SizeOf(ImageRect), 0); X := -1; I := Node.Level; // button if Node.HasChildren and FShowButtons then begin ButtonRect := Rect(I * FIndent, YTop, (I + 1)* FIndent, YBottom); X := ButtonRect.Left; end; // state icon if (Node.StateIndex <> -1) then begin StateImageRect := Rect((I + 1)* FIndent, YTop, (I + 1)* FIndent + FImageStateW, YBottom); if not FPaintStandard and not Node.HasChildren then OffsetRect(StateImageRect, -FIndent, 0); if X < 0 then X := StateImageRect.Left; end; // icon if (Node.SelectedIndex <> -1) or (Node.ImageIndex <> -1) then begin if not IsRectEmpty(StateImageRect) then begin ImageRect := StateImageRect; Inc(ImageRect.Left, FImageW); ImageRect.Right := ImageRect.Left + FImageW; end else begin ImageRect := Rect((I + 1)* FIndent, YTop, (I + 1)* FIndent + FImageW - 1, YBottom); if not FPaintStandard and not Node.HasChildren then OffsetRect(ImageRect, -FIndent, 0); end; if X < 0 then X := ImageRect.Left; end; if X > 0 then IndentRect := Rect(0, YTop, X, YBottom); // check range CheckRect(IndentRect); CheckRect(ButtonRect); CheckRect(StateImageRect); CheckRect(ImageRect); end; function GetHitTest(Node: TdxTreeListNode; IsSelected: Boolean; YTop, YBottom: Integer; P: TPoint): TdxTreeListHitTest; var IndentRect, ButtonRect, StateImageRect, ImageRect: TRect; begin with DrawInfo do begin if IsRectEmptyEx(FixedBandLeftRect) then Inc(P.X, LeftCoord); P.X := P.X - CellsRect.Left; end; GetNodeIndentInfo(Node, IsSelected, YTop, YBottom, IndentRect, ButtonRect, StateImageRect, ImageRect); if PtInRect(IndentRect, P) then Result := htIndent else if PtInRect(ButtonRect, P) then Result := htButton else if PtInRect(StateImageRect, P) then Result := htStateIcon else if PtInRect(ImageRect, P) then Result := htIcon else Result := htNowhere; end; function CanBandReSizing(VisibleIndex: Integer): Boolean; begin Result := (aoBandSizing in OptionsEx) and CanBandSizing(VisibleIndex); if Result and IsBandHeaderWidth and not ShowBands then Result := False; end; begin CalcDrawInfo(DrawInfo); try with Result do begin X := Pos.X; Y := Pos.Y; Band := -1; Column := -1; Node := nil; Row := -1; FooterRow := -1; hitType := htOutside; end; with DrawInfo do begin if not PtInRect(CRect, Pos) then Exit; Result.hitType := htNowhere; // Group Panel if not IsRectEmpty(GroupPanelRect) and PtInRect(GroupPanelRect, Pos) then begin Result.hitType := htGroupPanel; Exit; end; // Band Panel Edge if not IsRectEmpty(BandRect) and CanBandPanelSizing then begin R := BandRect; if not IsRectEmpty(BandButtonRect) then R.Left := BandButtonRect.Left; Inc(R.Bottom, dxTreeListMaxResizeWidth); if PtInRect(R, Pos) and (Pos.Y >= (R.Bottom - 2*dxTreeListMaxResizeWidth)) then begin Result.hitType := htBandPanelEdge; Exit; end; end; // BandButtonRect if not IsRectEmpty(BandButtonRect) and PtInRect(BandButtonRect, Pos) then begin Result.hitType := htBandButton; Exit; end; // BandRect if not IsRectEmpty(BandRect) then begin if PtInRect(BandRect, Pos) then begin Result.hitType := htBand; // test band edge if BandsInfo <> nil then for i := 0 to BandCount - 1 do begin R := BandsInfo^[i].BandRect; if PtInRect(R, Pos) and PtInRect(BandsInfo^[i].BandClipRect, Pos) then begin Result.Band := BandsInfo^[i].Index; if CanBandReSizing(Result.Band) then begin RClip := DrawInfo.BandRect; if not IsRectEmptyEx(FixedBandLeftRect) then RClip.Left := FixedBandLeftRect.Right; if not IsRectEmptyEx(FixedBandRightRect) then RClip.Right := FixedBandRightRect.Left; if (R.Left <= RClip.Left) and (R.Right > RClip.Right) and (Pos.X >= (RClip.Right - dxTreeListMaxResizeWidth)) then begin Result.hitType := htBandEdge; Exit; end else if Pos.X >= (R.Right - dxTreeListMaxResizeWidth) then begin Result.hitType := htBandEdge; Exit; end else if (i > 0) then begin if (Pos.X >= (BandsInfo^[i - 1].BandRect.Right - dxTreeListMaxResizeWidth)) and (Pos.X <= (BandsInfo^[i - 1].BandRect.Right + dxTreeListMaxResizeWidth)) and CanBandReSizing(BandsInfo^[i - 1].Index) then begin Result.Band := BandsInfo^[i - 1].Index; Result.hitType := htBandEdge; Exit; end; end; end; Break; end; if CanBandReSizing(BandsInfo^[i].Index) and (Pos.X > R.Right) and (Pos.X <= (R.Right + dxTreeListMaxResizeWidth)) then // last band begin Result.Band := BandsInfo^[i].Index; Result.hitType := htBandEdge; Exit; end; end; Exit; end; // Band Edge (last band) if (BandCount > 0) and CanBandReSizing(BandsInfo^[BandCount - 1].Index) and PtInRect(Rect(BandRect.Right, BandRect.Top, BandRect.Right + dxTreeListMaxResizeWidth, BandRect.Bottom), Pos) then begin Result.Band := BandsInfo^[BandCount - 1].Index; Result.hitType := htBandEdge; Exit; end; end; // Header Panel Edge if not IsRectEmpty(HeaderRect) and CanHeaderPanelSizing then begin R := HeaderRect; if not IsRectEmpty(HeaderButtonRect) then R.Left := HeaderButtonRect.Left; Inc(R.Bottom, dxTreeListMaxResizeWidth); if PtInRect(R, Pos) and (Pos.Y >= (R.Bottom - 2*dxTreeListMaxResizeWidth)) then begin Result.hitType := htHeaderPanelEdge; Exit; end; end; // HeaderButtonRect if not IsRectEmpty(HeaderButtonRect) and PtInRect(HeaderButtonRect, Pos) then begin Result.hitType := htHeaderButton; Exit; end; // HeaderRect if not IsRectEmpty(HeaderRect) then begin if PtInRect(HeaderRect, Pos) then begin Result.hitType := htColumn; if HeadersInfo <> nil then begin for i := 0 to HeaderCount - 1 do begin R := HeadersInfo^[i].HeaderRect; if PtInRect(R, Pos) and PtInRect(HeadersInfo^[i].HeaderClipRect, Pos) then begin Result.Band := HeadersInfo^[i].BandIndex; Result.Column := HeadersInfo^[i].AbsoluteIndex; // test long header RClip := DrawInfo.HeaderRect; if not IsRectEmptyEx(FixedBandLeftRect) then RClip.Left := FixedBandLeftRect.Right; if not IsRectEmptyEx(FixedBandRightRect) then RClip.Right := FixedBandRightRect.Left; if ((R.Left <= RClip.Left) and (R.Right > RClip.Right) and (Pos.X >= (RClip.Right - dxTreeListMaxResizeWidth))) or (Pos.X >= (R.Right - dxTreeListMaxResizeWidth)) then begin if CanHeaderReSizing(HeadersInfo^[i].AbsoluteIndex) and (not HeadersInfo^[i].LastColumn or CanHeaderBandSizing) then Result.hitType := htColumnEdge else if HeadersInfo^[i].LastColumn and CanBandReSizing(HeadersInfo^[i].BandIndex) then Result.hitType := htBandEdge; end else if (HeadersInfo^[i].ColIndex > 0) and (i > 0) and (HeadersInfo^[i - 1].BandIndex = HeadersInfo^[i].BandIndex) and (HeadersInfo^[i - 1].RowIndex = HeadersInfo^[i].RowIndex) then begin if (Pos.X >= (HeadersInfo^[i - 1].HeaderRect.Right - dxTreeListMaxResizeWidth)) and (Pos.X <= (HeadersInfo^[i - 1].HeaderRect.Right + dxTreeListMaxResizeWidth)) and CanHeaderReSizing(HeadersInfo^[i - 1].AbsoluteIndex) then begin Result.Column := HeadersInfo^[i - 1].AbsoluteIndex; Result.hitType := htColumnEdge; end; end else if (HeadersInfo^[i].ColIndex = 0) and (HeadersInfo^[i].BandIndex > 0) and (Pos.X < (HeadersInfo^[i].HeaderRect.Left + dxTreeListMaxResizeWidth)) then begin Result.Band := HeadersInfo^[i].BandIndex - 1; if not CanHeaderBandSizing and CanBandReSizing(HeadersInfo^[i].BandIndex - 1) then Result.hitType := htBandEdge else if CanHeaderBandSizing then begin k := GetHeaderRowCount(Result.Band); if k > 0 then begin Result.Column := GetHeaderAbsoluteIndex(Result.Band, k - 1, GetHeaderColCount(Result.Band, k - 1) - 1); if (Result.Column <> -1) and CanHeaderReSizing(Result.Column) then Result.hitType := htColumnEdge; end; end; end; Exit; end; end; end; Result.hitType := htNowhere; // Empty rect Exit; end; // Band Edge (last band) if (BandCount > 0) and PtInRect(Rect(HeaderRect.Right, HeaderRect.Top, HeaderRect.Right + dxTreeListMaxResizeWidth, HeaderRect.Bottom), Pos) then begin Result.Band := BandsInfo^[BandCount - 1].Index; if not CanHeaderBandSizing and CanBandReSizing(BandsInfo^[BandCount - 1].Index) then Result.hitType := htBandEdge else if CanHeaderBandSizing then begin k := GetHeaderRowCount(Result.Band); if k > 0 then begin Result.Column := GetHeaderAbsoluteIndex(Result.Band, k - 1, GetHeaderColCount(Result.Band, k - 1) - 1); if (Result.Column <> -1) and CanHeaderReSizing(Result.Column) then Result.hitType := htColumnEdge; end; end; Exit; end; end; // NewItemRowRect if not IsRectEmpty(NewItemRowRect) and PtInRect(NewItemRowRect, Pos) then begin Result.hitType := htNewRowItem; // calc column index if HeadersInfo <> nil then begin for i := 0 to HeaderCount - 1 do begin R := HeadersInfo^[i].HeaderRect; R.Top := NewItemRowRect.Top; R.Bottom := NewItemRowRect.Bottom - FNewItemRowSeparatorHeight; with HeadersInfo^[i].HeaderClipRect do RClip := Rect(Left, R.Top, Right, R.Bottom); if PtInRect(R, Pos) and PtInRect(RClip, Pos) then begin Result.Band := HeadersInfo^[i].BandIndex; Result.Column := HeadersInfo^[i].AbsoluteIndex; Break; end; end; end; Exit; end; // IndicatorRect if not ShowIndicator then IndicatorRect.Right := CellsRect.Right; if not IsRectEmpty(IndicatorRect) then begin if PtInRect(IndicatorRect, Pos) then begin Result.hitType := htIndicator; // calc Row index if RowsInfo <> nil then begin Y := CellsRect.Top; for i := 0 to RowCount - 1 do begin if (Y <= Pos.Y) and (Pos.Y < (Y + RowsInfo^[i].RowHeight)) then begin Result.Row := i; Result.Node := RowsInfo^[i].Node; if CanRowSizing then begin if (Y <> CellsRect.Top) and (i > 0) and (Y <= Pos.Y) and (Pos.Y <= (Y + dxTreeListMaxResizeWidth)) then begin Result.Row := i - 1; Result.Node := RowsInfo^[i - 1].Node; Result.hitType := htRowEdge; Exit; end else if ((Y + RowsInfo^[i].RowHeight - dxTreeListMaxResizeWidth) <= Pos.Y) and (Pos.Y <= (Y + RowsInfo^[i].RowHeight)) then begin Result.Row := i; Result.Node := RowsInfo^[i].Node; Result.hitType := htRowEdge; Exit; end; end; Break; end; Inc(Y, RowsInfo^[i].RowHeight); end; end; if ShowIndicator or (Result.hitType = htRowEdge) then Exit; end else // test last row if PtInRect(Rect(IndicatorRect.Left, IndicatorRect.Bottom, IndicatorRect.Right, IndicatorRect.Bottom + dxTreeListMaxResizeWidth), Pos) and (RowCount > 0) and CanRowSizing then begin Result.Row := RowCount - 1; Result.Node := RowsInfo^[RowCount - 1].Node; Result.hitType := htRowEdge; if ShowIndicator or (Result.hitType = htRowEdge) then Exit; end; end; // Status if not IsRectEmpty(StatusRect) and PtInRect(StatusRect, Pos) then begin Result.hitType := htStatusPanel; Exit; end; // FooterRect if not IsRectEmpty(FooterRect) and PtInRect(FooterRect, Pos) then begin Result.hitType := htSummaryFooter; // calc column if HeadersInfo <> nil then begin for i := 0 to HeaderCount - 1 do begin with HeadersInfo^[i] do begin R := Rect(HeaderRect.Left, FooterRect.Top + FFooterRowHeight * RowIndex, HeaderRect.Right, FooterRect.Top + FFooterRowHeight * RowIndex + LineCount * FFooterRowHeight + 3); if RowIndex = 0 then Dec(R.Top); with HeaderClipRect do RClip := Rect(Left, R.Top, Right, R.Bottom); end; if PtInRect(R, Pos) and PtInRect(RClip, Pos) then begin Result.Band := HeadersInfo^[i].BandIndex; Result.Column := HeadersInfo^[i].AbsoluteIndex; Break; end; end; end; Exit; end; // Row if (RowsInfo <> nil) and (BandCount > 0) then begin Y := CellsRect.Top; for i := 0 to RowCount - 1 do begin if (Y <= Pos.Y) and (Pos.Y < (Y + RowsInfo^[i].RowHeight)) then begin Result.Row := i; Result.hitType := htRight; Result.Node := RowsInfo^[i].Node; if Pos.X < EdgeX then Result.hitType := htLabel; if Result.Node <> nil then begin with RowsInfo^[i] do begin // test node footer for k := 0 to RowFooterCount - 1 do begin R := GetFooterRect(Node, k, Y + RowHeight - RowSeparatorLineWidth - RowFooterHeight, Byte(FShowGrid), DrawInfo); if PtInRect(R, Pos) then begin Result.hitType := htSummaryNodeFooter; Result.FooterRow := k; Break; end; end; // test indent if Result.hitType <> htSummaryNodeFooter then begin GetNodeIndent(Node, Ind1, Ind); if Ind > IndentLimit then Ind := IndentLimit; if IsRectEmptyEx(FixedBandLeftRect) then Dec(Ind, LeftCoord); if Pos.X < (CellsRect.Left + Ind) then Result.hitType := GetHitTest(Node, IsSelected, Y, Y + RowHeight, Pos); end; // test preview if Result.hitType = htLabel then begin if PreviewLineCount > 0 then begin if ((Y + RowHeight - PreviewLineCount * FDescTextHeight - RowSeparatorLineWidth - 2 - RowFooterHeight) <= Pos.Y) and (Pos.Y <= Y + RowHeight - RowSeparatorLineWidth - RowFooterHeight) then begin Result.hitType := htPreview; end; end; end; // calc column index if Result.hitType in [htLabel, htSummaryNodeFooter] then begin if (HeadersInfo <> nil) then begin for j := 0 to HeaderCount - 1 do begin with HeadersInfo^[j] do begin if Result.hitType = htLabel then begin R := Rect(HeaderRect.Left, Y + FRowHeight * RowIndex, HeaderRect.Right, Y + FRowHeight * RowIndex + LineCount * FRowHeight); if (FHeaderRowCount = 1) then R.Bottom := Y + RowHeight - PreviewLineCount * FDescTextHeight {- RowSeparatorLineWidth} - RowFooterHeight; end else begin k := Y + RowHeight {- RowSeparatorLineWidth} - RowFooterHeight + Result.FooterRow * FFooterRowNodeHeight; R := Rect(HeaderRect.Left, k + FFooterRowHeight * RowIndex, HeaderRect.Right, k + FFooterRowHeight * RowIndex + LineCount * FFooterRowHeight + 2); if RowIndex = 0 then Dec(R.Top); end; with HeaderClipRect do RClip := Rect(Left, R.Top, Right, R.Bottom); if PtInRect(R, Pos) and PtInRect(RClip, Pos) then begin Result.Band := HeadersInfo^[j].BandIndex; Result.Column := HeadersInfo^[j].AbsoluteIndex; Break; end; end; end; end; end; end; end; Break; end; Inc(Y, RowsInfo^[i].RowHeight); end; end; end; finally FreeDrawInfo(DrawInfo); end; end; function TCustomdxTreeList.GetHitTestInfoAt(X, Y: Integer): TdxTreeListHitTest; begin Result := GetHitInfo(Point(X, Y)).hitType; end; function TCustomdxTreeList.GetNextVisible(Node: TdxTreeListNode):TdxTreeListNode; function GetLastVisible(Node:TdxTreeListNode):TdxTreeListNode; 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; {**}var i: Integer; begin {**} if IsSmartNavigation then begin i := FindListNode(Node); Result := nil; if i <> -1 then begin i := Integer(FListIndexes[i]); Inc(i); if i < FListRealNodes.Count then Result := TdxTreeListNode(FListRealNodes[i]); end; Exit; end; {**} if Node.Expanded and (Node.Count > 0) 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 TCustomdxTreeList.GetNodeAt(X, Y: Integer): TdxTreeListNode; begin Result := GetHitInfo(Point(X, Y)).Node; end; function TCustomdxTreeList.GetNodeByNavigation(ANode: TdxTreeListNode; ANavigationMode: TdxTreeListNavigationMode; AGotoHidden: Boolean): TdxTreeListNode; begin Result := ANode; if Assigned(ANode) then begin case ANavigationMode of tlnmFirst: Result := TopNode; tlnmPrev: begin Result := ANode.GetPriorNode; end; tlnmNext: begin if AGotoHidden then Result := ANode.GetNext else Result := ANode.GetNextNode; end; tlnmLast: begin Result := LastNode; if AGotoHidden then while Result.Count > 0 do Result := Result[Result.Count - 1]; end; else Result := nil; end; end; end; function TCustomdxTreeList.GotoNodeByNavigation(ANavigationMode: TdxTreeListNavigationMode; AGotoHidden: Boolean): TdxTreeListNode; var ANeededSelectedResync: Boolean; begin Result := FocusedNode; if Assigned(Result) then begin ANeededSelectedResync := IsMultiSelect and (SelectedCount = 1) and IsNodeSelected(Result); Result := GetNodeByNavigation(Result, ANavigationMode, AGotoHidden); if Assigned(Result) then begin Result.Focused := True; if ANeededSelectedResync then begin ClearSelection; Result.Selected := True; end; end; end; end; procedure TCustomdxTreeList.GotoFirst; begin GotoNodeByNavigation(tlnmFirst, False); end; procedure TCustomdxTreeList.GotoLast(AGotoHidden: Boolean); begin GotoNodeByNavigation(tlnmLast, AGotoHidden); end; function TCustomdxTreeList.GotoNext(AGotoHidden: Boolean): Boolean; begin Result := GotoNodeByNavigation(tlnmNext, AGotoHidden) <> nil; end; function TCustomdxTreeList.GotoPrev(AGotoHidden: Boolean): Boolean; begin Result := GotoNodeByNavigation(tlnmPrev, AGotoHidden) <> nil; end; function TCustomdxTreeList.HideDrawFocusRect: Boolean; begin Result := aoHideFocusRect in Options; end; procedure TCustomdxTreeList.HideEditor; begin if FState <> tsEditing then Exit; if not (csDestroying in ComponentState) then if InplaceEditor <> nil then InplaceEditor.ValidateEdit; SetState(tsNormal); HideEdit(False); end; function TCustomdxTreeList.IndexOf(Value: TdxTreeListNode) : Integer; begin Result := FNodeList.IndexOf(Value); end; function TCustomdxTreeList.Insert(BeforeNode: TdxTreeListNode) : TdxTreeListNode; begin Result := CreateNode; if (BeforeNode = nil) then FNodeList.Add(Result) else FNodeList.Insert(BeforeNode.Index, Result); AddNode(Result); end; function TCustomdxTreeList.IsAutoFilter: Boolean; begin Result := False; end; function TCustomdxTreeList.IsActive: Boolean; begin Result := IsActiveControl or ((State = tsEditing) and (InplaceEditor <> nil) and InplaceEditor.IsFocused); end; function TCustomdxTreeList.IsBOF: Boolean; begin Result := (Count = 0) or (FocusedNode = TopNode); end; function TCustomdxTreeList.IsEOF: Boolean; begin Result := (Count = 0) or (FocusedNode = LastNode); end; function TCustomdxTreeList.IsInvertSelect: Boolean; begin Result := aoInvertSelect in OptionsEx; end; function TCustomdxTreeList.IsNodeVisible(Node: TdxTreeListNode) : 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; function TCustomdxTreeList.IsShowButtonAlways: Boolean; begin Result := aoShowButtonAlways in OptionsEx; end; procedure TCustomdxTreeList.MakeBandVisible(VisibleIndex: Integer); var XStart, XEnd, SWidth: Integer; begin if (GetBandCount > 1) and (VisibleIndex >= 0) and (VisibleIndex < GetBandCount) and (VisibleIndex <> GetBandFixedLeft) and (VisibleIndex <> GetBandFixedRight) then begin // Calc Left and Right Position XStart := GetStartBandCoord(VisibleIndex); XEnd := XStart + GetBandWidth(VisibleIndex); SWidth := GetScrollableWidth; // Check Pos if (XStart < LeftCoord) then LeftCoord := XStart else if (XEnd > (LeftCoord + SWidth)) then begin XEnd := LeftCoord + (XEnd - (LeftCoord + SWidth)); if XStart < XEnd then XEnd := XStart; LeftCoord := XEnd; end; end; end; procedure TCustomdxTreeList.MakeColumnVisible(AbsoluteIndex: Integer); var AIndex, BIndex, RIndex, CIndex, C, XStart, XEnd: Integer; SWidth, W: Integer; begin if (0 <= AbsoluteIndex) and (AbsoluteIndex < GetHeaderAbsoluteCount) then begin BIndex := GetVisibleBandIndex(GetHeaderBandIndex(AbsoluteIndex)); if (BIndex <> -1) and (BIndex <> GetBandFixedLeft) and (BIndex <> GetBandFixedRight) then begin // Calc Left and Right Pos 1 RIndex := GetHeaderRowIndex(AbsoluteIndex); CIndex := GetHeaderColIndex(AbsoluteIndex); XStart := GetStartBandCoord(BIndex); XEnd := XStart; for C := 0 to CIndex do begin AIndex := GetHeaderAbsoluteIndex(BIndex, RIndex, C); W := GetHeaderBoundsWidth(AIndex); if C <> CIndex then Inc(XStart, W) else XEnd := XStart + W; end; // Check Pos SWidth := GetScrollableWidth; // Check Pos if (XStart < LeftCoord) then LeftCoord := XStart else if (XEnd > (LeftCoord + SWidth)) then begin XEnd := LeftCoord + (XEnd - (LeftCoord + SWidth)); if XStart < XEnd then XEnd := XStart; LeftCoord := XEnd; end; end; end; end; procedure TCustomdxTreeList.MakeNodeVisible(Node: TdxTreeListNode); var FTopIndex, FIndex: Integer; FlagRepaint: Boolean; CurNode: TdxTreeListNode; begin FlagRepaint := False; 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; FTopIndex := GetAbsoluteIndex(TopVisibleNode); FIndex := GetAbsoluteIndex(Node); if (FTopIndex <= FIndex) and (FIndex <= (FTopIndex + RowCount - 1)) and (not FlagRepaint) then Exit; if FIndex < FTopIndex then TopIndex := FIndex else if (FIndex > (FTopIndex + RowCount - 1)) then TopIndex := CalcNearTopIndex(FIndex); if FlagRepaint then EndUpdate; end; function TCustomdxTreeList.PointInCustomizingForm(P:TPoint) : Boolean; begin Result := False; if (FCustomizingForm <> nil) and FCustomizingForm.Visible and PtInRect(FCustomizingForm.ClientRect, FCustomizingForm.ScreenToClient(P)) then Result := True; end; procedure TCustomdxTreeList.SaveAllToStrings(List: TStrings); var Node: TdxTreeListNode; begin {Copy Headers} List.Add(GetHeaderTabText); {Copy nodes} Node := TopNode; while Node <> nil do begin List.Add(GetNodeTabText(Node)); Node := Node.GetNextNode; end; end; procedure TCustomdxTreeList.SaveAllToTextFile(const FileName : String); var L: TStrings; begin L := TStringList.Create; try SaveAllToStrings(L); L.SaveToFile(FileName); finally L.Free; end; end; procedure TCustomdxTreeList.SaveSelectedToStrings(List: TStrings); var I: Integer; L: TList; begin {Copy Headers} List.Add(GetHeaderTabText); {Copy nodes} if IsMultiSelect then begin L := TList.Create; try for I := 0 to SelectedCount - 1 do L.Add(SelectedNodes[I]); L.Sort(@CompareByAbsoluteIndex); for I := 0 to L.Count - 1 do List.Add(GetNodeTabText(L[I])); finally L.Free; end; end else begin if FocusedNode <> nil then List.Add(GetNodeTabText(FocusedNode)); end; end; procedure TCustomdxTreeList.SaveSelectedToTextFile(const FileName : String); var L: TStrings; begin L := TStringList.Create; try SaveSelectedToStrings(L); L.SaveToFile(FileName); finally L.Free; end; end; procedure TCustomdxTreeList.ShowEditor; var Allow : Boolean; begin if not IsEditing or IsRowSelect or (FocusedNode = nil) then Exit; Allow := True; // check new item row if NewItemRowActive then DoBeforeEditNewItemRow(Allow) else if FocusedNode <> nil then DoBeforeEditing(FocusedNode, Allow) else Allow := False; if not Allow then begin FInplaceEdit := nil; Exit; end; if FState <> tsNormal then Exit; if (FocusedColumn = -1) or (GetVisibleHeaderCount = 0) then Exit; MakeColumnVisible(GetFocusedAbsoluteIndex(FocusedColumn)); if FocusedNode <> nil then FocusedNode.MakeVisible; SetState(tsEditing); UpdateEdit(True); end; procedure TCustomdxTreeList.ShowEditorChar(Ch: Char); begin ShowEditor; if (InplaceEditor <> nil) and (State = tsEditing) then case Ch of // RE ^V: PostMessage(InplaceEditor.Handle, WM_PASTE, 0, 0); ^X: PostMessage(InplaceEditor.Handle, WM_CUT, 0, 0); else PostMessage(InplaceEditor.Handle, WM_CHAR, Word(Ch), 0); end; end; procedure TCustomdxTreeList.ShowButtonEditorMouse(X, Y: Integer); begin ShowEditor; if (State = tsEditing) and (InplaceEditor <> nil) then InplaceEditor.MouseButtonClick(X, Y); end; procedure TCustomdxTreeList.ShowEditorMouse(X, Y: Integer); begin ShowEditor; if (State = tsEditing) and (InplaceEditor <> nil) then InplaceEditor.MouseClick; end; procedure TCustomdxTreeList.StabilizeAutoWidth; var AIndex: Integer; begin if IsBandHeaderWidth and (GetVisibleHeaderCount > 0) and (GetBandCount = 1) then begin AIndex := GetFocusedAbsoluteIndex(0); ChangedHeaderAutoWidth(GetBandCount - 1, AIndex, GetHeaderBoundsWidth(AIndex)); end else if GetBandCount > 0 then ChangedBandAutoWidth(0, GetBandWidth(0) + GetIndentWidth); end; function TCustomdxTreeList.StartSearch(AColumnIndex: Integer; const AText: string): Boolean; begin HideEditor; NewItemRowActive := False; if AColumnIndex = -1 then AColumnIndex := FocusedAbsoluteIndex; FSearchColumnIndex := AColumnIndex; FocusedColumn := GetFocusedVisibleIndex(FSearchColumnIndex); FSearching := True; FSearchText := AText; DoSearch(FSearchText, sdNone, True{Exact}); Result := FSearchText <> ''; end; procedure TCustomdxTreeList.EndSearch; begin if FSearching then begin FSearching := False; if (LockUpdate = 0) and (FocusedNode <> nil) and not (csDestroying in ComponentState) then InvalidateRect(GetRectNode(FocusedNode)); end; end; procedure TCustomdxTreeList.CheckSearchColumn; begin if not IsRowSelect and (FSearchColumnIndex <> FocusedAbsoluteIndex) then begin FSearchColumnIndex := FocusedAbsoluteIndex; FSearchText := ''; end; end; procedure TCustomdxTreeList.DoSearch(var AText: string; ADirection: TdxTreeListSearchDirection; AExact: Boolean); var Node: TdxTreeListNode; begin Inc(FLockSearching); try if (FSearchColumnIndex <> -1) and (Count > 0) then begin Node := nil; if not FindNodeByText(FSearchColumnIndex, AText, ADirection, Node) then begin if AExact then AText := '' else if ADirection = sdNone then Delete(AText, Length(AText), 1); end else if Node <> nil then Node.Focused := True; end else AText := ''; if FocusedNode <> nil then begin if IsMultiSelect then begin ClearSelection; if not FocusedNode.Selected then FocusedNode.Selected := True; end; FocusedNode.MakeVisible; InvalidateRect(GetRectNode(FocusedNode)); end; finally Dec(FLockSearching); end; end; function TCustomdxTreeList.FindNodeByText(AColumnIndex: Integer; const AText: string; ADirection: TdxTreeListSearchDirection; var ANode: TdxTreeListNode): Boolean; function GetPrior(Node: TdxTreeListNode): TdxTreeListNode; begin Result := nil; if Node <> nil then begin if AutoExpandOnSearch then Result := Node.GetPrev else Result := Node.GetPriorNode; end; end; function GetNext(Node: TdxTreeListNode): TdxTreeListNode; begin Result := nil; if Node <> nil then begin if AutoExpandOnSearch then Result := Node.GetNext else Result := Node.GetNextNode; end; end; var CurNode, StartNode: TdxTreeListNode; L: Integer; S: string; procedure CalcNextNode; begin if CurNode <> nil then if ADirection = sdUp then begin CurNode := GetPrior(CurNode); if CurNode = nil then begin CurNode := LastNode; StartNode := FocusedNode; end; end else begin CurNode := GetNext(CurNode); if CurNode = nil then begin CurNode := TopNode; StartNode := FocusedNode; end; end; end; begin Result := False; if AText <> '' then begin CurNode := FocusedNode; StartNode := nil; if ADirection <> sdNone then CalcNextNode; L := Length(AText); while (CurNode <> nil) and (CurNode <> StartNode) do begin S := CurNode.Strings[AColumnIndex]; if IsEqualText(Copy(S, 1, L), AText) then begin ANode := CurNode; Result := True; Break; end; CalcNextNode; end; end; end; procedure TCustomdxTreeList.BeginSelection; begin if FLockSelection = 0 then FPrevSelectedCount := SelectedCount; Inc(FLockSelection); end; function TCustomdxTreeList.GetDefaultPopupBorderStyle(AEditBorderStyle: TdxEditBorderStyle): TdxPopupBorderStyle; begin if LookAndFeel = lfStandard then Result := pbFrame3D else Result := pbSingle; end; procedure TCustomdxTreeList.EndSelection; begin Dec(FLockSelection); if (FLockSelection = 0) and (FPrevSelectedCount <> SelectedCount) then DoSelectedCountChange; end; // protected TCustomdxTreeList // override TCustomControl // override TCustomControl procedure TCustomdxTreeList.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 (LookAndFeel = lfStandard) 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; if (LookAndFeel <> lfStandard) then if (FBorderStyle = bsNone) then Style := Style and not WS_BORDER; end; end; procedure TCustomdxTreeList.CreateWnd; begin inherited CreateWnd; UpdateScrollBars; end; procedure TCustomdxTreeList.DoExit; begin inherited DoExit; HideEditor; end; procedure TCustomdxTreeList.KeyDown(var Key: Word; Shift: TShiftState); procedure DoSelection(Direction: Integer); function Sign(const I: Integer): Integer; begin if I = 0 then Result := 0 else if I < 0 then Result := -1 else Result := 1; end; var AddAfter: Boolean; begin AddAfter := False; if IsMultiSelect then if (ssShift in Shift) then begin if not FSelecting then begin if not ((GetSelectedCount=1) and ((Direction < 0) and IsTopNode(FocusedNode)) or ((Direction > 0) and IsLastNode(FocusedNode))) then ClearSelection; if CanFullMultiSelect and (SelectionAnchor <> nil) then begin SelectNodes(SelectionAnchor, FocusedNode); FocusedNode.Selected := Sign(SelectionAnchor.AbsoluteIndex - FocusedNode.AbsoluteIndex) <> Sign(Direction); // FocusedNode.Selected := False; end else begin SelectionAnchor := FocusedNode; FocusedNode.Selected := True; end; FSelecting := True; AddAfter := True; end else begin AddAfter := CompareSelectionAnchor(FocusedNode) <> -Direction; if not AddAfter then FocusedNode.Selected := False; end; end else begin if not ((GetSelectedCount=1) and ((Direction < 0) and IsTopNode(FocusedNode)) or ((Direction > 0) and IsLastNode(FocusedNode))) then ClearSelection; SelectionAnchor := nil; end; FocusedNumber:=FocusedNumber+Direction; if AddAfter then FocusedNode.Selected := True; end; procedure MoveFocused(Direction: Integer); var AFocusedIndex, ATopIndex, AEndIndex, FCount: Integer; begin FCount := GetAbsoluteCount; if (FocusedNode <> nil) {and (FCount > 1) }then begin if FCount > 1 then begin AFocusedIndex := GetAbsoluteIndex(FocusedNode); ATopIndex := GetAbsoluteIndex(TopVisibleNode); AEndIndex := ATopIndex + RowCount - 1; if AEndIndex > (FCount - 1) then AEndIndex := FCount - 1; if (ATopIndex < AFocusedIndex) and (AFocusedIndex < AEndIndex) then if Direction < 0 then FocusedNumber := ATopIndex else FocusedNumber := AEndIndex else begin AFocusedIndex := RowCount - 1; if AFocusedIndex < 1 then AFocusedIndex := 1; if Direction < 0 then FocusedNumber := FocusedNumber - AFocusedIndex else FocusedNumber := FocusedNumber + AFocusedIndex; end; end else begin if ((Direction < 0) and not IsTopNode(FocusedNode)) or ((Direction > 0) and not IsLastNode(FocusedNode)) then FocusedNumber := FocusedNumber + Direction; end; end; end; function CalcNextColumn(AColumn: Integer; AForward: Boolean): Integer; var AIndex, C: Integer; begin if AForward then begin C := GetVisibleHeaderCount; while (AColumn < C) do begin AIndex := GetFocusedAbsoluteIndex(AColumn); if GetHeaderTabStop(AIndex) then Break; Inc(AColumn); end; end else begin while (0 <= AColumn) do begin AIndex := GetFocusedAbsoluteIndex(AColumn); if GetHeaderTabStop(AIndex) then Break; Dec(AColumn); end; end; Result := AColumn; end; procedure MoveToEndColumnPriorRow; var AIndex: Integer; begin ClearSelection; FocusedNumber := FocusedNumber - 1; AIndex := CalcNextColumn(GetVisibleHeaderCount - 1, False{Forward}); // if AIndex < 0 then AIndex := GetVisibleHeaderCount - 1; if AIndex >= 0 then FocusedColumn := AIndex; end; procedure MoveToHomeNextRow; var AIndex: Integer; begin ClearSelection; FocusedNumber := FocusedNumber + 1; AIndex := CalcNextColumn(0, True{Forward}); // if AIndex > (GetVisibleHeaderCount - 1) then AIndex := 0; if AIndex <= (GetVisibleHeaderCount - 1) then FocusedColumn := AIndex; end; var AIndex: Integer; SearchDirection: TdxTreeListSearchDirection; begin BeginSelection; try inherited KeyDown(Key, Shift); if not CanTreeListAcceptKey(Key, Shift) then Key := 0; if State in [tsColumnSizing, tsColumnDragging, tsBandSizing, tsBandDragging, tsBandPanelSizing, tsHeaderPanelSizing, tsRowSizing] then begin if Key = VK_ESCAPE then CancelDragSizing; Exit; end; if Count = 0 then Exit; if (Key In [VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT, VK_TAB, VK_RETURN, {VK_INSERT,} VK_ESCAPE]) and (FState = tsEditing) then begin CloseEditor; if Key = VK_ESCAPE then Exit; end; if NewItemRowActive and (Key in [VK_NEXT, VK_DOWN]) then begin NewItemRowActive := False; if TopVisibleNode <> nil then TopVisibleNode.Focused := True; if not ((ssCtrl in Shift) or (ssShift in Shift)) then begin ClearSelection; SelectionAnchor := nil; if FocusedNode <> nil then FocusedNode.Selected := True; end; end else // Search if FSearching and ((Key in [VK_DELETE, VK_BACK, VK_ESCAPE]) or ((Key = VK_RETURN) and (Shift*[ssCtrl, ssShift] <> []))) then begin CheckSearchColumn; SearchDirection := sdNone; case Key of VK_DELETE: FSearchText := ''; VK_BACK: Delete(FSearchText, Length(FSearchText), 1); VK_RETURN: if ssCtrl in Shift then SearchDirection := sdDown else if ssShift in Shift then SearchDirection := sdUp; end; if Key = VK_ESCAPE then EndSearch else DoSearch(FSearchText, SearchDirection, False); end else if (ssCtrl in Shift) and not ( (Key in [VK_HOME, VK_END, VK_NEXT, VK_PRIOR, VK_UP, VK_DOWN]) and (ssShift in Shift) and CanFullMultiSelect) then begin FSelecting := False; case Key of VK_SPACE: if (IsRowSelect or not IsEditing) and (FocusedNode <> nil) then begin FocusedNode.Selected := not FocusedNode.Selected; SelectionAnchor := FocusedNode; end; VK_HOME: FocusedNumber := 0; VK_END: FocusedNumber := GetAbsoluteCount - 1; VK_NEXT: MoveFocused(1); //FocusedNumber:=FocusedNumber+RowCount - 1; VK_PRIOR: MoveFocused(-1); //FocusedNumber:=FocusedNumber-RowCount + 1; VK_UP: if IsTopNode(FocusedNode) then NewItemRowActive := True else FocusedNumber:=FocusedNumber-1; VK_DOWN: FocusedNumber:=FocusedNumber+1; VK_LEFT: FocusedColumn := 0; VK_RIGHT: FocusedColumn := GetVisibleHeaderCount - 1; VK_INSERT: CopySelectedToClipboard; end; end else begin case Key of VK_HOME: begin if (IsRowSelect or (ssShift in Shift)) then begin ClearSelection; { if (ssShift in Shift) and CanFullMultiSelect then begin if SelectionAnchor = nil then SelectionAnchor := FocusedNode; SelectNodes(SelectionAnchor, TopNode); end else SelectionAnchor := nil; FocusedNumber:=0; } if (ssShift in Shift) and CanFullMultiSelect then begin if SelectionAnchor = nil then SelectionAnchor := FocusedNode; FocusedNumber := 0; if SelectionAnchor <> nil then SelectNodes(SelectionAnchor, FocusedNode{TopNode}); end else begin SelectionAnchor := nil; FocusedNumber := 0; end; end else FocusedColumn := 0; end; VK_END: begin if (IsRowSelect or (ssShift in Shift)) then begin ClearSelection; { if (ssShift in Shift) and CanFullMultiSelect then begin if SelectionAnchor = nil then SelectionAnchor := FocusedNode; SelectNodes(SelectionAnchor, LastNode); end else SelectionAnchor := nil; FocusedNumber:=GetAbsoluteCount-1; } if (ssShift in Shift) and CanFullMultiSelect then begin if SelectionAnchor = nil then SelectionAnchor := FocusedNode; FocusedNumber := GetAbsoluteCount - 1; if SelectionAnchor <> nil then SelectNodes(SelectionAnchor, FocusedNode{LastNode}); end else begin SelectionAnchor := nil; FocusedNumber := GetAbsoluteCount - 1; end; end else FocusedColumn := GetVisibleHeaderCount - 1; end; VK_PRIOR: begin ClearSelection; if (ssShift in Shift) and CanFullMultiSelect then begin if SelectionAnchor = nil then SelectionAnchor := FocusedNode; end else SelectionAnchor := nil; // FocusedNumber := FocusedNumber - RowCount; if IsTopNode(FocusedNode) then NewItemRowActive := True else MoveFocused(-1); if (ssShift in Shift) and CanFullMultiSelect and (SelectionAnchor <> nil) then SelectNodes(SelectionAnchor, FocusedNode); end; VK_NEXT: begin ClearSelection; if (ssShift in Shift) and CanFullMultiSelect then begin if SelectionAnchor = nil then SelectionAnchor := FocusedNode; end else SelectionAnchor := nil; MoveFocused(1); if (ssShift in Shift) and CanFullMultiSelect and (SelectionAnchor <> nil) then SelectNodes(SelectionAnchor, FocusedNode); end; VK_UP: begin if not (IsVertThrough and DoMoveFocusedColumn(True{Up}, False)) then begin if IsTopNode(FocusedNode) then NewItemRowActive := True else DoSelection(-1); end; end; VK_DOWN: begin if not (IsVertThrough and DoMoveFocusedColumn(False{Down}, False)) then DoSelection(1); end; VK_LEFT: begin if IsRowSelect then begin FocusedNode.MakeVisible; if not NewItemRowActive then if FocusedNode.Expanded then FocusedNode.Expanded := False else if (FocusedNode.Index = 0) and (FocusedNode.Parent <> Nil) then begin ClearSelection; FocusedNode.Parent.Focused := True; FocusedNode.Selected := True; end else begin ClearSelection; FocusedNumber := FocusedNumber - 1; end; end else begin if (FocusedColumn = 0) and IsHorzThrough then MoveToEndColumnPriorRow else FocusedColumn := FocusedColumn - 1; end; end; VK_RIGHT: begin if IsRowSelect then begin FocusedNode.MakeVisible; if not NewItemRowActive then if FocusedNode.HasChildren then begin if not FocusedNode.Expanded then FocusedNode.Expanded := True else if FocusedNode.Count > 0 then begin ClearSelection; FocusedNode[0].Focused := True; FocusedNode.Selected := True; end; end else begin ClearSelection; FocusedNumber := FocusedNumber + 1; end; end else begin if (FocusedColumn >= (GetVisibleHeaderCount - 1)) and IsHorzThrough then MoveToHomeNextRow else FocusedColumn := FocusedColumn + 1; end; end; VK_ESCAPE: begin ClearSelection; InvalidateEditor; if FInplaceEdit <> nil then FInplaceEdit.Deselect; CloseEditor; end; VK_F2: ShowEditor; VK_TAB: if not (ssAlt in Shift) then begin if ssShift in Shift then begin if IsRowSelect then begin ClearSelection; FocusedNumber:=FocusedNumber - 1; end else begin // TabStop - calc next column AIndex := CalcNextColumn(FocusedColumn - 1, False{Forward}); if (AIndex < 0) and IsTabThrough then MoveToEndColumnPriorRow else FocusedColumn := AIndex; end; Shift := []; end else begin if IsRowSelect then begin ClearSelection; FocusedNumber:=FocusedNumber + 1; end else begin // TabStop - calc next column AIndex := CalcNextColumn(FocusedColumn + 1, True{Forward}); if (AIndex > (GetVisibleHeaderCount - 1)) and IsTabThrough then MoveToHomeNextRow else FocusedColumn := AIndex; end; end; end; VK_RETURN: begin if IsEnterThrough then begin // TabStop - calc next column AIndex := CalcNextColumn(FocusedColumn + 1, True{Forward}); if (AIndex > (GetVisibleHeaderCount - 1)) then MoveToHomeNextRow else FocusedColumn := AIndex; ShowEditor; end; end; end; if (GetSelectedCount=0) and (FocusedNode <> nil) then FocusedNode.Selected := True; end; finally EndSelection; end; end; procedure TCustomdxTreeList.KeyPress(var Key: Char); function IsControlPressed: Boolean; begin Result := (GetAsyncKeyState(VK_CONTROL) < 0) and (GetAsyncKeyState(VK_MENU) >= 0); end; begin if (State = tsNormal) and not FSearching and IsAutoSearch and not (Key in [#8..#9, #13, #27]) and not IsControlPressed then // TODO: ^V, ^X, ... StartSearch(FocusedAbsoluteIndex, ''); if not FSearching and IsEnterShowEditor and (FState <> tsEditing) then begin if Key = #13 then ShowEditor else if Key in [^H, ^V, ^X, #32..#255] then begin ShowEditorChar(Key); if InplaceEditor = nil then inherited KeyPress(Key); // OnKeyPress event end else inherited KeyPress(Key) end else inherited KeyPress(Key); if FState = tsEditing then Exit; if FocusedNode <> nil then case Key of '-': begin FocusedNode.MakeVisible; FocusedNode.Expanded := False; end; '+': begin FocusedNode.MakeVisible; FocusedNode.Expanded := True; end; '*': begin if FocusedNode.HasChildren then FocusedNode.Expand(True{Recuse}); end; ^C: if aoAutoCopySelectedToClipboard in OptionsEx then CopySelectedToClipboard; end; if FSearching and (Key in [#32..#255]) and not IsControlPressed then // TODO: ^V, ^X, ... begin CheckSearchColumn; FSearchText := FSearchText + Key; DoSearch(FSearchText, sdNone, False); end; end; procedure TCustomdxTreeList.Loaded; begin inherited Loaded; LayoutChanged; end; procedure TCustomdxTreeList.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); const DblClickHitTest = [htNowhere, htButton, htIcon, htStateIcon, htIndent, htLabel, htRight, htOutside]; var OldFocusedColumn, NewColumn: Integer; FlagFocus: Boolean; PrevNewItemRowActive: Boolean; begin if (State = tsEditing) and (InplaceEditor <> Nil) and (InplaceEditor.DisableKillFocus) then Exit; if (InplaceEditor <> nil) and not InplaceEditor.DisableCloseEditor then CloseEditor; FlagFocus := False; FlagCtrl := False; FlagSelect := False; FlagEditor := False; if not (csDesigning in ComponentState) and (CanFocus or (GetParentForm(Self) = nil)) then begin if not Focused then FlagFocus := True; //SetFocus; Windows.SetFocus(Handle); if not IsActiveControl then begin MouseCapture := False; Exit; end; end; FHitInfo := GetHitInfo(Point(X, Y)); // if Right button pressed then Cancel Drag and Sizing if (FState <> tsNormal) and (Button = mbRight) then CancelDragSizing; // Sizing if (FState = tsNormal) and (Button = mbLeft) then begin if (FHitInfo.hitType = htBandEdge) and (FHitInfo.Band <> -1) then begin if ssDouble in Shift then DoBestFitBand(FHitInfo.Band) else begin SetState(tsBandSizing); FSizingPos := X; FPrevSizingPos := FSizingPos; DrawSizingLine; end; Exit; end; if (FHitInfo.hitType = htColumnEdge) and (FHitInfo.Column <> -1) then begin if ssDouble in Shift then DoBestFitColumn(FHitInfo.Column) else begin SetState(tsColumnSizing); FSizingPos := X; FPrevSizingPos := FSizingPos; DrawSizingLine; end; Exit; end; if (FHitInfo.hitType = htBandPanelEdge) then begin SetState(tsBandPanelSizing); FSizingPos := Y; FPrevSizingPos := FSizingPos; DrawSizingLine; Exit; end; if (FHitInfo.hitType = htHeaderPanelEdge) then begin SetState(tsHeaderPanelSizing); FSizingPos := Y; FPrevSizingPos := FSizingPos; DrawSizingLine; Exit; end; if (FHitInfo.hitType = htRowEdge) then begin SetState(tsRowSizing); FSizingPos := Y; FPrevSizingPos := FSizingPos; DrawSizingLine; Exit; end; // Drag Drop if (FHitInfo.hitType = htBand) then begin SetState(tsBandDown); FDownBandIndex := FHitInfo.Band; FDownBandPushed:= True; FPointDragging.X := X; FPointDragging.Y := Y; InvalidateBand(FDownBandIndex); end; if (FHitInfo.hitType = htColumn) then begin if IsAutoFilter and (FHotTrackInfo.HeaderHotTrack in [hhtDropDownButton, hhtDropDownButtonDisabled]) then begin if (FHotTrackInfo.HeaderHotTrack in [hhtDropDownButton]) then begin SetState(tsDropDownButtonDown); FDropDownButtonColumnIndex := FHitInfo.Column; FDropDownButtonColumnPushed := True; InvalidateColumn(FDropDownButtonColumnIndex); end; end else begin SetState(tsColumnDown); FDownColumnIndex := FHitInfo.Column; FDownColumnPushed := True; FPointDragging.X := X; FPointDragging.Y := Y; InvalidateColumn(FDownColumnIndex); end; end; if (FHitInfo.hitType = htBandButton) and CanBandButtonClicking then begin SetState(tsBandButtonDown); FBandButtonPushed := True; InvalidateBandButton; end; if (FHitInfo.hitType = htHeaderButton) and CanHeaderButtonClicking then begin SetState(tsHeaderButtonDown); FHeaderButtonPushed := True; InvalidateHeaderButton; end; end; if (Button = mbLeft) and (FHitInfo.hitType in [htStatusPanel]) then begin if PtInRect(GetStatusCloseButtonRect, Point(X, Y)) then begin SetState(tsStatusCloseButtonDown); FStatusCloseButtonPressed := True; InvalidateRect(GetStatusCloseButtonRect); end; end; PrevNewItemRowActive := FNewItemRowActive; if (State = tsNormal) and ((Button = mbLeft) or ((Button = mbRight) and (FHitInfo.hitType in NodeHitTests) )) then begin if (FHitInfo.hitType = htNewRowItem) then begin if FocusedNode = nil then DoBeginNewItemActive; if FocusedNode <> nil then begin OldFocusedColumn := FocusedColumn; if FHitInfo.Column <> -1 then NewColumn := GetFocusedVisibleIndex(FHitInfo.Column) else NewColumn := OldFocusedColumn; if NewColumn <> OldFocusedColumn then FocusedColumn := NewColumn; NewItemRowActive := True; FlagEditor := True; if (Button = mbLeft) and not IsRowSelect and (FHitInfo.Column <> -1) and (PrevNewItemRowActive = FNewItemRowActive) and (OldFocusedColumn = NewColumn) and (not FlagFocus) then begin if FState <> tsEditing then if ClickTimerID = -1 then ClickTimerID := SetTimer(Handle, 2, GetDoubleClickTime, nil); end; end; end else begin if ((FHitInfo.hitType = htButton) {and not (ssDouble in Shift)}{TODO ? Option}) or ((FHitInfo.hitType in NodeHitTests) and (ssDouble in Shift) {and Flag?}) then begin FreeClickTimer; if DblClkExpanding or (FHitInfo.hitType = htButton) then FHitInfo.Node.Expanded := not FHitInfo.Node.Expanded; {and Flag?} if (ssDouble in Shift) and CanDblClick then DblClick; Exit; end; if (FHitInfo.hitType in NodeHitTests) or (FHitInfo.hitType = htIndicator) then begin if (Button = mbLeft) and (FHitInfo.hitType <> htIndicator) then SetState(tsNodeDown); FDragNode := FHitInfo.Node; NewItemRowActive := False; BeginSelection; try OldFocusedNode := FocusedNode; OldFocusedColumn := FocusedColumn; if FHitInfo.Column <> -1 then NewColumn := GetFocusedVisibleIndex(FHitInfo.Column) else NewColumn := OldFocusedColumn; SetFocusedNode(FHitInfo.Node, NewColumn, True); FPointDragging.X := X; FPointDragging.Y := Y; if FocusedNode <> nil then // TODO DB if IsMultiSelect then begin FSelecting := False; if (ssCtrl in Shift) or (ssShift in Shift) then begin BeginSelection; try FlagCtrl := True; if (ssShift in Shift) then begin if (SelectionAnchor = nil) or not SelectionAnchor.IsVisible then SelectionAnchor := OldFocusedNode; if not (ssCtrl in Shift) and (SelectionAnchor <> nil) then begin //UnselectNodes ClearSelection; OldFocusedNode := SelectionAnchor; end; if OldFocusedNode <> nil then SelectNodes(OldFocusedNode, FocusedNode) else FocusedNode.Selected := not FocusedNode.Selected; OldFocusedNode := Nil; end else begin FocusedNode.Selected := not FocusedNode.Selected; SelectionAnchor := FocusedNode; end; finally EndSelection; end; Exit; end else if not FocusedNode.Selected then begin BeginSelection; try ClearSelection; FocusedNode.Selected := True; SelectionAnchor := FocusedNode; finally EndSelection; end; end else if (Button <> mbRight) then FlagSelect := True; end; finally EndSelection; end; if FHitInfo.hitType <> htIndicator then if (Button = mbLeft) and not IsRowSelect and (FHitInfo.Column <> -1) and (FHitInfo.hitType = htLabel) then begin if NeedShowButtonEdit(X, Y, OldFocusedNode = FocusedNode, FocusedAbsoluteIndex) then begin FState := tsNormal; ShowButtonEditorMouse(X, Y); end else if (OldFocusedNode = FocusedNode) and (OldFocusedColumn = FocusedColumn) and (not FlagFocus) then begin if FState <> tsEditing then if ClickTimerID = -1 then ClickTimerID := SetTimer(Handle, 2, GetDoubleClickTime, nil); end; end; end; end; end else if FState = tsEditing then CloseEditor; if (Button = mbLeft) and (ssDouble in Shift) and CanDblClick and (FHitInfo.hitType in DblClickHitTest) then DblClick; if (Button = mbMiddle) and (State = tsNormal) then DoScrolling; inherited MouseDown(Button, Shift, X, Y); end; procedure TCustomdxTreeList.MouseMove(Shift: TShiftState; X, Y: Integer); procedure CheckAndDrawSizingLine(X, Coord1, Coord2: Integer); begin if X < Coord1 then X := Coord1; if X > Coord2 then X := Coord2; if (FSizingPos <> X) then begin DrawSizingLine; FSizingPos := X; DrawSizingLine; end; end; var hInfo: TdxTreeListHitInfo; Coord1, Coord2, Coord: Integer; PrevPushed: Boolean; Node: TdxTreeListNode; // Mouse Scroll HInfoScroll: TdxTreeListHitInfo; DrawInfo: TdxGridDrawInfo; begin hInfo := GetHitInfo(Point(X, Y)); if not (ssLeft in Shift) and (State = tsNodeDown) then SetState(tsNormal); if (State = tsBandSizing) then begin GetBandResizeRanges(FHitInfo.Band, X, Coord, Coord1, Coord2); CheckAndDrawSizingLine(X, Coord1, Coord2); end; if (State = tsColumnSizing) then begin GetHeaderResizeRanges(FHitInfo.Column, X, Coord, Coord1, Coord2); CheckAndDrawSizingLine(X, Coord1, Coord2); end; if (State = tsBandPanelSizing) then begin GetBandPanelResizeRanges(Y, Coord1, Coord2); CheckAndDrawSizingLine(Y, Coord1, Coord2); end; if (State = tsHeaderPanelSizing) then begin GetHeaderPanelResizeRanges(Y, Coord1, Coord2); CheckAndDrawSizingLine(Y, Coord1, Coord2); end; if (State = tsRowSizing) then begin GetRowResizeRanges(FHitInfo.Node, Y, Coord1, Coord2); CheckAndDrawSizingLine(Y, Coord1, Coord2); end; if (State = tsBandDragging) then DoBandDragging; if (State = tsBandDown) and (FDownBandIndex <> -1) and CanBandDragging(FDownBandIndex) and ((X < FPointDragging.X - 5) or (X > FPointDragging.X + 5) or (Y < FPointDragging.Y - 5) or (Y > FPointDragging.Y + 5)) then begin FDragAbsoluteBandIndex := GetAbsoluteBandIndex(FDownBandIndex); StartDragBand(FDragAbsoluteBandIndex); end; if (FState = tsColumnDragging) then DoHeaderDragging; if (State = tsColumnDown) and (FDownColumnIndex <> -1) and CanHeaderDragging(FDownColumnIndex) and ((X < FPointDragging.X - 5) or (X > FPointDragging.X + 5) or (Y < FPointDragging.Y - 5) or (Y > FPointDragging.Y + 5)) then begin FDragAbsoluteHeaderIndex := FDownColumnIndex; StartDragHeader(FDragAbsoluteHeaderIndex); end; if State = tsNodeDown then begin if (DragMode = dmAutomatic) 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 := GetNodeAt(X, Y); if Node <> nil then begin if Node <> FocusedNode then begin if not FlagCtrl then ClearSelection; Node.Focused := True; end; Node.Selected := True; FlagCtrl := False; FlagSelect := False; BeginDrag(False); end; end; end else if IsMouseScroll and (Count > 0) then begin CalcRectInfo(DrawInfo); if (DrawInfo.CellsRect.Top <= Y) and (Y <= DrawInfo.CellsRect.Bottom) then begin HInfoScroll := GetHitInfo(Point(DrawInfo.CellsRect.Left, Y)); if HInfoScroll.Node <> nil then begin if ScrollNodeTimerID <> -1 then KillTimer(Handle, ScrollNodeTimerID); ScrollNodeTimerID := -1; HInfoScroll.Node.Focused := True; if IsMultiSelect then begin ClearSelection; if FocusedNode <> nil then FocusedNode.Selected := True; end; end end else begin ScrollNodeTimerTopFlag := Y < DrawInfo.CellsRect.Top; if ScrollNodeTimerTopFlag and not TopVisibleNode.Focused then TopVisibleNode.Focused := True else begin HInfoScroll.Node := GetAbsoluteNode(TopIndex + RowCount - 1); if not ScrollNodeTimerTopFlag and (HInfoScroll.Node <> nil) and not HInfoScroll.Node.Focused then HInfoScroll.Node.Focused := True; end; ScrollNodeTimerID := SetTimer(Handle, 1, 60, @MouseScrollTimerProc); end; end; end; if (State = tsBandDown) and (FDownBandIndex <> -1) then begin PrevPushed := FDownBandPushed; if (hInfo.hitType = htBand) and (hInfo.Band = FDownBandIndex) then FDownBandPushed := True else FDownBandPushed := False; if FDownBandPushed <> PrevPushed then InvalidateBand(FDownBandIndex); end; if (State = tsDropDownButtonDown) and (FDropDownButtonColumnIndex <> -1) then begin PrevPushed := FDropDownButtonColumnPushed; if (hInfo.hitType = htColumn) and (hInfo.Column = FDropDownButtonColumnIndex) and (FHotTrackInfo.HeaderHotTrack = hhtDropDownButton) then FDropDownButtonColumnPushed := True else FDropDownButtonColumnPushed := False; if FDropDownButtonColumnPushed <> PrevPushed then InvalidateColumn(FDropDownButtonColumnIndex); end; if (State = tsColumnDown) and (FDownColumnIndex <> -1) then begin PrevPushed := FDownColumnPushed; if (hInfo.hitType = htColumn) and (hInfo.Column = FDownColumnIndex) then FDownColumnPushed := True else FDownColumnPushed := False; if FDownColumnPushed <> PrevPushed then InvalidateColumn(FDownColumnIndex); end; if (State = tsBandButtonDown) then begin PrevPushed := FBandButtonPushed; if (hInfo.hitType = htBandButton) then FBandButtonPushed := True else FBandButtonPushed := False; if FBandButtonPushed <> PrevPushed then InvalidateBandButton; end; if (State = tsHeaderButtonDown) then begin PrevPushed := FHeaderButtonPushed; if (hInfo.hitType = htHeaderButton) then FHeaderButtonPushed := True else FHeaderButtonPushed := False; if FHeaderButtonPushed <> PrevPushed then InvalidateHeaderButton; end; CheckHotTrackNode(hInfo); inherited MouseMove(Shift, X, Y); end; procedure TCustomdxTreeList.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var Coord1, Coord2, Coord: Integer; OldDownIndex: Integer; hInfo : TdxTreeListHitInfo; FlagClick : Boolean; begin BeginSelection; try hInfo := GetHitInfo(Point(X, Y)); if (FState = tsBandSizing) then begin DrawSizingLine; if FHitInfo.Band <> -1 then begin GetBandResizeRanges(FHitInfo.Band, FSizingPos, Coord, Coord1, Coord2); if FSizingPos < Coord1 then FSizingPos := Coord1; if FSizingPos > Coord2 then FSizingPos := Coord2; end; if FPrevSizingPos <> FSizingPos then begin if not IsAutoWidth then ScaledBandHeaderWidth(FHitInfo.Band, FSizingPos - Coord + 2) else ChangedBandAutoWidth(FHitInfo.Band, FSizingPos - Coord + 2); DoChangedColumnsWidth; end; SetState(tsNormal); end; if (FState = tsColumnSizing) then begin DrawSizingLine; if FHitInfo.Column <> -1 then begin GetHeaderResizeRanges(FHitInfo.Column, FSizingPos, Coord, Coord1, Coord2); if FSizingPos < Coord1 then FSizingPos := Coord1; if FSizingPos > Coord2 then FSizingPos := Coord2; end; if FPrevSizingPos <> FSizingPos then begin if IsBandHeaderWidth and not IsAutoWidth and (GetHeaderRowCount(FHitInfo.Band) <= 1) then ScaledHeaderBandWidth(FHitInfo.Band, FHitInfo.Column, FSizingPos - Coord + 1) else ChangedHeaderAutoWidth(FHitInfo.Band, FHitInfo.Column, FSizingPos - Coord + 1); DoChangedColumnsWidth; end; SetState(tsNormal); end; if (FState = tsBandPanelSizing) then begin DrawSizingLine; ChangedBandRowCount(CalcBandPanelRowCount(FSizingPos)); SetState(tsNormal); end; if (FState = tsRowSizing) then begin DrawSizingLine; if (FPrevSizingPos <> FSizingPos) and (FHitInfo.Node <> nil) then ChangedRowHeight(CalcNearestRowHeight(FHitInfo.Node, FSizingPos - GetRectNode(FHitInfo.Node).Top)); SetState(tsNormal); end; if (FState = tsHeaderPanelSizing) then begin DrawSizingLine; ChangedHeaderMaxRowCount(CalcHeaderPanelRowCount(FSizingPos)); SetState(tsNormal); end; if State = tsBandDown then begin OldDownIndex := FDownBandIndex; CancelDragSizing; if (hInfo.hitType = htBand) and (hInfo.Band = OldDownIndex) then DoBandClick(OldDownIndex); end; if (State = tsBandDragging) then EndDragBand(True); if State = tsDropDownButtonDown then begin OldDownIndex := FDropDownButtonColumnIndex; CancelDragSizing; if (hInfo.hitType = htColumn) and (hInfo.Column = OldDownIndex) and (FHotTrackInfo.HeaderHotTrack = hhtDropDownButton) and not (csDesigning in ComponentState) then begin FDropDownButtonColumnIndex := OldDownIndex; try DoHeaderDropDownButtonClick(OldDownIndex); finally FDropDownButtonColumnIndex := -1; end; end; end; if State = tsStatusCloseButtonDown then begin CancelDragSizing; if FStatusCloseButtonActive then DoStatusCloseButtonClick; end; if State = tsColumnDown then begin OldDownIndex := FDownColumnIndex; CancelDragSizing; if (hInfo.hitType = htColumn) and (hInfo.Column = OldDownIndex) then begin FlagMultiSort := IsMultiSort and (ssShift in Shift); FlagClearSort := (ssCtrl in Shift); try DoHeaderClick(OldDownIndex); finally FlagClearSort := False; FlagMultiSort := False; end; end; end; if (State = tsColumnDragging) then EndDragHeader(True); if (State = tsBandButtonDown) then begin if FBandButtonPushed then OldDownIndex := 1 else OldDownIndex := -1; CancelDragSizing; if OldDownIndex <> -1 then DoBandButtonClick; end; if (State = tsHeaderButtonDown) then begin if FHeaderButtonPushed then OldDownIndex := 1 else OldDownIndex := -1; CancelDragSizing; if OldDownIndex <> -1 then DoHeaderButtonClick; end; if FlagSelect then begin ClearSelection; FocusedNode.Selected := True; SelectionAnchor := FocusedNode; FlagSelect := False; end; if FState in [tsEditing, tsNodeDragging, tsNodeDown] then FlagClick := True else FlagClick := False; if (FlagClick or FlagEditor) and IsImmediateEditor and not IsRowSelect and (hInfo.Column <> -1) and (FHitInfo.Column = hInfo.Column) and (FHitInfo.Row = hInfo.Row) and (FHitInfo.hitType = hInfo.hitType) and (hInfo.hitType in [htLabel, htNewRowItem]) and (Button = mbLeft) and ((hInfo.Node = FocusedNode) or (FHitInfo.hitType = htNewRowItem))then begin FState := tsNormal; if not (ssShift in Shift) and not (ssCtrl in Shift) then ShowEditorMouse(X, Y); end; FlagEditor := False; if State = tsNodeDown then SetState(tsNormal); if FlagClick then Click; inherited MouseUp(Button, Shift, X, Y); finally EndSelection; end; end; procedure TCustomdxTreeList.Notification(AComponent: TComponent; Operation: TOperation); begin inherited Notification(AComponent, Operation); if Operation = opRemove then begin if AComponent = Images then Images := nil; if AComponent = StateImages then StateImages := nil; end; end; procedure TCustomdxTreeList.Paint; type TBrushInfo = record Brush: HBRUSH; Color: TColor; end; PBrushesInfo = ^TBrushesInfo; TBrushesInfo = array [0..dxGridMaxDrawItems - 1] of TBrushInfo; var DrawInfo: TdxGridDrawInfo; BandBrush: HBRUSH; HeaderBrush: HBRUSH; GroupBrush: HBRUSH; BackgroundBrush: HBRUSH; PanelBrush: HBRUSH; HighlightBrush: HBRUSH; TreeLineBrush: HBRUSH; HideSelectionBrush: HBRUSH; LevelBrush: HBRUSH; FooterBrush: HBRUSH; FixedBandLineBrush: HBRUSH; // clip region FlagClip, FlagRgn, IsClipRgnExists: Boolean; Rgn, PrevClipRgn: HRGN; PBrushes: PBrushesInfo; BrushIndex: Integer; // New ACellBkColor: TColor; ACellBkBrush: HBRUSH; APanelBrushColor: TColor; function GetLookAndFeelStyle: TdxLookAndFeel; begin Result := LookAndFeel; if Result = lfUltraFlat then Result := lfFlat; end; function GetLevelBrush(ALevel: Integer; var AColor: TColor): HBRUSH; begin Result := GroupBrush; if AssignedLevelColorEvent then begin DoGetLevelColor(ALevel, AColor); if AColor <> FGroupColor then begin if LevelBrush <> 0 then DeleteObject(LevelBrush); LevelBrush := CreateSolidBrush(ColorToRGB(AColor)); Result := LevelBrush; end; end; end; procedure GetBkBrush(Node: TdxTreeListNode; ASelected, AFocused, AGroup, AHasChildren: Boolean; ALevel, AIndex: Integer; var AColor, ATextColor: TColor; var ABrush: HBRUSH); begin if not AFocused and (FDragObject <> nil) and (Node <> nil) and Node.Focused then begin AColor := FHighlightColor; //clHighlight; ATextColor := FHighlightTextColor; //clHighlightText; ABrush := HighlightBrush; end else if ASelected and not (HideSelection and not AFocused) then begin if AFocused then begin AColor := FHighlightColor; //clHighlight; ATextColor := FHighlightTextColor; //clHighlightText; ABrush := HighlightBrush; end else begin AColor := HideSelectionColor; ATextColor := HideSelectionTextColor; ABrush := HideSelectionBrush; end; end else begin if not FPaintStandard and (AGroup or AHasChildren) then begin AColor := FGroupColor; if FGroupTextColor <> clNone then ATextColor := FGroupTextColor else ATextColor := Self.Font.Color; ABrush := GetLevelBrush(ALevel, AColor); end else begin if (AIndex <> -1) and (IsExistColumnFont(DrawInfo.HeadersInfo^[AIndex].AbsoluteIndex)) then ATextColor := GetColumnFont(DrawInfo.HeadersInfo^[AIndex].AbsoluteIndex).Color else ATextColor := Self.Font.Color; if ((not ASelected) or (HideSelection and not AFocused)) and (AIndex <> -1) and (PBrushes^[AIndex].Brush <> 0) then begin AColor := PBrushes^[AIndex].Color; ABrush := PBrushes^[AIndex].Brush; end else begin ABrush := BackgroundBrush; AColor := Self.Color; end; end; end; end; procedure GetCellBkBrush(AIndex: Integer; var AColor: TColor; var ABrush: HBRUSH); begin if (AIndex <> -1) and (PBrushes^[AIndex].Brush <> 0) then begin AColor := PBrushes^[AIndex].Color; ABrush := PBrushes^[AIndex].Brush; end else begin ABrush := BackgroundBrush; AColor := Self.Color; end; end; procedure SaveRegion(const AClipRect: TRect); begin PrevClipRgn := CreateRectRgn(0, 0, 0, 0); IsClipRgnExists := GetClipRgn(Canvas.Handle, PrevClipRgn) = 1; Rgn := CreateRectRgnIndirect(AClipRect); if IsClipRgnExists then CombineRgn(Rgn, PrevClipRgn, Rgn, RGN_AND); SelectClipRgn(Canvas.Handle, Rgn); DeleteObject(Rgn); FlagRgn := True; end; procedure RestoreRegion; begin if not FlagRgn then Exit; if IsClipRgnExists then SelectClipRgn(Canvas.Handle, PrevClipRgn) else SelectClipRgn(Canvas.Handle, 0); DeleteObject(PrevClipRgn); FlagRgn := False; end; procedure SetPoints(P: PIntArray; Index: Integer; X1, Y1, X2, Y2: Integer); begin Index := Index * 4; P^[Index] := X1; P^[Index + 1] := Y1; P^[Index + 2] := X2; P^[Index + 3] := Y2; end; procedure DrawGrPanel; begin with Canvas, DrawInfo do if RectVisible(Handle, GroupPanelRect) then begin DrawGroupPanel(Canvas, GroupPanelRect, HeaderBrush, PanelBrush); end; end; procedure DrawFooterFrame(ADC: HDC; ARect: TRect); begin if LookAndFeel = lfUltraFlat then FrameRect(ADC, ARect, GetSysColorBrush(COLOR_BTNSHADOW)) else DrawEdge(ADC, ARect, BDR_SUNKENOUTER, BF_RECT); end; procedure DrawCaptionButton(ADC: HDC; var ARect: TRect; ABrush: HBRUSH; ADown: Boolean; ALookAndFeel: TdxLookAndFeel); begin if LookAndFeel = lfUltraFlat then begin DrawEdge(ADC, ARect, BDR_SUNKENOUTER, BF_TOP or BF_BOTTOM or BF_RIGHT or BF_FLAT or BF_ADJUST); FillRect(ADC, ARect, ABrush); if ADown then with ARect do BitBlt(ADC, Left, Top, Right - Left, Bottom - Top, 0, 0, 0, DSTINVERT); end else DrawBandButtonEx(ADC, ARect, ABrush, ADown, hbNormal, ALookAndFeel); end; procedure DrawBands; var S: string; R, RClip: TRect; i, BIndex: Integer; ExistEvent, Done: Boolean; AAlignment: TAlignment; AColor: TColor; AFont: TFont; Br: HBRUSH; // clip rect IsClipRgnExists: Boolean; PrevRgn, Rgn: HRGN; begin with Canvas, DrawInfo do begin // draw band button if RectVisible(Handle, BandButtonRect) then DrawCaptionButton(Handle, BandButtonRect, BandBrush, FBandButtonPushed{Down}, LookAndFeel{GetLookAndFeelStyle}); // DrawBandButtonEx(Handle, BandButtonRect, BandBrush, FBandButtonPushed{Down}, hbNormal, // LookAndFeel{GetLookAndFeelStyle}); // draw bands if RectVisible(Handle, BandRect) then begin if BandsInfo <> nil then begin Font.Assign(BandFont); SetTextColor(Handle, ColorToRGB(BandFont.Color)); for i := 0 to BandCount - 1 do begin BIndex := BandsInfo^[i].Index; S := GetBandText(BIndex); AAlignment := GetBandAlignment(BIndex); R := BandsInfo^[i].BandRect; RClip := BandsInfo^[i].BandClipRect; Br := BandBrush; Done := False; // begin custom draw ExistEvent := AssignedDrawBandEvent(BIndex); if ExistEvent then begin FSaveFont.Assign(Font); AColor := BandColor; AFont := Canvas.Font; // set clip rect IsClipRgnExists := False; PrevRgn := 0; Rgn := 0; if not EqualRect(R, RCLip) then begin PrevRgn := CreateRectRgn(0, 0, 0, 0); IsClipRgnExists := GetClipRgn(Handle, PrevRgn) = 1; Rgn := CreateRectRgnIndirect(RClip); SelectClipRgn(Handle, Rgn) end; DoDrawBand(BIndex, Canvas, R, RClip, S, AColor, AFont, AAlignment, Done); if not Done then begin if ColorToRGB(AColor) <> ColorToRGB(BandColor) then begin Brush.Color := AColor; Br := Brush.Handle; end; end; // restore prev clip recct if PrevRgn <> 0 then begin if IsClipRgnExists then SelectClipRgn(Handle, PrevRgn) else SelectClipRgn(Handle, 0); DeleteObject(PrevRgn); end; if Rgn <> 0 then DeleteObject(Rgn); end; if not Done then DrawBandEx(Handle, R, RClip, Br, DrawBitmap, S, FDownBandPushed and (FDownBandIndex = BIndex){ADown}, (FBandRowCount > 1){AMultiLine}, AAlignment, csNone{no sorted}, nil {no glyph}, hbNormal, LookAndFeel{GetLookAndFeelStyle}, []{TODO Ultra}); // end custom draw if ExistEvent then Font.Assign(FSaveFont); end; end; end; // draw fixed lines if not IsRectEmpty(FixedBandLeftRect) and RectVisible(Handle, FixedBandLeftRect) then begin with FixedBandLeftRect do R := Rect(Right - FFixedBandLineWidth, Top, Right, Bottom); Windows.FillRect(Handle, R, FixedBandLineBrush{GetSysColorBrush(COLOR_WINDOWFRAME)}); end; if not IsRectEmpty(FixedBandRightRect)and RectVisible(Handle, FixedBandRightRect) then begin with FixedBandRightRect do R := Rect(Left, Top, Left + FFixedBandLineWidth, Bottom); Windows.FillRect(Handle, R, FixedBandLineBrush{GetSysColorBrush(COLOR_WINDOWFRAME)}); end; end; end; procedure DrawHeaders; var S: string; R, RClip: TRect; I: Integer; ExistEvent, Done: Boolean; AAlignment: TAlignment; AColor: TColor; AFont: TFont; AGlyph: TBitmap; ASorted: TdxTreeListColumnSort; ADropDownButtonState: TdxHeaderDropDownButtonState; Br: HBRUSH; ButtonStyle: TdxHeaderButtonStyle; // clip rect IsClipRgnExists: Boolean; PrevRgn, Rgn: HRGN; begin with Canvas, DrawInfo do begin // draw header button if RectVisible(Handle, HeaderButtonRect) then DrawCaptionButton(Handle, HeaderButtonRect, HeaderBrush, FHeaderButtonPushed{Down}, LookAndFeel{GetLookAndFeelStyle}); // draw headers if RectVisible(Handle, HeaderRect) then begin if HeadersInfo <> nil then begin Font.Assign(HeaderFont); SetTextColor(Handle, ColorToRGB(HeaderFont.Color)); for I := 0 to HeaderCount - 1 do with HeadersInfo^[I] do begin AAlignment := GetHeaderAlignment(AbsoluteIndex); if IsExistHeaderGlyph(AbsoluteIndex) then AGlyph := GetHeaderGlyph(AbsoluteIndex) else AGlyph := nil; S := GetHeaderText(AbsoluteIndex); ASorted := GetHeaderSorted(AbsoluteIndex); R := HeaderRect; RClip := HeaderClipRect; Br := HeaderBrush; ADropDownButtonState := GetHeaderDropDownButtonState(AbsoluteIndex); Done := False; // begin custom draw ExistEvent := AssignedDrawHeaderEvent(AbsoluteIndex); if ExistEvent then begin FSaveFont.Assign(Font); AColor := HeaderColor; AFont := Canvas.Font; // set clip rect IsClipRgnExists := False; PrevRgn := 0; Rgn := 0; if not EqualRect(R, RCLip) then begin PrevRgn := CreateRectRgn(0, 0, 0, 0); IsClipRgnExists := GetClipRgn(Handle, PrevRgn) = 1; Rgn := CreateRectRgnIndirect(RClip); SelectClipRgn(Handle, Rgn) end; DoDrawHeader(AbsoluteIndex, Canvas, R, RClip, S, AColor, AFont, AAlignment, ASorted, Done); if not Done then begin if ColorToRGB(AColor) <> ColorToRGB(HeaderColor) then begin Brush.Color := AColor; Br := Brush.Handle; end; end; // restore prev clip recct if PrevRgn <> 0 then begin if IsClipRgnExists then SelectClipRgn(Handle, PrevRgn) else SelectClipRgn(Handle, 0); DeleteObject(PrevRgn); end; if Rgn <> 0 then DeleteObject(Rgn); end; if not Done then begin ButtonStyle := hbNormal; if True {Options} and not ((FirstColumn = LastColumn) and FirstColumn) then begin if FirstColumn then ButtonStyle := hbRight else if LastColumn then ButtonStyle := hbLeft else ButtonStyle := hbLeftRight; end; DrawBandEx(Handle, R, RClip, Br, DrawBitmap, S, FDownColumnPushed and (FDownColumnIndex = AbsoluteIndex){ADown}, (LineCount > 1) or (FHeaderLineCount > 1){AMultiLine}, AAlignment, ASorted, AGlyph, ButtonStyle, LookAndFeel, ADropDownButtonState); end; if not IsRectEmpty(HeaderEmptyRect) then Windows.FillRect(Handle, HeaderEmptyRect, PanelBrush); // end custom draw if ExistEvent then Font.Assign(FSaveFont); end; end; // Empty Headers if EmptyRectsInfo <> nil then begin for I := 0 to EmptyRectCount - 1 do with EmptyRectsInfo^[I] do if not IsRectEmpty(EmptyRect) then Windows.FillRect(Handle, EmptyRect, PanelBrush); end; end; end; end; procedure DrawNewItemRow; var R, R1, RClip: TRect; i: Integer; Points, Strokes: PIntArray; MaxLines, LinesCount: Integer; Br: HBRUSH; AColor, ATextColor: TColor; IsFocused, ASelected: Boolean; begin with Canvas, DrawInfo do begin if RectVisible(Handle, NewItemRowRect) then begin // draw separator R := Rect(CellsRect.Left, NewItemRowRect.Bottom - FNewItemRowSeparatorHeight, CellsRect.Left + GetBandTotalWidth, NewItemRowRect.Bottom); OffsetRect(R, -LeftCoord, 0); if not IsRectEmptyEx(FixedBandLeftRect) then R.Left := CellsRect.Left; if not IsRectEmptyEx(FixedBandRightRect) and (R.Right > CellsRect.Right) then R.Right := CellsRect.Right; RClip := Rect(CellsRect.Left, NewItemRowRect.Top, CellsRect.Right, NewItemRowRect.Bottom); SaveRegion(RClip); DrawBandButton(Handle, R, HeaderBrush, False{Down}, hbNormal, GetLookAndFeelStyle); RestoreRegion; // draw indicator if FIndicatorWidth > 0 then begin R1 := Rect(NewItemRowRect.Left, NewItemRowRect.Top, NewItemRowRect.Left + FIndicatorWidth, NewItemRowRect.Bottom); DrawIndicatorEx(Handle, R1, R1, HeaderBrush, DrawBitmap, ikInsert, LookAndFeel {GetLookAndFeelStyle}); // TODO end; // draw cells MaxLines := 1; if FShowGrid and FShowPreviewGrid then Inc(MaxLines, HeaderCount * 2 + EmptyRectCount); // grid lines memory allocating Points := AllocMem(MaxLines * SizeOf(TPoint) * 2); Strokes := AllocMem(MaxLines * SizeOf(Integer)); for i := 0 to MaxLines - 1 do Strokes^[i] := 2; LinesCount := 0; try FlagClip := ((not IsRectEmptyEx(FixedBandLeftRect)) or (not IsRectEmptyEx(FixedBandRightRect)) or (LeftCoord <> 0 )) and ((CellsRect.Right - CellsRect.Left) < GetBandTotalWidth); RClip := Rect(CellsRect.Left, NewItemRowRect.Top, CellsRect.Right, NewItemRowRect.Top + FRowHeight); if not IsRectEmptyEx(FixedBandLeftRect) then RClip.Left := FixedBandLeftRect.Right else begin Dec(RClip.Left, LeftCoord); if RClip.Left < CellsRect.Left then RClip.Left := CellsRect.Left; end; if not IsRectEmptyEx(FixedBandRightRect) then RClip.Right := FixedBandRightRect.Left; // set Font Font.Assign(Self.Font); IsFocused := IsActiveControl or ((State = tsEditing) and (InplaceEditor <> nil) and (InplaceEditor.IsFocused)); for i := 0 to HeaderCount - 1 do with HeadersInfo^[i] do begin if FlagClip then // set clip region begin if not ((BandIndex = FixedBandLeftIndex) or (BandIndex = FixedBandRightIndex)) and not FlagRgn then // set region SaveRegion(RClip) else if FlagRgn and ((BandIndex = FixedBandLeftIndex) or (BandIndex = FixedBandRightIndex)) then // restore prev rgn RestoreRegion; end; R := Rect(HeaderRect.Left, NewItemRowRect.Top, HeaderRect.Right, NewItemRowRect.Top + FRowHeight - Byte(FShowGrid and FShowPreviewGrid)); if not (((BandIndex = FixedBandLeftIndex) or (BandIndex = FixedBandPrevRightIndex)) and LastColumn) then Dec(R.Right, Byte(FShowGrid and FShowPreviewGrid)); if FShowGrid and not FShowPreviewGrid and LastColumn then begin if (BandCount > 1) and (BandIndex = BandsInfo^[BandCount - 1].Index) or (BandCount = 1) then Dec(R.Right, 1{SizeGrid}); end; ASelected := IsNewItemRowActive and (IsRowSelect or (IsMultiSelect and not IsInvertSelect) or ((FocusedAbsoluteIndex = AbsoluteIndex) and not IsInvertSelect) or ((FocusedAbsoluteIndex <> AbsoluteIndex) and IsInvertSelect)); if ASelected and HideSelection and not IsFocused then ASelected := False; // TODO ? // TODO PAINT1 GetBkBrush(FocusedNode, ASelected, IsFocused, False, False, 0, I, AColor, ATextColor, Br); GetCellBkBrush(I, ACellBkColor, ACellBkBrush); DrawCellEx(Canvas, R, DrawBitmap, FocusedNode, AbsoluteIndex, ASelected, False{Focused TODO}, AColor, ATextColor, Br, MultiLine, ckNewItemRow, LeftEdgeColumn, RightEdgeColumn, ACellBkColor, ACellBkBrush); // Draw Focus if ASelected and not (IsRowSelect or IsInvertSelect) and (FocusedAbsoluteIndex = AbsoluteIndex) and ((IsFocused and not HideDrawFocusRect) or (not IsFocused and not HideFocusRect)) then if IsFocused then DrawFocused(Handle, R) else if (FDragObject = nil) then DrawFramed(Handle, R); // grid horz line if FShowGrid and FShowPreviewGrid then begin SetPoints(Points, LinesCount, R.Left, R.Bottom, R.Right, R.Bottom); if FlagRgn then begin if (Points^[LinesCount * 4] < RClip.Left) then Points^[LinesCount * 4] := RClip.Left; if (Points^[LinesCount * 4 + 2] > RClip.Right) then Points^[LinesCount * 4 + 2] := RClip.Right; end; Inc(LinesCount); end; // grid vert line if FShowGrid and FShowPreviewGrid and not (((BandIndex = FixedBandLeftIndex) or (BandIndex = FixedBandPrevRightIndex)) and LastColumn) then begin if not (FlagRgn and ((R.Right < RClip.Left) or (R.Right > RClip.Right))) then begin SetPoints(Points, LinesCount, R.Right, R.Top, R.Right, R.Bottom + 1); Inc(LinesCount); end; end; end; // Draw Focus - if RowSelect if IsNewItemRowActive and (IsRowSelect or IsInvertSelect) and ((IsFocused and not HideDrawFocusRect) or not IsFocused and not HideFocusRect) then begin R := Rect(CellsRect.Left, NewItemRowRect.Top, CellsRect.Left + GetBandTotalWidth - Byte(FShowGrid), NewItemRowRect.Top + FRowHeight - Byte(FShowGrid and FShowPreviewGrid)); if IsRectEmptyEx(FixedBandLeftRect) then OffsetRect(R, - LeftCoord, 0); if not IsRectEmptyEx(FixedBandRightRect) then if R.Right > CellsRect.Right - Byte(FShowGrid) then R.Right := CellsRect.Right - Byte(FShowGrid); if IsFocused then DrawFocused(Handle, R) else if (FDragObject = nil) then DrawFramed(Handle, R); end; // vert right line if FShowGrid then begin SetPoints(Points, LinesCount, EdgeX, NewItemRowRect.Top, EdgeX, NewItemRowRect.Top + FRowHeight); Inc(LinesCount); end; // restore prev rgn if FlagRgn then RestoreRegion; // Empty Headers if EmptyRectsInfo <> nil then begin for i := 0 to EmptyRectCount - 1 do with EmptyRectsInfo^[i] do begin R := Rect(EmptyRect.Left, NewItemRowRect.Top, EmptyRect.Right, NewItemRowRect.Top + FRowHeight); // grid vert line if FShowGrid and FShowPreviewGrid and not ((BandIndex = FixedBandLeftIndex) or (BandIndex = FixedBandPrevRightIndex)) then begin if not ((R.Right < RClip.Left) or (R.Right > RClip.Right)) and not ClippingFlag then // (BandsInfo^[BandIndex].BandRect.Right <= BandsInfo^[BandIndex].BandClipRect.Right) then begin SetPoints(Points, LinesCount, R.Right - 1, R.Top, R.Right - 1, R.Bottom); Inc(LinesCount); Dec(R.Right); end; end; if not IsRectEmpty(R) then Windows.FillRect(Handle, R, BackgroundBrush); end; end; // draw grid if FShowGrid then begin Canvas.Pen.Color := GetGridColor(Self.Color); //clBtnShadow PolypolyLine(Canvas.Handle, Points^, Strokes^, LinesCount); end; finally FreeMem(Strokes); FreeMem(Points); end; end; end; end; procedure DrawIndicator; var i, Y: Integer; R1, R2: TRect; begin with Canvas, DrawInfo do begin if RectVisible(Handle, IndicatorRect) and (RowsInfo <> nil) then begin Y := CellsRect.Top; for i := 0 to RowCount - 1 do with RowsInfo^[i] do begin R1 := Rect(IndicatorRect.Left, Y, IndicatorRect.Right, Y + RowHeight); R2 := R1; if not IsRectEmpty(FooterRect) then if R2.Bottom > FooterRect.Top then R2.Bottom := FooterRect.Top; DrawIndicatorEx(Handle, R1, R2, HeaderBrush, DrawBitmap, IndicatorKind, LookAndFeel {GetLookAndFeelStyle}); // TODO Inc(Y, RowHeight); end; with IndicatorRect do ExcludeClipRect(Handle, Left, Top, Right, Bottom); end; end; end; procedure DrawFooter; var R, RClip: TRect; i, X, Ind, H, YTop: Integer; begin with Canvas, DrawInfo do begin if RectVisible(Handle, FooterRect) then begin // draw frame R := FooterRect; if IsRectEmptyEx(FixedBandLeftRect) and (LeftCoord <> 0) then Dec(R.Left, Byte(not FFlat) + 1); if IsRectEmptyEx(FixedBandRightRect) and (CellsRect.Left + GetBandTotalWidth - LeftCoord > R.Right) then Inc(R.Right, Byte(not FFlat) + 1); if not FFlat then begin Windows.FrameRect(Handle, R, GetSysColorBrush(COLOR_WINDOWFRAME)); InflateRect(R, -1, -1); Dec(R.Left); DrawEdge(Handle, R, BDR_RAISEDINNER, BF_RECT); end else begin DrawEdge(Handle, R, BDR_SUNKENOUTER, BF_TOP); Inc(R.Top); if LookAndFeel = lfUltraFlat then Windows.FillRect(Handle, R, HeaderBrush) else DrawEdge(Handle, R, BDR_RAISEDINNER, BF_RECT); end; InflateRect(R, -1, -1); Windows.FillRect(Handle, R, HeaderBrush); YTop := R.Top; // draw footer cells try FlagClip := ((not IsRectEmptyEx(FixedBandLeftRect)) or (not IsRectEmptyEx(FixedBandRightRect)) or (LeftCoord <> 0 )) and ((CellsRect.Right - CellsRect.Left) < GetBandTotalWidth); RClip := Rect(CellsRect.Left, FooterRect.Top, CellsRect.Right, FooterRect.Bottom); if not IsRectEmptyEx(FixedBandLeftRect) then RClip.Left := FixedBandLeftRect.Right else begin Dec(RClip.Left, LeftCoord); if RClip.Left < CellsRect.Left - FIndicatorWidth then RClip.Left := CellsRect.Left - FIndicatorWidth; end; if not IsRectEmptyEx(FixedBandRightRect) then RClip.Right := FixedBandRightRect.Left; FlagRgn := False; // set Font Font.Assign(Self.Font); // SetTextColor(Handle, ColorToRGB(Self.Font.Color)); for i := 0 to HeaderCount - 1 do with HeadersInfo^[i] do begin if FlagClip then // set clip region begin if not ((BandIndex = FixedBandLeftIndex) or (BandIndex = FixedBandRightIndex)) and not FlagRgn then // set region SaveRegion(RClip) else if FlagRgn and ((BandIndex = FixedBandLeftIndex) or (BandIndex = FixedBandRightIndex)) then // restore prev rgn RestoreRegion; end; X := HeaderRect.Left; if IsRectEmptyEx(FixedBandLeftRect) then Inc(X, LeftCoord); if (BandIndex = 0) and (X < CellsRect.Left) then Ind := CellsRect.Left - X else Ind := 0; H := LineCount * FFooterRowHeight; if HeaderRect.Right > (HeaderRect.Left + Ind) then // if Visible begin R := Rect(HeaderRect.Left + Ind, YTop + FFooterRowHeight * RowIndex, HeaderRect.Right, YTop + FFooterRowHeight * RowIndex + H); InflateRect(R, -1, -1); if (BandIndex = 0) and (ColIndex = 0) then Inc(R.Left); if LastColumn and (BandIndex = BandsInfo^[BandCount - 1].Index) then Dec(R.Right, 2); if IsExistFooterCell(AbsoluteIndex) then begin DrawFooterFrame(Canvas.Handle, R); // DrawEdge(Canvas.Handle, R, BDR_SUNKENOUTER, BF_RECT); // TODO REMOVE // Windows.FrameRect(Canvas.Handle, R, GetSysColorBrush(COLOR_BTNSHADOW)); InflateRect(R, -1, -1); SetBkColor(Canvas.Handle, ColorToRGB(HeaderColor)); SetTextColor(Canvas.Handle, ColorToRGB(Self.Font.Color)); DrawCell(Canvas, R, DrawBitmap, nil{footer}, AbsoluteIndex, -1, False, False, HeaderColor, HeaderBrush, LineCount > 1, ckFooter {footer}, False, False); end; end; end; finally // restore prev rgn if FlagRgn then RestoreRegion; end; with FooterRect do ExcludeClipRect(Handle, Left, Top, Right, bottom); end; end; end; procedure DrawStatus; procedure DrawCloseButton(ADC: HDC; ARect: TRect; ASelected, APushed: Boolean); var ABkBrush: HBRUSH; APenColor: TColor; APrevPen: HPEN; begin if APushed then begin ABkBrush := GetSysColorBrush(COLOR_WINDOWFRAME); APenColor := clWindow; end else if ASelected then begin ABkBrush := GetSysColorBrush(COLOR_WINDOW); APenColor := clWindowFrame; end else begin ABkBrush := GetSysColorBrush(COLOR_BTNFACE); APenColor := clBtnText; end; Windows.FillRect(ADC, ARect, ABkBrush); // cross APrevPen := SelectObject(ADC, CreatePen(PS_SOLID, 1, ColorToRGB(APenColor))); InflateRect(ARect, -2, -2); with ARect do begin { \ } MoveToEx(ADC, Left, Top, nil); LineTo(ADC, Right - 2, Bottom - 1); LineTo(ADC, Right - 1, Bottom - 1); LineTo(ADC, Left + 1, Top); LineTo(ADC, Left, Top); { / } MoveToEx(ADC, Right - 1, Top, nil); LineTo(ADC, Left + 1, Bottom - 1); LineTo(ADC, Left, Bottom - 1); LineTo(ADC, Right - 2, Top); LineTo(ADC, Right, Top); end; DeleteObject(SelectObject(ADC, APrevPen)); end; var AShowStatusButton: Boolean; R: TRect; S: string; begin with Canvas, DrawInfo do if RectVisible(Handle, StatusRect) then begin AShowStatusButton := GetStatusButtonVisible; S := GetStatusText; // Text Font.Assign(Self.Font); //Font.Style := Font.Style + [fsBold]; R := StatusRect; InflateRect(R, -2, -2); if AShowStatusButton then Inc(R.Left, dxGridStatusCloseButtonWidth); DrawTextRect(Handle, S, Length(S), StatusRect, R, DX_DTR_LEFT or DX_DTR_SINGLELINE or DX_DTR_VCENTER, PanelBrush, Font.Handle, ColorToRGB(APanelBrushColor), ColorToRGB(clBtnHighlight), nil); // Button if AShowStatusButton then begin with StatusRect do R := Rect(Left, Top, Left + dxGridStatusCloseButtonSizeX, Top + dxGridStatusCloseButtonSizeY); OffsetRect(R, 3, (StatusRect.Bottom - StatusRect.Top - dxGridStatusCloseButtonSizeY) div 2); DrawCloseButton(Handle, R, FStatusCloseButtonActive and not FStatusCloseButtonPressed, FStatusCloseButtonActive and FStatusCloseButtonPressed); end; with StatusRect do ExcludeClipRect(Handle, Left, Top, Right, bottom); end; end; procedure DrawCells; var I, J, Y, H, Ind, SizeGrid, StartLineX: Integer; XPos1, XPos2: Integer; R, RClip: TRect; // lines Points, Strokes: PIntArray; MaxLines, LinesCount: Integer; Br: HBRUSH; CorrectY, DeltaButton, YPos1, YPos2: Integer; LevelNode: TdxTreeListNode; X, YTop, YBottom, YCenter: Integer; K, FooterCount: Integer; TreeBrush: HBRUSH; PrevBkColor: TColorRef; AColor, ATextColor: TColor; IsFocused: Boolean; NodeLevel: Integer; FlagSelected: Boolean; procedure CheckCoord(var Value: Integer; Limit: Integer); begin if Value > Limit then Value := Limit; end; function GetStartLineCoord(Node: TdxTreeListNode; Index: Integer): Integer; begin with DrawInfo do begin Result := Node.Level * FIndent; if Node.Expanded then Inc(Result, FIndent - 1) else if not Node.HasChildren and Node.IsLast then Dec(Result, FIndent); if (Index + 1) < RowCount then if RowsInfo^[Index + 1].Node.Level < RowsInfo^[Index].Node.Level then Result := RowsInfo^[Index + 1].Node.Level * FIndent; if (Node = LastNode) then Result := 0; if not ShowRoot then Dec(Result, FIndent); end; end; function GetTotalRect(AIndent, YTop, YBottom: Integer): TRect; // group and preview begin with DrawInfo do begin Result := Rect(CellsRect.Left + AIndent, YTop, CellsRect.Left + GetBandTotalWidth - SizeGrid, YBottom); if IsRectEmptyEx(FixedBandLeftRect) then OffsetRect(Result, - LeftCoord, 0); if not IsRectEmptyEx(FixedBandRightRect) then if Result.Right > CellsRect.Right - SizeGrid then Result.Right := CellsRect.Right - SizeGrid; end; end; procedure DrawTreeLine(X1, Y1, X2, Y2: Integer); begin Windows.FillRect(Canvas.Handle, Rect(X1, Y1, X2 + 1, Y2 + 1), TreeBrush); end; begin with Canvas, DrawInfo do begin // Empty rect if not IsRectEmpty(EmptyRectRight) and RectVisible(Handle, EmptyRectRight) then Windows.FillRect(Handle, EmptyRectRight, BackgroundBrush); if not IsRectEmpty(EmptyRectBottom) and RectVisible(Handle, EmptyRectBottom) then Windows.FillRect(Handle, EmptyRectBottom, BackgroundBrush); if RectVisible(Handle, CellsRect) and (BandCount > 0) then begin IsFocused := IsActiveControl or ((State = tsEditing) and (InplaceEditor <> nil) and (InplaceEditor.IsFocused)); if FShowGrid then begin SizeGrid := 1; MaxLines := RowSeparatorLineWidth * RowCount * ( 1 + Byte(not IsRectEmptyEx(FixedBandLeftRect)) + Byte(not IsRectEmptyEx(FixedBandRightRect))); // separators row Inc(MaxLines); // vert right line end else begin SizeGrid := 0; MaxLines := 0; end; if RowsInfo <> nil then begin // draw Indent and calc count grid points RClip := Rect(CellsRect.Left, CellsRect.Top, CellsRect.Left + IndentLimit, CellsRect.Bottom); if IsRectEmptyEx(FixedBandLeftRect) then Dec(RClip.Right, LeftCoord); if RClip.Left > RClip.Right then RClip.Left := RClip.Right; FlagRgn := False; SaveRegion(RClip); try // OnGetImageIndex events -> raised exception //set tree line color if FPaintStandard and FShowLines and (TreeLineStyle = tlDot) then begin {save Bk Color} PrevBkColor := GetBkColor(Canvas.Handle); TreeBrush := HalftoneBrush; if Odd(CellsRect.Left) = Odd(CellsRect.Top) then begin SetBkColor(Canvas.Handle, ColorToRGB(TreeLineColor)); SetTextColor(Canvas.Handle, ColorToRGB(Self.Color)); end else begin SetBkColor(Canvas.Handle, ColorToRGB(Self.Color)); SetTextColor(Canvas.Handle, ColorToRGB(TreeLineColor)); end; end else TreeBrush := TreeLineBrush; // start position Y := CellsRect.Top; for j := 0 to RowCount - 1 do with RowsInfo^[j] do begin PrepareNode(Node); try if FPaintStandard then Br := BackgroundBrush else Br := GroupBrush; CorrectY := Byte(not FShowGrid and Node.HasChildren and not FPaintStandard); GetNodeIndent(Node, Ind, Indent); R := Rect(CellsRect.Left, Y, CellsRect.Left + Indent, Y + RowHeight); if IsRectEmptyEx(FixedBandLeftRect) then OffsetRect(R, - LeftCoord, 0); if (R.Right > R.Left) then // fill and draw images begin StartLineX := GetStartLineCoord(Node, j); NodeLevel := Node.Level; H := NodeLevel; if not Node.HasChildren then Dec(NodeLevel); if Node.HasChildren or FPaintStandard then Inc(H); YCenter := Y + RowHeight div 2 - 1 + 1{?}; for i := 0 to H - 1 do begin R := Rect(CellsRect.Left + i * FIndent, Y + Byte(i = H - 1)*CorrectY, CellsRect.Left + (i + 1) * FIndent - 1, Y + RowHeight); {.} if not ShowRoot then OffsetRect(R, - FIndent, 0); if not FShowGrid and FPaintStandard then Inc(R.Right) else if R.Right > (CellsRect.Left + StartLineX) then R.Bottom := Y + RowHeight - RowSeparatorLineWidth; if IsRectEmptyEx(FixedBandLeftRect) then OffsetRect(R, - LeftCoord, 0); // footer indent if (RowFooterCount > 0) then begin k := GetNodeFooterRowCount(Node, i); if k <> -1 then Dec(R.Bottom, k * FFooterRowNodeHeight); end; if not FPaintStandard then begin if (I <= NodeLevel) and AssignedLevelColorEvent then begin AColor := FGroupColor; Br := GetLevelBrush(I, AColor); end else Br := GroupBrush; end; // fill indent Windows.FillRect(Canvas.Handle, R, Br); // tree lines if FPaintStandard and FShowLines then begin DeltaButton := 9 div 2 + 1; // horz line X := CellsRect.Left + Node.Level * FIndent; {.} if not ShowRoot then Dec(X, FIndent); if IsRectEmptyEx(FixedBandLeftRect) then Dec(X, LeftCoord); XPos1 := X + (FIndent div 2) - 1; if FShowButtons and Node.HasChildren then Inc(XPos1, DeltaButton); DrawTreeLine(XPos1, YCenter, X + FIndent - 1, YCenter); // vert lines X := CellsRect.Left + Node.Level * FIndent + (FIndent div 2) - 1; // x coord {.} if not ShowRoot then Dec(X, FIndent); if IsRectEmptyEx(FixedBandLeftRect) then Dec(X, LeftCoord); if FShowButtons and Node.HasChildren then begin // top line if Node <> TopNode then begin YPos1 := Y; // NEW if (J > 0) and (FImageH > 0) and (Node.Parent <> nil) and (Node.Parent[0] = Node) then Dec(YPos1, (RowsInfo^[J - 1].RowHeight - FImageH) div 2); YPos2 := YCenter - DeltaButton; DrawTreeLine(X, YPos1, X, YPos2); end; // bottom line if not Node.IsLast then begin YPos1 := YCenter + DeltaButton; YPos2 := Y + RowHeight; DrawTreeLine(X, YPos1, X, YPos2); end; end else begin if Node = TopNode then YPos1 := YCenter else YPos1 := Y; // NEW if (J > 0) and (FImageH > 0) and (Node.Parent <> nil) and (Node.Parent[0] = Node) then Dec(YPos1, (RowsInfo^[J - 1].RowHeight - FImageH) div 2); if not Node.IsLast then YPos2 := Y + RowHeight else YPos2 := YCenter; if YPos1 < YPos2 then DrawTreeLine(X, YPos1, X, YPos2); end; // left lines LevelNode := Node.Parent; while LevelNode <> nil do begin Dec(X, FIndent); if not LevelNode.IsLast then begin YPos1 := Y; YPos2 := Y + RowHeight; DrawTreeLine(X, YPos1, X, YPos2); end; LevelNode := LevelNode.Parent; end; end; end; if Node.HasChildren and not (FPaintStandard and FShowGrid) then begin R.Left := R.Right; R.Right := R.Left + 1; R.Bottom := Y + RowHeight - RowSeparatorLineWidth; Windows.FillRect(Canvas.Handle, R, Br); end; if FShowButtons and Node.HasChildren then // draw plus/minus button begin R.Left := CellsRect.Left + (Node.Level) * FIndent; {.} if not ShowRoot then OffsetRect(R, - FIndent, 0); R.Right := R.Left + FIndent - 1; R.Bottom := Y + RowHeight - RowSeparatorLineWidth; if IsRectEmptyEx(FixedBandLeftRect) then OffsetRect(R, - LeftCoord, 0); if FPaintStandard then begin R.Bottom := Y + RowHeight; DrawButton(Canvas, R, YCenter, not Node.Expanded); end else if LookAndFeel = lfUltraFlat then DrawUltraFlatButton(Canvas.Handle, R, not Node.Expanded) else DrawOutButton(Canvas, R, not Node.Expanded); end; // images R.Bottom := Y + RowHeight - RowSeparatorLineWidth; if (RowFooterCount > 0) then // footer indent begin k := GetRowFooterCount(Node); if k <> -1 then Dec(R.Bottom, k * FFooterRowNodeHeight); end; if not FPaintStandard then begin if IsGroup or Node.HasChildren then begin if AssignedLevelColorEvent then begin AColor := FGroupColor; Br := GetLevelBrush(Node.Level, AColor); end else Br := GroupBrush; end else Br := BackgroundBrush; end; if Node.StateIndex <> -1 then begin R.Left := CellsRect.Left + Ind; R.Right := R.Left + FImageStateW; if IsRectEmptyEx(FixedBandLeftRect) then OffsetRect(R, - LeftCoord, 0); Windows.FillRect(Canvas.Handle, R, Br); WriteImage(Canvas, R, StateImages, Node.StateIndex); Inc(Ind, FImageStateW); end; if IsSelected then begin R.Left := CellsRect.Left + Ind; R.Right := R.Left + FImageW; if IsRectEmptyEx(FixedBandLeftRect) then OffsetRect(R, - LeftCoord, 0); Windows.FillRect(Canvas.Handle, R, Br); if Node.SelectedIndex <> -1 then WriteImage(Canvas, R, Images, Node.SelectedIndex); end else begin R.Left := CellsRect.Left + Ind; R.Right := R.Left + FImageW; if IsRectEmptyEx(FixedBandLeftRect) then OffsetRect(R, - LeftCoord, 0); Windows.FillRect(Canvas.Handle, R, Br); if Node.ImageIndex <> -1 then WriteImage(Canvas, R, Images, Node.ImageIndex); end; end; // calc lines count if FShowGrid then begin Inc(MaxLines, Node.Level + Byte(FPaintStandard)); // vert separators if not IsGroup and FShowPreviewGrid then Inc(MaxLines, HeaderCount * 2 + EmptyRectCount); // cells if FShowPreviewGrid and (PreviewLineCount > 0) then Inc(MaxLines); // preview separator line if FShowGrid and FShowPreviewGrid then Inc(MaxLines, RowFooterHeight * RowFooterCount); // row footer separator line end else begin Inc(MaxLines, Node.Level + 1{bottom line - group or last children node }); if not IsGroup then begin if not IsRectEmptyEx(FixedBandLeftRect) then Inc(MaxLines); if not IsRectEmptyEx(FixedBandRightRect) then Inc(MaxLines); end; end; if Indent > IndentLimit then Indent := IndentLimit; Inc(Y, RowHeight); finally UnPrepareNode(Node); end; end; // restore Bk Color if FPaintStandard and FShowLines then SetBkColor(Canvas.Handle, PrevBkColor); finally // restore prev rgn RestoreRegion; end; // grid lines memory allocating Points := AllocMem(MaxLines * SizeOf(TPoint) * 2); Strokes := AllocMem(MaxLines * SizeOf(Integer)); for i := 0 to MaxLines - 1 do Strokes^[i] := 2; LinesCount := 0; // draw values try // OnCustomDraw events -> raised exception Y := CellsRect.Top; FlagClip := ((not IsRectEmptyEx(FixedBandLeftRect)) or (not IsRectEmptyEx(FixedBandRightRect)) or (LeftCoord <> 0 )) and ((CellsRect.Right - CellsRect.Left) < GetBandTotalWidth); // set Font Font.Assign(Self.Font); // TODO PAINT* SetTextColor(Handle, ColorToRGB(Self.Font.Color)); // TODO PAINT* for j := 0 to RowCount - 1 do with RowsInfo^[j] do begin PrepareNode(Node); try CorrectY := Byte(not FShowGrid and Node.HasChildren and not FPaintStandard); if IsGroup then begin FlagRgn := False; R := GetTotalRect(Indent, Y + CorrectY, Y + RowHeight - RowSeparatorLineWidth); RClip := Rect(CellsRect.Left, R.Top, CellsRect.Right, R.Bottom); if FlagClip then SaveRegion(RClip); // TODO PAINT1 GetBkBrush(Node, IsSelected and (not IsNewItemRowActive or IsMultiSelect), IsFocused, IsGroup, Node.HasChildren, Node.Level, -1, AColor, ATextColor, Br); SetBkColor(Canvas.Handle, ColorToRGB(AColor)); SetTextColor(Canvas.Handle, ColorToRGB(ATextColor)); DrawCell(Canvas, R, DrawBitmap, Node, 0, -1, IsSelected, IsFocused and Node.Focused, AColor, Br, False, ckGroup, False, False); // Draw Focus if not IsNewItemRowActive and Node.Focused and ((IsFocused and not HideDrawFocusRect) or (not IsFocused and not HideFocusRect)) then if IsFocused then DrawFocused(Handle, R) else if (FDragObject = nil) then DrawFramed(Handle, R); if FlagRgn then RestoreRegion; end else begin // draw fixed band lines R.Top := Y; R.Bottom := R.Top + RowHeight - PreviewLineCount * FDescTextHeight - Byte((PreviewLineCount > 0) and FShowGrid and FShowPreviewGrid) - 2 * Byte(PreviewLineCount > 0) - RowFooterHeight; if PreviewLineCount > 0 then Dec(R.Bottom, RowSeparatorLineWidth); if not IsRectEmpty(FooterRect) then if R.Bottom > FooterRect.Top then R.Bottom := FooterRect.Top; // draw fixed lines if not IsRectEmptyEx(FixedBandLeftRect) then begin with FixedBandLeftRect do R := Rect(Right - FFixedBandLineWidth, R.Top, Right, R.Bottom); Windows.FillRect(Handle, R, FixedBandLineBrush{GetSysColorBrush(COLOR_WINDOWFRAME)}); end; if not IsRectEmptyEx(FixedBandRightRect) then begin with FixedBandRightRect do R := Rect(Left, R.Top, Left + FFixedBandLineWidth, R.Bottom); Windows.FillRect(Handle, R, FixedBandLineBrush{GetSysColorBrush(COLOR_WINDOWFRAME)}); end; Inc(R.Top, CorrectY); // cells - calc clip region FlagRgn := False; RClip := Rect(CellsRect.Left + Indent, Y, CellsRect.Right, Y + RowHeight{ - PreviewLineCount * FDescTextHeight - RowSeparatorLineWidth}); if not IsRectEmptyEx(FixedBandLeftRect) then RClip.Left := FixedBandLeftRect.Right else begin Dec(RClip.Left, LeftCoord); if RClip.Left < CellsRect.Left then RClip.Left := CellsRect.Left; end; if not IsRectEmptyEx(FixedBandRightRect) then RClip.Right := FixedBandRightRect.Left; // draw cells for I := 0 to HeaderCount - 1 do with HeadersInfo^[I] do begin if FlagClip then // set clip region begin if not ((BandIndex = FixedBandLeftIndex) or (BandIndex = FixedBandRightIndex)) and not FlagRgn then // set region SaveRegion(RClip) else if FlagRgn and ((BandIndex = FixedBandLeftIndex) or (BandIndex = FixedBandRightIndex)) then // restore prev rgn RestoreRegion; end; // calc indent StartLineX := HeaderRect.Left; if IsRectEmptyEx(FixedBandLeftRect) then Inc(StartLineX, LeftCoord); if (BandIndex = 0) and (StartLineX - CellsRect.Left < Indent) then Ind := Indent - (StartLineX - CellsRect.Left) else Ind := 0; H := LineCount * FRowHeight; if HeaderRect.Right > (HeaderRect.Left + Ind) then // if Visible begin R := Rect(HeaderRect.Left + Ind, Y + FRowHeight * RowIndex + CorrectY, HeaderRect.Right, Y + FRowHeight * RowIndex + H - SizeGrid * Byte(FShowPreviewGrid) + CorrectY); if (FHeaderRowCount = 1) then begin R.Bottom := Y + RowHeight - PreviewLineCount * FDescTextHeight - RowSeparatorLineWidth - RowFooterHeight; if PreviewLineCount > 0 then Dec(R.Bottom, 2 + Byte(FShowGrid and FShowPreviewGrid)); end; if not (((BandIndex = FixedBandLeftIndex) or (BandIndex = FixedBandPrevRightIndex)) and LastColumn) then Dec(R.Right, SizeGrid * Byte(FShowPreviewGrid)); if FShowGrid and not FShowPreviewGrid and LastColumn then begin if (BandCount > 1) and (BandIndex = BandsInfo^[BandCount - 1].Index) or (BandCount = 1) then Dec(R.Right, SizeGrid); end; if RectVisible(Handle, R) then begin // Bk Color and Text Color FlagSelected := IsSelected and (not IsNewItemRowActive or IsMultiSelect) and (IsRowSelect or (IsMultiSelect and not IsInvertSelect) or (IsMultiSelect and IsInvertSelect and IsNewItemRowActive) or (IsMultiSelect and IsInvertSelect and not Node.Focused) or ((FocusedAbsoluteIndex = AbsoluteIndex) and not IsInvertSelect) or ((FocusedAbsoluteIndex <> AbsoluteIndex) and IsInvertSelect)); if FlagSelected and HideSelection and not IsFocused then FlagSelected := False; // TODO ? // TODO PAINT1 GetBkBrush(Node, FlagSelected, IsFocused, IsGroup, Node.HasChildren, Node.Level, I, AColor, ATextColor, Br); GetCellBkBrush(I, ACellBkColor, ACellBkBrush); DrawCellEx(Canvas, R, DrawBitmap, Node, AbsoluteIndex, FlagSelected, IsFocused and Node.Focused and (IsInvertSelect or IsRowSelect or (FocusedAbsoluteIndex = AbsoluteIndex)), AColor, ATextColor, Br, (LineCount > 1) or (RowLineCount > 1) or MultiLine, ckRow, LeftEdgeColumn, RightEdgeColumn, ACellBkColor, ACellBkBrush); // Draw Focus if not IsNewItemRowActive and not (IsRowSelect or IsInvertSelect) and Node.Focused and (FocusedAbsoluteIndex = AbsoluteIndex) and ((IsFocused and not HideDrawFocusRect) or (not IsFocused and not HideFocusRect)) then if IsFocused then DrawFocused(Handle, R) else if (FDragObject = nil) then DrawFramed(Handle, R); end; if RectVisible(Handle, Rect(R.Left, R.Top, R.Right, R.Bottom + 1)) then begin // grid horz line if FShowGrid and FShowPreviewGrid and (FHeaderRowCount > 1) then begin SetPoints(Points, LinesCount, R.Left, R.Bottom, R.Right, R.Bottom); if FlagRgn and (Points^[LinesCount * 4] < RClip.Left) then Points^[LinesCount * 4] := RClip.Left; if FlagRgn and (Points^[LinesCount * 4 + 2] > RClip.Right) then Points^[LinesCount * 4 + 2] := RClip.Right; Inc(LinesCount); end; end; // grid vert line if FShowGrid and FShowPreviewGrid and not (((BandIndex = FixedBandLeftIndex) or (BandIndex = FixedBandPrevRightIndex)) and LastColumn) then begin if not (FlagRgn and ((R.Right < RClip.Left) or (R.Right >= RClip.Right))) then begin SetPoints(Points, LinesCount, R.Right, R.Top, R.Right, R.Bottom + 1); if LastColumn then // band edge begin Points^[LinesCount * 4 + 3] := Y + FRowHeight * GetHeaderMaxRowCount; if (FHeaderRowCount = 1) then Points^[LinesCount * 4 + 3]:= Y + RowHeight - PreviewLineCount * FDescTextHeight - RowSeparatorLineWidth - RowFooterHeight - 2 * Byte(PreviewLineCount > 0); end else if (i < (HeaderCount - 1)) and (BandIndex = HeadersInfo^[i + 1].BandIndex) and (RowIndex = HeadersInfo^[i + 1].RowIndex) then begin H := HeadersInfo^[i + 1].LineCount * FRowHeight; H := Y + FRowHeight * RowIndex + H - SizeGrid; if (H + 1) > Points^[LinesCount * 4 + 3] then Points^[LinesCount * 4 + 3] := (H + 1); end; Inc(LinesCount); end; end; // empty header rect if not IsRectEmpty(HeaderEmptyRect) and not IsGroup then begin R.Top := Y + FRowHeight * (RowIndex + LineCount) + CorrectY; R.Bottom := Y + FRowHeight * GetHeaderMaxRowCount + CorrectY; if FShowGrid and FShowPreviewGrid then Dec(R.Bottom); if FShowGrid and FShowPreviewGrid then begin Inc(R.Right, SizeGrid); if LastColumn then begin if (i > 0) and (BandIndex = HeadersInfo^[i - 1].BandIndex) and (RowIndex = HeadersInfo^[i - 1].RowIndex) then if HeadersInfo^[i - 1].LineCount < HeadersInfo^[i].LineCount then Dec(R.Left); Dec(R.Right); end else if (i < (HeaderCount - 1)) and (BandIndex = HeadersInfo^[i + 1].BandIndex) and (RowIndex = HeadersInfo^[i + 1].RowIndex) then begin if HeadersInfo^[i].LineCount < HeadersInfo^[i + 1].LineCount then Dec(R.Right) else if HeadersInfo^[i].LineCount > HeadersInfo^[i + 1].LineCount then Dec(R.Left); end; end; GetBkBrush(Node, IsSelected and (not IsNewItemRowActive or IsMultiSelect) and (IsRowSelect or IsInvertSelect or IsMultiSelect), IsFocused, IsGroup, Node.HasChildren, Node.Level, -1, AColor, ATextColor, Br); Windows.FillRect(Handle, R, Br); end; end; end; // restore prev rgn if FlagRgn then RestoreRegion; // fill empty rect if EmptyRectsInfo <> nil then begin for i := 0 to EmptyRectCount - 1 do with EmptyRectsInfo^[i] do begin R := GetTotalRect(Indent, Y + CorrectY, Y + FRowHeight * GetHeaderMaxRowCount + CorrectY - Byte(FShowGrid and FShowPreviewGrid)); if (FHeaderRowCount = 1) then begin R.Bottom := Y + RowHeight - PreviewLineCount * FDescTextHeight - RowSeparatorLineWidth - RowFooterHeight; if PreviewLineCount > 0 then Dec(R.Bottom, 2 + Byte(FShowGrid and FShowPreviewGrid)); end; if EmptyRectsInfo^[i].BandIndex <> 0 then R.Left := EmptyRect.Left; R.Right := EmptyRect.Right; // vert line - group separator if FShowGrid and FShowPreviewGrid and not ((BandIndex = FixedBandLeftIndex) or (BandIndex = FixedBandPrevRightIndex)) then begin if not ((R.Right < RClip.Left) or (R.Right > RClip.Right)) and not ClippingFlag then // (BandsInfo^[BandIndex].BandRect.Right <= BandsInfo^[BandIndex].BandClipRect.Right) then begin SetPoints(Points, LinesCount, R.Right - 1, R.Top, R.Right - 1, R.Bottom); Inc(LinesCount); Dec(R.Right); end; end; GetBkBrush(Node, IsSelected and (not IsNewItemRowActive or IsMultiSelect) and (IsRowSelect or IsInvertSelect or IsMultiSelect), IsFocused, IsGroup, Node.HasChildren, Node.Level, -1, AColor, ATextColor, Br); if not IsRectEmpty(R) then Windows.FillRect(Handle, R, Br); end; end; // preview if PreviewLineCount > 0 then begin FlagRgn := False; R := GetTotalRect(Indent, Y + RowHeight - PreviewLineCount * FDescTextHeight - RowSeparatorLineWidth - 2 - RowFooterHeight, Y + RowHeight - RowSeparatorLineWidth - RowFooterHeight); RClip := Rect(CellsRect.Left, R.Top, CellsRect.Right, R.Bottom); if FlagClip then SaveRegion(RClip); GetBkBrush(Node, IsSelected and (not IsNewItemRowActive or IsMultiSelect) and (IsRowSelect or IsInvertSelect or IsMultiSelect), IsFocused, IsGroup, Node.HasChildren, Node.Level, -1, AColor, ATextColor, Br); DrawPreview(Canvas, R, DrawBitmap, Node, AColor, ATextColor, Br, IsSelected); // grid - separator preview if FShowGrid and FShowPreviewGrid then begin SetPoints(Points, LinesCount, R.Left, R.Top - 1, R.Right, R.Top - 1); if FlagRgn and (Points^[LinesCount * 4] < RClip.Left) then Points^[LinesCount * 4] := RClip.Left; if FlagRgn and (Points^[LinesCount * 4 + 2] > RClip.Right) then Points^[LinesCount * 4 + 2] := RClip.Right; Inc(LinesCount); end; if FlagRgn then RestoreRegion; end; // node footer for k := 0 to RowFooterCount - 1 do begin R := GetFooterRect(Node, k, Y + RowHeight - RowSeparatorLineWidth - RowFooterHeight, SizeGrid, DrawInfo); if FShowGrid and FShowPreviewGrid then begin // grid footer separator (horz line) SetPoints(Points, LinesCount, R.Left, R.Top, R.Right, R.Top); Inc(LinesCount); // grid vert line if R.Right < CellsRect.Right then begin SetPoints(Points, LinesCount, R.Right, R.Top, R.Right, R.Bottom); Inc(LinesCount); end; // correct rect size Inc(R.Top, SizeGrid); end; //fc Br := FooterBrush; AColor := FFooterColor; if AssignedLevelColorEvent then Br := GetLevelBrush(GetNodeFooterLevel(Node, k), AColor) else Br := FooterBrush; Windows.FillRect(Handle, R, Br); // draw footer cells try RClip := R; if not IsRectEmptyEx(FixedBandLeftRect) then RClip.Left := FixedBandLeftRect.Right else begin Dec(RClip.Left, LeftCoord); if RClip.Left < CellsRect.Left - FIndicatorWidth then RClip.Left := CellsRect.Left - FIndicatorWidth; end; if not IsRectEmptyEx(FixedBandRightRect) then RClip.Right := FixedBandRightRect.Left; YTop := R.Top + 1; for i := 0 to HeaderCount - 1 do with HeadersInfo^[i] do begin if FlagClip then // set clip region begin if not ((BandIndex = FixedBandLeftIndex) or (BandIndex = FixedBandRightIndex)) and not FlagRgn then // set region SaveRegion(RClip) else if FlagRgn and ((BandIndex = FixedBandLeftIndex) or (BandIndex = FixedBandRightIndex)) then // restore prev rgn RestoreRegion; end; X := HeaderRect.Left; if IsRectEmptyEx(FixedBandLeftRect) then Inc(X, LeftCoord); // calc indent StartLineX := Indent; XPos1 := GetNodeFooterLevel(Node, k); if XPos1 <> -1 then Dec(StartLineX, (Node.Level - 1 - XPos1) * FIndent); if (BandIndex = 0) and (X - CellsRect.Left < StartLineX{Indent}) then Ind := StartLineX{Indent} - (X - CellsRect.Left) else Ind := 0; H := LineCount * FFooterRowHeight; if HeaderRect.Right > (HeaderRect.Left + Ind) then // if Visible begin R := Rect(HeaderRect.Left + Ind, YTop + FFooterRowHeight * RowIndex, HeaderRect.Right, YTop + FFooterRowHeight * RowIndex + H); InflateRect(R, -1, -1); if (BandIndex = 0) and (ColIndex = 0) then Inc(R.Left); if LastColumn and (BandIndex = BandsInfo^[BandCount - 1].Index) then Dec(R.Right, 2); if IsExistRowFooterCell(Node, AbsoluteIndex, K) then begin DrawFooterFrame(Canvas.Handle, R); // DrawEdge(Canvas.Handle, R, BDR_SUNKENOUTER, BF_RECT); InflateRect(R, -1, -1); // DrawFooterCell //fc SetBkColor(Canvas.Handle, ColorToRGB(FFooterColor)); SetBkColor(Canvas.Handle, ColorToRGB(AColor)); SetTextColor(Canvas.Handle, ColorToRGB(FFooterTextColor)); //fc DrawCell(Canvas, R, DrawBitmap, Node, AbsoluteIndex, K, False, False, // FFooterColor, Br, LineCount > 1, ckFooter{footer}, False, False); DrawCell(Canvas, R, DrawBitmap, Node, AbsoluteIndex, K, False, False, AColor, Br, LineCount > 1, ckFooter{footer}, False, False); end; end; end; finally // restore prev rgn if FlagRgn then RestoreRegion; end; end; // Draw Focus - if RowSelect if not IsNewItemRowActive and (IsRowSelect or IsInvertSelect) and Node.Focused and ((IsFocused and not HideDrawFocusRect) or not IsFocused and not HideFocusRect) then begin R := GetTotalRect(Indent, Y, {Y + RowHeight - RowSeparatorLineWidth} Y + RowHeight - RowSeparatorLineWidth - RowFooterHeight); if not FPaintStandard and not FShowGrid and Node.HasChildren then Inc(R.Top); if IsFocused then DrawFocused(Handle, R) else if (FDragObject = nil) then DrawFramed(Handle, R); end; end; // grid - vert line separator group H := Node.Level; if FPaintStandard then if FShowGrid then Inc(H) else H := 0; for i := 0 to H - 1 do begin StartLineX := CellsRect.Left + (i + 1) * FIndent - 1; {.} if not ShowRoot then Dec(StartLineX, FIndent); // footer indent YBottom := Y + RowHeight; if (RowFooterCount > 0) then begin k := GetNodeFooterRowCount(Node, i); if k > 0 then Dec(YBottom, k * FFooterRowNodeHeight + RowSeparatorLineWidth); end; if StartLineX < CellsRect.Left + IndentLimit then begin if IsRectEmptyEx(FixedBandLeftRect) then Dec(StartLineX, LeftCoord); if StartLineX >= CellsRect.Left then begin SetPoints(Points, LinesCount, StartLineX, Y, StartLineX, YBottom); Inc(LinesCount); end; end; end; Inc(Y, RowHeight); // grid - separator row if FShowGrid or (Node.HasChildren and not FPaintStandard) then begin if not FShowGrid and Node.HasChildren then begin Ind := Node.Level * FIndent; {.} if not ShowRoot then Dec(Ind, FIndent); StartLineX := RowHeight - 1; end else begin Ind := GetStartLineCoord(Node, j); StartLineX := 0; end; if FShowGrid then H := RowSeparatorLineWidth else H := 1; if Ind > IndentLimit then Ind := IndentLimit; XPos1 := CellsRect.Left + Ind; if IsRectEmptyEx(FixedBandLeftRect) then Dec(XPos1, LeftCoord); if XPos1 < CellsRect.Left then XPos1 := CellsRect.Left; if not IsGroup and (PreviewLineCount = 0) and (RowFooterHeight = 0) then begin if not IsRectEmptyEx(FixedBandLeftRect) then begin XPos2 := FixedBandLeftRect.Right - FFixedBandLineWidth; for i := 0 to H - 1 do begin SetPoints(Points, LinesCount, XPos1, Y + i - H - StartLineX, XPos2, Y + i - H - StartLineX); Inc(LinesCount); end; XPos1 := FixedBandLeftRect.Right; end; if not IsRectEmptyEx(FixedBandRightRect) then begin XPos2 := FixedBandRightRect.Left; for i := 0 to H - 1 do begin SetPoints(Points, LinesCount, XPos1, Y + i - H - StartLineX, XPos2, Y + i - H - StartLineX); Inc(LinesCount); end; XPos1 := FixedBandRightRect.Left + FFixedBandLineWidth; end; end; XPos2 := EdgeX + Byte(not FShowGrid); for i := 0 to H - 1 do begin SetPoints(Points, LinesCount, XPos1, Y + i - H - StartLineX, XPos2, Y + i - H - StartLineX); Inc(LinesCount); end; end; finally UnPrepareNode(Node); // synchronizing with DataSet end; end; // Vert right line if FShowGrid then begin SetPoints(Points, LinesCount, EdgeX, CellsRect.Top, EdgeX, CellsRect.Bottom); if EdgeY <> -1 then Points^[LinesCount * 4 + 3] := EdgeY + 1; Inc(LinesCount); end; // grid lines if FShowGrid then Canvas.Pen.Color := GetGridColor(Self.Color) //clBtnShadow else Canvas.Pen.Color := Self.Color; // SelectObject(Canvas.Handle, Canvas.Pen.Handle); PolypolyLine(Canvas.Handle, Points^, Strokes^, LinesCount); finally FreeMem(Strokes); FreeMem(Points); end; end; end; end; end; function GetShadowPanelColor: TColor; begin if LookAndFeel = lfUltraFlat then Result := $00A0A0A0 else Result := clBtnShadow; end; {.$DEFINE DEBUG_PAINT} {$IFDEF DEBUG_PAINT} var i, t1, t2: LongInt; {$ENDIF DEBUG_PAINT} begin {$IFDEF DEBUG_PAINT} t1 := gettickcount; for i := 0 to 100 do {$ENDIF DEBUG_PAINT} begin HideDragImages; try // calc Draw Info CalcDrawInfo(DrawInfo); // create GDI objects DrawBitmap := TBitmap.Create; BandBrush := CreateSolidBrush(ColorToRGB(FBandColor)); HeaderBrush := CreateSolidBrush(ColorToRGB(FHeaderColor)); GroupBrush := CreateSolidBrush(ColorToRGB(FGroupColor)); BackgroundBrush := CreateSolidBrush(ColorToRGB(Self.Color)); APanelBrushColor := GetShadowPanelColor; PanelBrush := CreateSolidBrush(ColorToRGB(APanelBrushColor)); //GetSysColorBrush(COLOR_BTNSHADOW); HighlightBrush := CreateSolidBrush(ColorToRGB(FHighlightColor));//GetSysColorBrush(COLOR_HIGHLIGHT); TreeLineBrush := CreateSolidBrush(ColorToRGB(TreeLineColor)); HideSelectionBrush := CreateSolidBrush(ColorToRGB(FHideSelectionColor)); FooterBrush := CreateSolidBrush(ColorToRGB(FFooterColor)); FixedBandLineBrush := CreateSolidBrush(ColorToRGB(FFixedBandLineColor)); LevelBrush := 0; // create column brushes with DrawInfo do begin PBrushes := AllocMem(HeaderCount * SizeOf(TBrushInfo)); for BrushIndex := 0 to HeaderCount - 1 do with HeadersInfo^[BrushIndex] do begin PBrushes^[BrushIndex].Color := GetColumnColor(AbsoluteIndex); if ColorToRGB(PBrushes^[BrushIndex].Color) <> ColorToRGB(Self.Color) then PBrushes^[BrushIndex].Brush := CreateSolidBrush(ColorToRGB(PBrushes^[BrushIndex].Color)); end; end; try DrawGrPanel; DrawBands; DrawHeaders; DrawNewItemRow; DrawIndicator; DrawFooter; DrawStatus; DrawCells; finally // free Brushes Info with DrawInfo do for BrushIndex := 0 to HeaderCount - 1 do if PBrushes^[BrushIndex].Brush <> 0 then DeleteObject(PBrushes^[BrushIndex].Brush); FreeMem(PBrushes); // free other DeleteObject(FixedBandLineBrush); DeleteObject(FooterBrush); if LevelBrush <> 0 then DeleteObject(LevelBrush); DeleteObject(HideSelectionBrush); DeleteObject(TreeLineBrush); DeleteObject(HighlightBrush); DeleteObject(PanelBrush); DeleteObject(BackgroundBrush); DeleteObject(GroupBrush); DeleteObject(HeaderBrush); DeleteObject(BandBrush); if DrawBitmap <> nil then begin DrawBitmap.Free; DrawBitmap := nil; end; // free Draw Info FreeDrawInfo(DrawInfo); end; finally ShowDragImages; end; end; {$IFDEF DEBUG_PAINT} SelectClipRgn(Canvas.Handle, 0); t2 := gettickcount; getparentform(self).caption := inttostr(t2 - t1); {$ENDIF DEBUG_PAINT} end; procedure TCustomdxTreeList.WndProc(var Message: TMessage); var Node: TdxTreeListNode; P: TPoint; begin if (Message.Msg = WM_MOUSEMOVE) and (State in [tsBandDragging, tsColumnDragging]) then begin if State = tsBandDragging then DoBandDragging; if State = tsColumnDragging then DoHeaderDragging; Exit; end; if (Message.Msg = WM_KEYDOWN) and (Message.wParam = VK_ESCAPE) and Dragging and (DragMode = dmAutomatic) then EndDrag(False); {$IFNDEF DELPHI4} if ((Message.Msg = WM_KEYUP) or (Message.Msg = WM_KEYDOWN)) and (Message.wParam = VK_CONTROL) and Dragging then begin GetCursorPos(P); SetCursorPos(P.X, P.Y); end; {$ENDIF} if (Message.Msg = WM_KEYDOWN) and (Message.wParam in [VK_ADD, VK_SUBTRACT]) and Dragging and (DragMode = dmAutomatic) then begin GetCursorPos(P); P := ScreenToClient(P); // Windows.ScreenToClient(Parent.Handle, P); Node := GetNodeAt(P.X, P.Y); if Node <> nil then if Node.HasChildren then if (Message.wParam = VK_ADD) and not Node.Expanded then Node.Expanded := True else if (Message.wParam = VK_SUBTRACT) and Node.Expanded then Node.Expanded := False; end; if not (csDesigning in ComponentState) and ((Message.Msg = WM_LBUTTONDOWN) or (Message.Msg = WM_LBUTTONDBLCLK)) and not Dragging and (DragMode = dmAutomatic) then begin if not IsControlMouseMsg(TWMMouse(Message)) then begin ControlState := ControlState + [csLButtonDown]; Dispatch(Message); end; end else inherited WndProc(Message); end; // routines TCustomdxTreeList function TCustomdxTreeList.CalcBandHeight(LineCount: Integer): Integer; begin Result := FBandTextHeight * LineCount + 3{indent} + 2 + Byte(not FFlat){black line -> right_bottom}; end; function TCustomdxTreeList.CalcBandPanelRowCount(Y: Integer): Integer; var DrawInfo: TdxGridDrawInfo; i: Integer; begin CalcRectInfo(DrawInfo); with DrawInfo do begin Result := 0; for i := 1 to GetBandMaxRowCount do begin if Y >= (BandRect.Top + CalcBandHeight(i)) then Inc(Result) else Break; end; end; end; function TCustomdxTreeList.CalcHeaderPanelRowCount(Y: Integer): Integer; var DrawInfo: TdxGridDrawInfo; begin CalcRectInfo(DrawInfo); with DrawInfo do begin Result := (Y - HeaderRect.Top + FHeaderRowHeight div 2) div FHeaderRowHeight; if Result < 1 then Result := 1; end; end; function TCustomdxTreeList.CalcNearestRowHeight(Node: TdxTreeListNode; ResizeRowHeight: Integer): Integer; var i: Integer; begin Result := FRowHeight; if Node <> nil then begin for i := FMinRowHeight to ResizeRowHeight do begin if GetRowHeight(Node, i, True{ReCalc}) <= ResizeRowHeight then Result := i else Break; end; end; end; class function TCustomdxTreeList.CalcTextRowHeight(TextHeight: Integer): Integer; begin Result := TextHeight + 3; end; procedure TCustomdxTreeList.CancelDragSizing; begin if State in [tsBandSizing, tsColumnSizing, tsBandPanelSizing, tsHeaderPanelSizing, tsRowSizing] then begin DrawSizingLine; SetState(tsNormal); SetCursor(Screen.Cursors[Cursor]); end; if State = tsBandDown then begin SetState(tsNormal); FDownBandIndex := -1; InvalidateBand(-1); end; if State = tsBandDragging then EndDragBand(False); if State = tsDropDownButtonDown then begin SetState(tsNormal); FDropDownButtonColumnIndex := -1; FDownColumnIndex := -1; InvalidateColumn(-1); end; if State = tsStatusCloseButtonDown then begin SetState(tsNormal); FStatusCloseButtonPressed := False; InvalidateRect(GetStatusCloseButtonRect); end; if State = tsColumnDown then begin SetState(tsNormal); FDownColumnIndex := -1; InvalidateColumn(-1); end; if State = tsColumnDragging then EndDragHeader(False); if State = tsBandButtonDown then begin SetState(tsNormal); FBandButtonPushed := False; InvalidateBandButton; end; if State = tsHeaderButtonDown then begin SetState(tsNormal); FHeaderButtonPushed := False; InvalidateHeaderButton; end; // Hide Hints HideStatusCloseButtonHint; end; procedure TCustomdxTreeList.ChangedBandAutoWidth(BandIndex, NewWidth: Integer); var OldWidth, NewAutoWidth: Integer; I, W: Integer; PInfo: PSizingInfoArray; BandCoord, InfoCount, iStart, iEnd, TotalWidth: Integer; begin InfoCount := GetBandCount; // calc resize band indexes if BandIndex = (InfoCount - 1) then begin iStart := 0; iEnd := InfoCount - 2; end else begin iStart := BandIndex + 1; iEnd := InfoCount - 1; end; PInfo := AllocMem(InfoCount * SizeOf(TSizingInfo)); try NewWidth := NewWidth - Byte(BandIndex = 0) * GetIndentWidth; TotalWidth := 0; OldWidth := GetBandWidth(BandIndex); for I := 0 to InfoCount - 1 do begin W := GetBandWidth(I); if (I = 0) then Dec(W, GetIndentWidth); // Indent if I = BandIndex then W := NewWidth; if (iStart <= I) and (I <= iEnd) then Inc(TotalWidth, W); PInfo^[I].AIndex := I; PInfo^[I].Width := W; end; BeginUpdate; try if TotalWidth > 0 then begin BandCoord := 0; NewAutoWidth := TotalWidth - (NewWidth - OldWidth); for I := iStart to iEnd do begin if I <> iEnd then W := MulDiv(PInfo^[I].Width, NewAutoWidth, TotalWidth) else W := NewAutoWidth - BandCoord; PInfo^[I].Width := W; Inc(BandCoord, W); end; ChangeHiddenBandWidth(NewAutoWidth, TotalWidth); end; // set width for I := 0 to InfoCount - 1 do if not IsBandHeaderWidth then ChangedBandWidth(I, PInfo^[I].Width) else begin MakeBandHeaderList(True); ScaledBandHeaderWidth(I, PInfo^[I].Width); end; finally EndUpdate; end; finally FreeMem(PInfo); end; end; procedure TCustomdxTreeList.ChangedHeaderAutoWidth(BandIndex, AbsoluteHeaderIndex, NewWidth: Integer); var OldBandWidth, NewBandWidth, OldWidth, NewAutoWidth: Integer; I, J, W, RIndex, CIndex, CCount, AIndex: Integer; PInfo: PSizingInfoArray; HeaderCoord, iStart, iEnd, TotalWidth: Integer; begin RIndex := GetHeaderRowIndex(AbsoluteHeaderIndex); CIndex := GetHeaderColIndex(AbsoluteHeaderIndex); CCount := GetHeaderColCount(BandIndex, RIndex); NewWidth := NewWidth - Byte((BandIndex = 0) and (CIndex = 0)) * GetIndentWidth; // calc resize band indexes if CIndex = (CCount - 1) then begin iStart := 0; iEnd := CCount - 2; end else begin iStart := CIndex + 1; iEnd := CCount - 1; end; PInfo := AllocMem(CCount * SizeOf(TSizingInfo)); try // save prev width OldBandWidth := GetBandWidth(BandIndex); OldWidth := GetHeaderBoundsWidth(AbsoluteHeaderIndex); if (BandIndex = 0) and (CIndex = 0) then Dec(OldWidth, GetIndentWidth); // Indent TotalWidth := 0; for I := 0 to CCount - 1 do begin AIndex := GetHeaderAbsoluteIndex(BandIndex, RIndex, I); W := GetHeaderBoundsWidth(AIndex); if (BandIndex = 0) and (I = 0) then Dec(W, GetIndentWidth); // Indent if I = CIndex then W := NewWidth; if (iStart <= I) and (I <= iEnd) then Inc(TotalWidth, W); PInfo^[I].AIndex := AIndex; PInfo^[I].Width := W; end; // change size BeginUpdate; try MakeBandHeaderList(False); if TotalWidth > 0 then begin HeaderCoord := 0; NewAutoWidth := TotalWidth - (NewWidth - OldWidth); for I := iStart to iEnd do begin if I <> iEnd then W := MulDiv(PInfo^[I].Width, NewAutoWidth, TotalWidth) else W := NewAutoWidth - HeaderCoord; PInfo^[I].Width := W; Inc(HeaderCoord, W); end; ChangeHiddenHeaderWidth(BandIndex, NewAutoWidth, TotalWidth); end; // set width NewBandWidth := 0; for I := 0 to CCount - 1 do begin ChangedHeaderWidth(PInfo^[I].AIndex, PInfo^[I].Width); Inc(NewBandWidth, PInfo^[I].Width); end; // change other rows if IsBandHeaderWidth and (OldBandWidth > 0) then begin for J := 0 to GetHeaderRowCount(BandIndex) - 1 do begin if J <> RIndex then begin CCount := GetHeaderColCount(BandIndex, J); for I := 0 to CCount - 1 do begin AIndex := GetHeaderAbsoluteIndex(BandIndex, J, I); W := MulDiv(GetHeaderWidth(AIndex), NewBandWidth, OldBandWidth); ChangedHeaderWidth(AIndex, W); end; end; end; end; finally EndUpdate; end; finally FreeMem(PInfo); end; end; procedure TCustomdxTreeList.DoBandDragging; var DrawInfo: TdxGridDrawInfo; P, P1: TPoint; DragCur: TCursor; NewArrowsPos: TPoint; ACurWidth: Integer; Flag, Accept: Boolean; LeftEdge, RightEdge: Integer; begin if (ScrollTimerID <> -1) then begin KillTimer(Handle, ScrollTimerID); ScrollTimerID := -1; end; GetCursorPos(P); NewArrowsPos := P; CalcDrawInfo(DrawInfo); try CalcArrowsPos(NewArrowsPos, nil, True, FDownBandIndex, FDragAbsoluteBandIndex); if (NewArrowsPos.X <> FArrowsPos.X) or (NewArrowsPos.Y <> FArrowsPos.Y) then begin DrawArrows(True); FArrowsPos := NewArrowsPos; DrawArrows(True); end; P := ScreenToClient(P); if PtInRect(Rect(DrawInfo.CRect.Left, DrawInfo.BandRect.Top, DrawInfo.CRect.Right, DrawInfo.BandRect.Bottom), P) then DragCur := Cursor else DragCur := crdxTreeListDeleteCursor; GetDragImageCursor(P, DragCur); Accept := DragCur <> crdxTreeListDeleteCursor; DoDragOverBand(P, FDragAbsoluteBandIndex, Accept); if not Accept then DragCur := crdxTreeListDeleteCursor else DragCur := Cursor; Flag := (FDragImageList.DragCursor <> DragCur); if Flag then FDragImageList.HideDragImage; FDragImageList.DragCursor := DragCur; if Flag then FDragImageList.ShowDragImage; if FDragImageList.DragCursor = crdxTreeListDeleteCursor then ACurWidth := 32 else ACurWidth := 0; P1 := FDragImageList.GetHotSpot; if FDragImageList.Dragging and ((P1.X <> (FDragImageList.Width - ACurWidth) div 2) or (P1.Y <> FDragImageList.Height div 2)) then begin P1 := ClientToScreen(Point(P.X, P.Y)); Dec(P1.X, ACurWidth div 2); FDragImageList.EndDrag; FDragImageList.SetDragImage(0, (FDragImageList.Width - ACurWidth) div 2, (FDragImageList.Height) div 2); FDragImageList.BeginDrag(GetDeskTopWindow, P1.X, P1.Y) end else P1 := ClientToScreen(Point(P.X - ACurWidth div 2, P.Y)); if not FDragImageList.Dragging then FDragImageList.BeginDrag(GetDeskTopWindow, P1.X, P1.Y) else FDragImageList.DragMove(P1.X, P1.Y); if not PointInCustomizingForm(P) then with DrawInfo do begin LeftEdge := BandRect.Left; if not IsRectEmpty(FixedBandLeftRect) then LeftEdge := FixedBandLeftRect.Right; RightEdge := BandRect.Right; if not IsRectEmpty(FixedBandRightRect) then RightEdge := FixedBandRightRect.Left; if (P.X > LeftEdge) and (P.X < LeftEdge + 3 * dxTreeListMaxResizeWidth) then begin ScrollTimerLeftFlag := True; ScrollTimerID := SetTimer(Handle, 1, tiHScroll, @ScrollTimerProc); end else if (P.X > RightEdge - 3 * dxTreeListMaxResizeWidth) and (P.X <= RightEdge) then begin ScrollTimerLeftFlag := False; ScrollTimerID := SetTimer(Handle, 1, tiHScroll, @ScrollTimerProc); end; end; finally FreeDrawInfo(DrawInfo); end; end; procedure TCustomdxTreeList.DoHeaderDragging; var DrawInfo: TdxGridDrawInfo; P, P1: TPoint; DragCur: TCursor; NewArrowsPos: TPoint; ACurWidth: Integer; Flag, Accept: Boolean; LeftEdge, RightEdge: Integer; begin if (ScrollTimerID <> -1) then begin KillTimer(Handle, ScrollTimerID); ScrollTimerID := -1; end; GetCursorPos(P); NewArrowsPos := P; CalcDrawInfo(DrawInfo); try CalcArrowsPos(NewArrowsPos, nil, False, FDownColumnIndex, FDragAbsoluteHeaderIndex); if (NewArrowsPos.X <> FArrowsPos.X) or (NewArrowsPos.Y <> FArrowsPos.Y) then begin DrawArrows(True); FArrowsPos := NewArrowsPos; DrawArrows(True); end; P := ScreenToClient(P); if PtInRect(Rect(DrawInfo.CRect.Left, DrawInfo.HeaderRect.Top, DrawInfo.CRect.Right, DrawInfo.HeaderRect.Bottom), P) then DragCur := Cursor else DragCur := crdxTreeListDeleteCursor; GetDragImageCursor(P, DragCur); Accept := DragCur <> crdxTreeListDeleteCursor; DoDragOverHeader(P, FDragAbsoluteHeaderIndex, Accept); if not Accept then DragCur := crdxTreeListDeleteCursor else DragCur := Cursor; Flag := (FDragImageList.DragCursor <> DragCur); if Flag then FDragImageList.HideDragImage; FDragImageList.DragCursor := DragCur; if Flag then FDragImageList.ShowDragImage; if FDragImageList.DragCursor = crdxTreeListDeleteCursor then ACurWidth := 32 else ACurWidth := 0; P1 := FDragImageList.GetHotSpot; if FDragImageList.Dragging and ((P1.X <> (FDragImageList.Width - ACurWidth) div 2) or (P1.Y <> FDragImageList.Height div 2)) then begin P1 := ClientToScreen(Point(P.X, P.Y)); Dec(P1.X, ACurWidth div 2); FDragImageList.EndDrag; FDragImageList.SetDragImage(0, (FDragImageList.Width - ACurWidth) div 2, (FDragImageList.Height) div 2); FDragImageList.BeginDrag(GetDeskTopWindow, P1.X, P1.Y) end else P1 := ClientToScreen(Point(P.X - ACurWidth div 2, P.Y)); if not FDragImageList.Dragging then FDragImageList.BeginDrag(GetDeskTopWindow, p1.X, p1.Y) else FDragImageList.DragMove(p1.X, p1.Y); if not PointInCustomizingForm(P) then with DrawInfo do begin LeftEdge := HeaderRect.Left; if not IsRectEmpty(FixedBandLeftRect) then LeftEdge := FixedBandLeftRect.Right; RightEdge := HeaderRect.Right; if not IsRectEmpty(FixedBandRightRect) then RightEdge := FixedBandRightRect.Left; if (P.X > LeftEdge) and (P.X < LeftEdge + 3 * dxTreeListMaxResizeWidth) then begin ScrollTimerLeftFlag := True; ScrollTimerID := SetTimer(Handle, 1, tiHScroll, @ScrollTimerProc); end else if (P.X > RightEdge - 3 * dxTreeListMaxResizeWidth) and (P.X <= RightEdge) then begin ScrollTimerLeftFlag := False; ScrollTimerID := SetTimer(Handle, 1, tiHScroll, @ScrollTimerProc); end; end; finally FreeDrawInfo(DrawInfo); end; end; procedure TCustomdxTreeList.DoScrolling; type TdxScrollDirection = (dirNone, dirLeft, dirUp, dirRight, dirDown); const ScrollTimeStep = 20; ScrollValueStep = 5; MaxSpeed = 12; var BreakOnMouseUp: Boolean; AllowHorScrolling, AllowVerScrolling: Boolean; P, PrevP: TPoint; AnchorPos: TPoint; AnchorSize: Integer; AnchorWnd: HWND; Direction: TdxScrollDirection; Speed: Integer; TimerHits: Integer; Timer: UINT; CaptureWnd: HWND; Msg: TMsg; function CreateScrollingAnchorWnd: HWND; var B: TBitmap; W, H: Integer; Rgn: HRGN; DC: HDC; function GetResourceBitmapName: string; begin if AllowHorScrolling and AllowVerScrolling then Result := 'DXGRID_FULLSCROLLBITMAP' else if AllowHorScrolling then Result := 'DXGRID_HORSCROLLBITMAP' else Result := 'DXGRID_VERSCROLLBITMAP'; end; begin B := TBitmap.Create; B.LoadFromResourceName(HInstance, GetResourceBitmapName); W := B.Width; H := B.Height; AnchorSize := W; with AnchorPos do Result := CreateWindow('STATIC', nil, WS_POPUP, X - W div 2, Y - H div 2, W, H, Handle, 0, HInstance, nil); Rgn := CreateEllipticRgn(0, 0, W + 1, H + 1); SetWindowRgn(Result, Rgn, True); SetWindowPos(Result, 0, 0, 0, 0, 0, SWP_NOZORDER or SWP_NOMOVE or SWP_NOSIZE or SWP_SHOWWINDOW or SWP_NOACTIVATE); DC := GetWindowDC(Result); BitBlt(DC, 0, 0, W, H, B.Canvas.Handle, 0, 0, SRCCOPY); Rgn := CreateEllipticRgn(0, 0, W + 1, H + 1); FrameRgn(DC, Rgn, GetSysColorBrush(COLOR_WINDOWTEXT), 1, 1); DeleteObject(Rgn); ReleaseDC(Result, DC); B.Free; end; procedure CalcDirectionAndSpeed(const P: TPoint); var DeltaX, DeltaY, SpeedValue: Integer; function GetNeutralZone: TRect; begin with AnchorPos do Result := Bounds(X - AnchorSize div 2, Y - AnchorSize div 2, AnchorSize, AnchorSize); if not AllowHorScrolling then begin Result.Left := 0; Result.Right := Screen.Width; end; if not AllowVerScrolling then begin Result.Top := 0; Result.Bottom := Screen.Height; end; end; begin if PtInRect(GetNeutralZone, P) then begin Direction := dirNone; Speed := 0; Exit; end else begin BreakOnMouseUp := True; DeltaX := P.X - AnchorPos.X; DeltaY := P.Y - AnchorPos.Y; if AllowHorScrolling and (not AllowVerScrolling or (Abs(DeltaX) > Abs(DeltaY))) then begin if DeltaX < 0 then Direction := dirLeft else Direction := dirRight; SpeedValue := Abs(DeltaX); end else begin if DeltaY < 0 then Direction := dirUp else Direction := dirDown; SpeedValue := Abs(DeltaY); end; end; Dec(SpeedValue, AnchorSize div 2); Speed := 1 + SpeedValue div ScrollValueStep; if Speed > MaxSpeed then Speed := MaxSpeed; end; procedure SetMouseCursor; var Cursor: TCursor; begin case Direction of dirLeft: Cursor := crdxTreeListLeftScroll; dirUp: Cursor := crdxTreeListUpScroll; dirRight: Cursor := crdxTreeListRightScroll; dirDown: Cursor := crdxTreeListDownScroll; else if AllowHorScrolling and AllowVerScrolling then Cursor := crdxTreeListFullScroll else if AllowHorScrolling then Cursor := crdxTreeListHorScroll else Cursor := crdxTreeListVerScroll; end; SetCursor(Screen.Cursors[Cursor]); end; procedure Scroll(Direction: TdxScrollDirection); begin case Direction of dirLeft: SendMessage(Handle, WM_HScroll, SB_LINEUP, 0); dirRight: SendMessage(Handle, WM_HScroll, SB_LINEDOWN, 0); dirUp: SendMessage(Handle, WM_VScroll, SB_LINEUP, 0); dirDown: SendMessage(Handle, WM_VScroll, SB_LINEDOWN, 0); end; end; begin BreakOnMouseUp := False; // TODO AllowHorScrolling := GetWindowLong(Handle, GWL_STYLE) and WS_HSCROLL <> 0; AllowVerScrolling := GetWindowLong(Handle, GWL_STYLE) and WS_VSCROLL <> 0; GetCursorPos(PrevP); AnchorPos := PrevP; AnchorWnd := CreateScrollingAnchorWnd; Direction := dirNone; SetMouseCursor; Speed := 1; TimerHits := 0; Timer := SetTimer(0, 0, ScrollTimeStep, nil); CaptureWnd := Handle; SetCapture(CaptureWnd); try while GetCapture = CaptureWnd do begin case Integer(GetMessage(Msg, 0, 0, 0)) of -1: Break; 0: begin PostQuitMessage(Msg.wParam); Break; end; end; case Msg.message of WM_KEYDOWN, WM_KEYUP: if Msg.wParam = VK_ESCAPE then Break; WM_MOUSEMOVE: begin P := SmallPointToPoint(TSmallPoint(Msg.lParam)); Windows.ClientToScreen(Msg.hwnd, P); if (P.X <> PrevP.X) or (P.Y <> PrevP.Y) then begin CalcDirectionAndSpeed(P); SetMouseCursor; PrevP := P; end; end; WM_MBUTTONUP: if BreakOnMouseUp then Break; WM_TIMER: if UINT(Msg.wParam) = Timer then begin Inc(TimerHits); if TimerHits mod (MaxSpeed - Speed + 1) = 0 then Scroll(Direction); end; else if (Msg.message = WM_PAINT) and (Msg.hwnd = AnchorWnd) then begin ValidateRect(AnchorWnd, nil); Continue; end; if (Msg.message >= WM_MOUSEFIRST) and (Msg.message <= WM_MOUSELAST) then Break; TranslateMessage(Msg); DispatchMessage(Msg); end; end; finally if GetCapture = CaptureWnd then ReleaseCapture; KillTimer(0, Timer); DestroyWindow(AnchorWnd); end; end; procedure TCustomdxTreeList.FreeImageList(var AImgList: TImageList); begin if AImgList <> nil then begin AImgList.Free; AImgList := nil; end; end; function TCustomdxTreeList.GetBandMinWidth(VisibleIndex: Integer): Integer; var I, J, W: Integer; begin if not CanBandSizing(VisibleIndex) then Result := GetBandSizeWidth(VisibleIndex) else Result := GetBandMinWidthSize(VisibleIndex); for J := 0 to GetHeaderRowCount(VisibleIndex) - 1 do begin W := 0; for I := 0 to GetHeaderColCount(VisibleIndex, J) - 1 do Inc(W, GetHeaderMinWidth(GetHeaderAbsoluteIndex(VisibleIndex, J, I))); if W > Result then Result := W; end; end; procedure TCustomdxTreeList.GetBandPanelResizeRanges(Y: Integer; var Min, Max: Integer); var DrawInfo: TdxGridDrawInfo; i, Y1, Y2: Integer; begin Min := Y; Max := Y; CalcRectInfo(DrawInfo); with DrawInfo do begin if not IsRectEmpty(BandRect) then begin Max := BandRect.Top + CalcBandHeight(1); for i := 2 to GetBandMaxRowCount do begin Y1 := BandRect.Top + CalcBandHeight(i - 1); Y2 := BandRect.Top + CalcBandHeight(i); if Y < (Y2 + Y1) div 2 then begin Max := BandRect.Top + CalcBandHeight(i - 1); Break; end else Max := BandRect.Top + CalcBandHeight(i); end; Min := Max; end; end; end; function TCustomdxTreeList.GetBandRealWidth(VisibleIndex: Integer): Integer; var I, J, W: Integer; begin Result := 0; if IsBandHeaderWidth then begin for J := 0 to GetHeaderRowCount(VisibleIndex) - 1 do begin W := 0; for I := 0 to GetHeaderColCount(VisibleIndex, J) - 1 do Inc(W, GetHeaderWidth(GetHeaderAbsoluteIndex(VisibleIndex, J, I))); if W > Result then Result := W; end; end; if Result = 0 then Result := GetBandSizeWidth(VisibleIndex); W := GetBandMinWidth(VisibleIndex); if Result < W then Result := W; end; procedure TCustomdxTreeList.GetBandResizeRanges(VisibleIndex, X: Integer; var Start, Min, Max: Integer); var DrawInfo: TdxGridDrawInfo; i:Integer; begin Min := X; Max := X; CalcDrawInfo(DrawInfo); try with DrawInfo do if BandsInfo <> nil then begin for i := 0 to BandCount - 1 do begin if BandsInfo^[i].Index = VisibleIndex then begin with BandsInfo^[i].BandRect do begin Start := Left; Min := Start + GetBandMinWidth(VisibleIndex) + Byte(BandsInfo^[i].Index = 0) * GetIndentWidth; if CanBandFullSizing(VisibleIndex) then Max := 100000 else Max := ClientWidth - 2; end; Break; end; end; end; finally FreeDrawInfo(DrawInfo); end; end; function TCustomdxTreeList.GetBandTotalWidth: Integer; var I, W: Integer; FlagNotSizing: Boolean; begin if GetBandCount = 0 then Result := 0 else if not IsAutoWidth then begin Result := GetIndentWidth; for i := 0 to GetBandCount - 1 do Inc(Result, GetBandWidth(i)); end else begin with GetHorzGridRect do Result := Right - Left; // Check MinWidth W := GetIndentWidth; FlagNotSizing := True; for I := 0 to GetBandCount - 1 do begin Inc(W, GetBandMinWidth(I)); if CanBandSizing(I) then FlagNotSizing := False; end; if (Result < W) or FlagNotSizing then Result := W; end; end; function TCustomdxTreeList.GetBandWidth(VisibleIndex: Integer): Integer; var I, TotalWidth, W, MinW, AllWidth, MinRealWidth, ScaledWidth, RealWidth, CalcWidth: Integer; begin if IsAutoWidth then begin if VisibleIndex = GetBandCount - 1 then begin // calc all width without self AllWidth := GetIndentWidth; for I := 0 to GetBandCount - 2 do Inc(AllWidth, GetBandWidth(I)); Result := GetBandTotalWidth - AllWidth; end else begin // calc total width TotalWidth := 0; MinRealWidth := 0; for I := 0 to GetBandCount - 1 do begin Inc(TotalWidth, GetBandRealWidth(I)); Inc(MinRealWidth, GetBandMinWidth(I)); end; RealWidth := GetBandTotalWidth - GetIndentWidth; // calc scaled total width ScaledWidth := 0; for I := 0 to GetBandCount - 1 do begin W := GetBandRealWidth(I); MinW := GetBandMinWidth(I); if CanBandSizing(I) then if MulDiv(RealWidth, W, TotalWidth) > MinW then Inc(ScaledWidth, W); end; // calc real width W := GetBandRealWidth(VisibleIndex); MinW := GetBandMinWidth(VisibleIndex); CalcWidth := MulDiv(RealWidth, W, TotalWidth); if not CanBandSizing(VisibleIndex) then Result := W else if ScaledWidth <> TotalWidth then if CalcWidth > MinW then Result := MinW + MulDiv(RealWidth - MinRealWidth, W, ScaledWidth) else Result := MinW else Result := CalcWidth; end; end else Result := GetBandRealWidth(VisibleIndex); end; function TCustomdxTreeList.GetFocusedColumnAbsoluteIndex: Integer; begin if FFocusedAbsoluteIndex = -1 then FFocusedAbsoluteIndex := GetFocusedAbsoluteIndex(FocusedColumn); Result := FFocusedAbsoluteIndex; end; procedure TCustomdxTreeList.SetFocusedColumnAbsoluteIndex(Value: Integer); begin if FocusedAbsoluteIndex <> Value then FocusedColumn := GetFocusedVisibleIndex(Value); end; function TCustomdxTreeList.GetHeaderBoundsWidth(AbsoluteIndex: Integer): Integer; var I, AIndex, BIndex, RIndex, CIndex, CCount: Integer; HeaderLeftCoord, HeaderTotalWidth, RealBandWidth, BandWidth, ScaledWidth, HeaderTotalMinWidth, W, MinW: Integer; FlagScaled: Boolean; function CalcWidth(AIndex: Integer): Integer; var MinW, W, CalcWidth: Integer; begin W := GetHeaderWidth(AIndex); MinW := GetHeaderMinWidth(AIndex); CalcWidth := MulDiv(RealBandWidth, W, HeaderTotalWidth); if CanHeaderSizing(AIndex) then begin if ScaledWidth <> HeaderTotalWidth then if CalcWidth > MinW then begin if FlagScaled then W := MinW + MulDiv(RealBandWidth - HeaderTotalMinWidth, W, ScaledWidth) else W := CalcWidth; end else W := MinW else W := CalcWidth; end else begin Dec(RealBandWidth, W); Dec(HeaderTotalWidth, W); Dec(HeaderTotalMinWidth, W); end; Result := W; end; begin BIndex := GetVisibleBandIndex(GetHeaderBandIndex(AbsoluteIndex)); RIndex := GetHeaderRowIndex(AbsoluteIndex); CIndex := GetHeaderColIndex(AbsoluteIndex); CCount := GetHeaderColCount(BIndex, RIndex); HeaderLeftCoord := 0; BandWidth := GetBandWidth(BIndex); RealBandWidth := BandWidth; HeaderTotalWidth := GetHeaderTotalWidth(BIndex, RIndex); HeaderTotalMinWidth := GetHeaderTotalMinWidth(BIndex, RIndex); // calc scaled total width ScaledWidth := 0; FlagScaled := False; for I := 0 to CCount - 1 do begin AIndex := GetHeaderAbsoluteIndex(BIndex, RIndex, I); W := GetHeaderWidth(AIndex); MinW := GetHeaderMinWidth(AIndex); if CanHeaderSizing(AIndex) then if MulDiv(RealBandWidth, W, HeaderTotalWidth) >= MinW then Inc(ScaledWidth, W) else FlagScaled := True; end; // calc real width Result := RealBandWidth; for I := 0 to CCount - 1 do begin if I <> (CCount - 1){not last} then begin AIndex := GetHeaderAbsoluteIndex(BIndex, RIndex, I); Result := CalcWidth(AIndex); if AIndex = AbsoluteIndex then Break; end else Result := BandWidth - HeaderLeftCoord; Inc(HeaderLeftCoord, Result); end; if (BIndex = 0) and (CIndex = 0) then Inc(Result, GetIndentWidth); // Indent end; (* function TCustomdxTreeList.GetHeaderBoundsWidth(AbsoluteIndex: Integer): Integer; var I, AIndex, BIndex, RIndex, CIndex, CCount: Integer; HeaderLeftCoord, HeaderTotalWidth, RealBandWidth, ScaledWidth, HeaderTotalMinWidth, W, MinW: Integer; function CalcWidth(AIndex: Integer): Integer; var MinW, W, CalcWidth: Integer; begin W := GetHeaderWidth(AIndex); MinW := GetHeaderMinWidth(AIndex); CalcWidth := MulDiv(RealBandWidth, W, HeaderTotalWidth); if CanHeaderSizing(AIndex) then begin if ScaledWidth <> HeaderTotalWidth then if CalcWidth > MinW then W := MinW + MulDiv(RealBandWidth - HeaderTotalMinWidth, W, ScaledWidth) else W := MinW else W := CalcWidth; end; Result := W; end; begin BIndex := GetVisibleBandIndex(GetHeaderBandIndex(AbsoluteIndex)); RIndex := GetHeaderRowIndex(AbsoluteIndex); CIndex := GetHeaderColIndex(AbsoluteIndex); CCount := GetHeaderColCount(BIndex, RIndex); HeaderLeftCoord := 0; RealBandWidth := GetBandWidth(BIndex); HeaderTotalWidth := GetHeaderTotalWidth(BIndex, RIndex); HeaderTotalMinWidth := GetHeaderTotalMinWidth(BIndex, RIndex); // calc scaled total width ScaledWidth := 0; for I := 0 to CCount - 1 do begin AIndex := GetHeaderAbsoluteIndex(BIndex, RIndex, I); W := GetHeaderWidth(AIndex); MinW := GetHeaderMinWidth(AIndex); if CanHeaderSizing(AIndex) then if MulDiv(RealBandWidth, W, HeaderTotalWidth) > MinW then Inc(ScaledWidth, W); end; // calc real width Result := RealBandWidth; if CIndex = (CCount - 1) then begin for I := 0 to CCount - 1 do begin if I <> (CCount - 1){not last} then begin AIndex := GetHeaderAbsoluteIndex(BIndex, RIndex, I); Result := CalcWidth(AIndex); // Result := MulDiv(RealBandWidth, GetHeaderWidth(AIndex), HeaderTotalWidth) end else Result := RealBandWidth - HeaderLeftCoord; Inc(HeaderLeftCoord, Result); end; end else begin Result := CalcWidth(AbsoluteIndex); // Result := MulDiv(RealBandWidth, GetHeaderWidth(AbsoluteIndex), HeaderTotalWidth); end; if (BIndex = 0) and (CIndex = 0) then Inc(Result, GetIndentWidth); // Indent end; *) function TCustomdxTreeList.GetHeaderLineCount(BandIndex, RowIndex, ColIndex: Integer): Integer; var C: Integer; begin Result := 1; if RowIndex = GetHeaderRowCount(BandIndex) - 1 then // is last line begin C := GetHeaderMaxRowCount; Result := GetHeaderMaxLineCount(GetHeaderAbsoluteIndex(BandIndex, RowIndex, ColIndex)); if Result = 0 then Result := C; if (Result + RowIndex) > C then Result := C - RowIndex; end; end; procedure TCustomdxTreeList.GetHeaderPanelResizeRanges(Y: Integer; var Min, Max: Integer); var DrawInfo: TdxGridDrawInfo; I: Integer; begin Min := Y; Max := Y; CalcRectInfo(DrawInfo); with DrawInfo do begin if not IsRectEmpty(HeaderRect) then begin I := (Y - HeaderRect.Top + FHeaderRowHeight div 2) div FHeaderRowHeight; if I < 1 then I := 1; if I > GetHeaderMaxLimitRowCount then I := GetHeaderMaxLimitRowCount; Max := HeaderRect.Top + FHeaderRowHeight * I; Min := Max; end; end; end; procedure TCustomdxTreeList.GetHeaderResizeRanges(AbsoluteIndex, X: Integer; var Start, Min, Max: Integer); var DrawInfo: TdxGridDrawInfo; i, j: Integer; begin Min := X; Max := X; CalcDrawInfo(DrawInfo); try with DrawInfo do if HeadersInfo <> nil then begin for i := 0 to HeaderCount - 1 do begin if HeadersInfo^[i].AbsoluteIndex = AbsoluteIndex then begin with HeadersInfo^[i].HeaderRect do begin Start := Left; Min := Left + GetHeaderMinWidth(AbsoluteIndex) + Byte((HeadersInfo^[i].BandIndex = 0) and (HeadersInfo^[i].ColIndex = 0)) * GetIndentWidth; if not IsAutoWidth and CanHeaderFullSizing(AbsoluteIndex) then Max := 100000 else if CanHeaderBandSizing then Max := ClientWidth - 1 else // calc band range coord begin Max := HeadersInfo^[i].HeaderRect.Right; for j := 0 to BandCount - 1 do begin if BandsInfo^[j].Index = HeadersInfo^[i].BandIndex then begin Max := BandsInfo^[j].BandRect.Right; Break; end; end; end; end; Break; end; end; end; finally FreeDrawInfo(DrawInfo); end; end; function TCustomdxTreeList.GetHeaderTotalMinWidth(BandIndex, RowIndex: Integer): Integer; var i: Integer; begin Result := 0; for i := 0 to GetHeaderColCount(BandIndex, RowIndex) - 1 do Inc(Result, GetHeaderMinWidth(GetHeaderAbsoluteIndex(BandIndex, RowIndex, i))); end; function TCustomdxTreeList.GetHeaderTotalWidth(BandIndex, RowIndex: Integer): Integer; var i: Integer; begin Result := 0; for i := 0 to GetHeaderColCount(BandIndex, RowIndex) - 1 do Inc(Result, GetHeaderWidth(GetHeaderAbsoluteIndex(BandIndex, RowIndex, i))); end; function TCustomdxTreeList.GetHorzGridRect: TRect; begin Result := ClientRect; if FShowIndicator then Inc(Result.Left, FIndicatorWidth); Dec(Result.Bottom, FStatusHeight); end; function TCustomdxTreeList.GetNodeFooterLevel(Node: TdxTreeListNode; Index: Integer): Integer; var FooterIndex, L: Integer; begin Result := -1; FooterIndex := -1; if IsShowRowFooter and not Node.HasChildren and Node.IsLast then begin Node := Node.Parent; while Node <> nil do begin L := Node.Level; if IsLevelFooter(L) then begin Result := L; Inc(FooterIndex); end; if FooterIndex = Index then Break; Node := Node.Parent; end; end; end; function TCustomdxTreeList.GetNodeFooterRowCount(Node: TdxTreeListNode; Level: Integer): Integer; var i, L: Integer; begin Result := -1; if not Node.HasChildren and Node.IsLast then begin Result := 0; for i := 0 to GetRowFooterCount(Node) - 1 do begin L := GetNodeFooterLevel(Node, i); if Level > L then Inc(Result); end; end; end; procedure TCustomdxTreeList.GetNodeIndent(ANode: TdxTreeListNode; var AIndent, AImageIndent: Integer); begin if ANode.HasChildren then AIndent := (ANode.Level + 1) * FIndent else AIndent := (ANode.Level + Byte(FPaintStandard)) * FIndent; if not ShowRoot then Dec(AIndent, FIndent); AImageIndent := AIndent; if ANode.StateIndex <> -1 then Inc(AImageIndent, FImageStateW); Inc(AImageIndent, FImageW); // if Assigned(Images) -> FImageW > 0 end; function TCustomdxTreeList.GetPreviewBoundsWidth(Node: TdxTreeListNode): Integer; var Ind, Indent: Integer; begin GetNodeIndent(Node, Ind, Indent); Result := GetBandTotalWidth - Byte(FShowGrid) - Indent; end; function TCustomdxTreeList.GetRowHeight(Node: TdxTreeListNode; FHeight: Integer; ReCalc: Boolean): Integer; var PreviewCount, L, H: Integer; begin // speed if IsSmartRecalcRowHeight then if not ReCalc and (Node <> nil) and (Node.FRowHeight <> 0) then begin Result := Node.FRowHeight; Exit; end; if Node <> nil then Node.FRowLineCount := 0; // TODO NEW if IsShowPreview then PreviewCount := GetRowPreviewLineCount(Node) else PreviewCount := 0; if FShowGrid then Result := GetRowSeparatorLineWidth else Result := 0; {begin ^^^} if (Node <> nil) and IsCalcRowAutoHeight then begin H := FHeight; L := GetRowLineCount(Node, H); if (L > 1) and (H = FHeight) then Inc(FHeight, FTextHeight*(L - 1)); if H > FHeight then FHeight := H; end else L := 0; {end ^^^} if (Node <> nil) and IsRowGroup(Node) then begin Inc(Result, FHeight{FRowHeight} - Byte(FShowGrid)); if FShowGrid then Inc(Result); end else begin Inc(Result, GetHeaderMaxRowCount * FHeight{FRowHeight} + PreviewCount * FDescTextHeight + Byte((PreviewCount > 0) and FShowGrid and FShowPreviewGrid)); end; if not FShowGrid and (Node <> nil) and Node.HasChildren and not FPaintStandard then Inc(Result); if (PreviewCount > 0) and (Node <> nil) and not IsRowGroup(Node) then Inc(Result, 2); if FShowGrid and FShowPreviewGrid then Dec(Result); Inc(Result, GetRowFooterCount(Node) * FFooterRowNodeHeight); // speed if not ReCalc and (Node <> nil) then begin Node.FRowHeight := Result; Node.FRowLineCount := L; // TODO NEW end; end; function TCustomdxTreeList.GetRowFooterCount(Node: TdxTreeListNode): Integer; var ANode: TdxTreeListNode; begin Result := 0; if IsShowRowFooter and (Node <> nil) and not Node.HasChildren and Node.IsLast then begin ANode := Node.Parent; while ANode <> nil do begin if Node.IsLast then begin if IsLevelFooter(ANode.Level) then Inc(Result); Node := ANode; ANode := ANode.Parent; end else Break; end; end; end; procedure TCustomdxTreeList.GetRowResizeRanges(Node: TdxTreeListNode; Y: Integer; var Min, Max: Integer); var DrawInfo: TdxGridDrawInfo; begin Min := Y; Max := Y; if Node <> nil then begin CalcRectInfo(DrawInfo); with DrawInfo do begin Min := GetRectNode(Node).Top + GetRowHeight(Node, FMinRowHeight, True{ReCalc}); if not IsRectEmpty(FooterRect) then Max := FooterRect.Top - 1 else Max := CRect.Bottom - 1; end; end; end; function TCustomdxTreeList.GetScrollableBandWidth: Integer; var FixedIndex: Integer; begin Result := GetBandTotalWidth; FixedIndex := GetBandFixedLeft; if FixedIndex <> -1 then Dec(Result, GetBandWidth(FixedIndex) + GetIndentWidth); FixedIndex := GetBandFixedRight; if FixedIndex <> -1 then Dec(Result, GetBandWidth(FixedIndex)); end; function TCustomdxTreeList.GetScrollableWidth: Integer; var R: TRect; begin R := GetScrollHorzGridRect; Result := R.Right - R.Left; end; function TCustomdxTreeList.GetScrollHorzGridRect: TRect; var FixedIndex: Integer; begin Result := GetHorzGridRect; Inc(Result.Top, FGroupPanelHeight); if not IsAutoWidth then begin FixedIndex := GetBandFixedLeft; if FixedIndex <> -1 then Inc(Result.Left, GetBandWidth(FixedIndex) + GetIndentWidth); FixedIndex := GetBandFixedRight; if FixedIndex <> -1 then Dec(Result.Right, GetBandWidth(FixedIndex)); end; end; function TCustomdxTreeList.GetStartBandCoord(VisibleIndex: Integer): Integer; var I, iStart: Integer; begin Result := 0; if (GetBandCount > 1) and (VisibleIndex >= 0) and (VisibleIndex < GetBandCount) then begin if (VisibleIndex <> GetBandFixedLeft) and (VisibleIndex <> GetBandFixedRight) then begin iStart := 0; if GetBandFixedLeft <> -1 then Inc(iStart); for i := iStart to VisibleIndex - 1 do Inc(Result, GetBandWidth(I) + Byte(I = 0)*GetIndentWidth); end; end; end; function TCustomdxTreeList.GetVisibleHeaderCount: Integer; var I: Integer; begin Result := 0; for I := 0 to GetHeaderAbsoluteCount - 1 do if IsHeaderVisible(I) then Inc(Result); end; procedure TCustomdxTreeList.HideDragImages; begin if FLockHideDragImages = 0 then begin if State in [tsColumnSizing, tsBandSizing, tsBandPanelSizing, tsHeaderPanelSizing, tsRowSizing] then DrawSizingLine; if (FDragImageList <> nil) and FDragImageList.Dragging then FDragImageList.HideDragImage; if State in [tsBandDragging, tsColumnDragging] then DrawArrows(False); {new modification} if (FDragObject <> nil) then FDragObject.HideDragImage; end; Inc(FLockHideDragImages); end; function TCustomdxTreeList.IsCalcRowAutoHeight: Boolean; begin Result := not IsShowPreview and (GetHeaderMaxRowCount = 1) and IsRowAutoHeight; end; function TCustomdxTreeList.IsFixedBand(VisibleIndex: Integer): Boolean; begin Result := False; // Result := not (csDesigning in ComponentState) and // ((VisibleIndex = GetBandFixedRight) or (VisibleIndex = GetBandFixedLeft)); end; function TCustomdxTreeList.IsFixedBandHeader(AbsoluteIndex: Integer): Boolean; {var I: Integer;} begin Result := False; { if csDesigning in ComponentState then Result := False else begin I := GetVisibleBandIndex(GetHeaderBandIndex(AbsoluteIndex)); Result := (I <> -1) and ((I = GetBandFixedLeft) or (I = GetBandFixedRight)); end;} end; procedure TCustomdxTreeList.PrepareArrowsRect(IsBand: Boolean); begin if IsBand then FArrowsRect := Rect(0, 0, arWidth{9}, FBandHeight + 2*arHeight{9}) else FArrowsRect := Rect(0, 0, arWidth{9}, FHeaderRowHeight + 2*arHeight{9}); with SaveArrowsBitmap, FArrowsRect Do begin Width := Max(Width, Right - Left); Height := Max(Height, Bottom - Top); end; end; procedure TCustomdxTreeList.PrepareDragBand(AbsoluteIndex: Integer); var bmp: TBitmap; I, W: Integer; S: string; R: TRect; AAlignment: TAlignment; begin bmp := TBitmap.Create; with bmp do begin I := GetVisibleBandIndex(AbsoluteIndex); if I <> -1 then W := GetBandWidth(I) else W := GetAbsoluteBandWidth(AbsoluteIndex); if AbsoluteIndex = 0 then Inc(W, GetIndentWidth); // Indent // check width if W > Screen.Width then W := Screen.Width; Width := W; Height := FBandHeight; end; with bmp.Canvas do begin Font.Assign(BandFont); Brush.Color := BandColor; S := GetAbsoluteBandText(AbsoluteIndex); AAlignment := GetAbsoluteBandAlignment(AbsoluteIndex); R := Rect(0, 0, bmp.Width, bmp.Height); DrawBand(Handle, R, Brush.Handle, S, False{ADown}, (FBandRowCount > 1){AMultiLine}, AAlignment, csNone{no sorted}, nil {no glyph}, hbNormal, LookAndFeel, []); end; // check image list if FDragImageList = nil then FDragImageList := TImageList.CreateSize(bmp.Width, bmp.Height); FDragImageList.AddMasked(bmp, clNone); bmp.Free; end; procedure TCustomdxTreeList.PrepareDragHeader(AbsoluteIndex: Integer); var DrawInfo: TdxGridDrawInfo; bmp: TBitmap; I, W: Integer; S: string; R: TRect; AAlignment: TAlignment; ASorted: TdxTreeListColumnSort; AGlyph: TBitmap; begin bmp := TBitmap.Create; if IsHeaderVisible(AbsoluteIndex) then W := GetHeaderBoundsWidth(AbsoluteIndex) else W := GetHeaderWidth(AbsoluteIndex); if IsHeaderVisible(AbsoluteIndex) then //is Visible Header begin CalcDrawInfo(DrawInfo); with DrawInfo do begin for i := 0 to HeaderCount - 1 do if HeadersInfo^[i].AbsoluteIndex = AbsoluteIndex then with HeadersInfo^[i] do begin W := HeaderRect.Right - HeaderRect.Left; Break; end; end; FreeDrawInfo(DrawInfo); end; // check width if W <= 0 then W := 20; if W > Screen.Width then W := Screen.Width; S := GetHeaderText(AbsoluteIndex); AAlignment := GetHeaderAlignment(AbsoluteIndex); ASorted := GetHeaderSorted(AbsoluteIndex); if IsExistHeaderGlyph(AbsoluteIndex) then AGlyph := GetHeaderGlyph(AbsoluteIndex) else AGlyph := nil; // draw bitmap with bmp, Canvas do begin Width := W; Height := FHeaderRowHeight; Font.Assign(HeaderFont); Brush.Color := HeaderColor; R := Rect(0, 0, bmp.Width, bmp.Height); DrawBand(Handle, R, Brush.Handle, S, False{ADown}, False{AMultiLine}, AAlignment, ASorted, AGlyph, hbNormal, LookAndFeel, []); end; // check image list if FDragImageList = nil then FDragImageList := TImageList.CreateSize(bmp.Width, bmp.Height); FDragImageList.AddMasked(bmp, clNone); bmp.Free; end; procedure TCustomdxTreeList.PrepareDragNode(Node: TdxTreeListNode; Column: Integer{absolute index}); const DragIndent = 20; var bmp: TBitmap; W: Integer; S: string; R, R1: TRect; begin bmp := TBitmap.Create; if Column = -1 then Column := 0; if GetVisibleHeaderCount > 0 then begin R := CellRect(Node, GetFocusedVisibleIndex(Column)); S := GetNodeDragText(Node, Column); end else begin R := Rect(0, 0, FRowHeight, 16); S := ''; end; W := R.Right - R.Left; // draw bitmap with bmp, Canvas do begin Width := W + 6 + DragIndent; // Height := FRowHeight + 6; Height := R.Bottom - R.Top{Node.FRowHeight} + 6; Font.Assign(Self.Font); Brush.Color := Self.Color; R := Rect(0, 0, bmp.Width, bmp.Height); FillRect(R); Inc(R.Left, DragIndent); // Draw Frame DrawFocusRect(R); InflateRect(R, -1, -1); DrawFocusRect(R); InflateRect(R, -1, -1); DrawFocusRect(R); InflateRect(R, -1, -1); // Draw Images R1 := R; if Node.StateIndex <> -1 then begin R1.Right := R1.Left + FImageStateW; WriteImage(bmp.Canvas, R1, StateImages, Node.StateIndex); R1.Left := R1.Right; end; if Node.ImageIndex <> -1 then begin R1.Right := R1.Left + FImageW; WriteImage(bmp.Canvas, R1, Images, Node.ImageIndex); R1.Left := R1.Right; end; // Draw text R1.Right := R.Right; SetBkMode(Handle, Windows.TRANSPARENT); DrawText(Handle, PChar(S), Length(S), R1, DT_LEFT {or DT_VCENTER or DT_SINGLELINE }or DT_WORDBREAK or // TODO ? DT_EXPANDTABS or DT_NOPREFIX or DT_END_ELLIPSIS); end; // check image list if FDragImageList = nil then FDragImageList := TImageList.CreateSize(bmp.Width, bmp.Height); FDragImageList.AddMasked(bmp, Self.Color); bmp.Free; end; procedure TCustomdxTreeList.ResetTopFocusedNodes; begin FFocused := Items[0]; SetTopVisibleNode(FFocused); end; procedure TCustomdxTreeList.ScaledBandHeaderWidth(BandIndex, NewWidth: Integer); var OldWidth: Integer; I, J, W, AIndex: Integer; PInfo: PSizingInfoArray; InfoCount: Integer; PrevLockUpdate: Boolean; begin OldWidth := GetBandWidth(BandIndex); NewWidth := NewWidth - Byte(BandIndex = 0) * GetIndentWidth; PInfo := AllocMem(GetVisibleHeaderCount * SizeOf(TSizingInfo)); InfoCount := 0; try for J := 0 to GetHeaderRowCount(BandIndex) - 1 do for I := 0 to GetHeaderColCount(BandIndex, J) - 1 do begin AIndex := GetHeaderAbsoluteIndex(BandIndex, J, I); W := GetHeaderBoundsWidth(AIndex); if (BandIndex = 0) and (I = 0) then Dec(W, GetIndentWidth); // Indent PInfo^[InfoCount].AIndex := AIndex; PInfo^[InfoCount].Width := W; Inc(InfoCount); end; PrevLockUpdate := (LockUpdate <> 0); if not PrevLockUpdate then BeginUpdate; try for I := 0 to InfoCount - 1 do begin W := MulDiv(PInfo^[I].Width, NewWidth, OldWidth); ChangedHeaderWidth(PInfo^[I].AIndex, W); end; ChangeHiddenHeaderWidth(BandIndex, NewWidth, OldWidth); ChangedBandWidth(BandIndex, NewWidth); finally if not PrevLockUpdate then EndUpdate; end; finally FreeMem(PInfo); end; end; procedure TCustomdxTreeList.ScaledHeaderBandWidth(BandIndex, AbsoluteHeaderIndex, NewWidth: Integer); var I, J, W, AIndex, RIndex, CIndex, Ccount: Integer; PInfo: PSizingInfoArray; InfoCount: Integer; HeaderCoord, OldBandWidth, NewBandWidth, OldWidth: Integer; begin PInfo := AllocMem(GetVisibleHeaderCount * SizeOf(TSizingInfo)); InfoCount := 0; try OldBandWidth := GetBandWidth(BandIndex); OldWidth := GetHeaderBoundsWidth(AbsoluteHeaderIndex); NewBandWidth := OldBandWidth + (NewWidth - OldWidth); RIndex := GetHeaderRowIndex(AbsoluteHeaderIndex); CIndex := GetHeaderColIndex(AbsoluteHeaderIndex); NewWidth := NewWidth - Byte((BandIndex = 0) and (CIndex = 0)) * GetIndentWidth; for J := 0 to GetHeaderRowCount(BandIndex) - 1 do begin HeaderCoord := 0; CCount := GetHeaderColCount(BandIndex, J); for I := 0 to CCount - 1 do begin AIndex := GetHeaderAbsoluteIndex(BandIndex, J, I); W := GetHeaderBoundsWidth(AIndex); if (BandIndex = 0) and (I = 0) then Dec(W, GetIndentWidth); // Indent if J = RIndex then begin if I = (CCount - 1) then W := NewBandWidth - HeaderCoord else if AIndex = AbsoluteHeaderIndex then W := NewWidth; end else if I <> (CCount - 1) then W := MulDiv(W, NewBandWidth, OldBandWidth) else W := NewBandWidth - HeaderCoord; Inc(HeaderCoord, W); PInfo^[InfoCount].AIndex := AIndex; PInfo^[InfoCount].Width := W; Inc(InfoCount); end; end; // change width BeginUpdate; try for I := 0 to InfoCount - 1 do ChangedHeaderWidth(PInfo^[I].AIndex, PInfo^[I].Width); ChangeHiddenHeaderWidth(BandIndex, NewBandWidth, OldBandWidth); finally EndUpdate; end; finally FreeMem(PInfo); end; end; procedure TCustomdxTreeList.ScrollGridHorz(Distance: Integer); // TODO - animation var R: TRect; begin R := GetScrollHorzGridRect; ScrollWindowEx(Handle, Distance, 0, @R, @R, 0, nil, SW_INVALIDATE); end; procedure TCustomdxTreeList.ScrollGridVert(Distance: Integer); // TODO - animation var R: TRect; begin R := GetScrollVertGridRect; ScrollWindowEx(Handle, 0, Distance, @R, @R, 0, nil, SW_INVALIDATE); if FPaintStandard and (TreeLineStyle = tlDot) then begin R.Right := R.Left + GetBandWidth(0) + GetIndentWidth; if GetBandFixedLeft <> -1 then Dec(R.Right, LeftCoord); Windows.InvalidateRect(Handle, @R, False); end; end; procedure TCustomdxTreeList.ShowDragImages; begin Dec(FLockHideDragImages); if FLockHideDragImages = 0 then begin if State in [tsColumnSizing, tsBandSizing, tsBandPanelSizing, tsHeaderPanelSizing, tsRowSizing] then DrawSizingLine; if State in [tsBandDragging, tsColumnDragging] then DrawArrows(False); if (FDragImageList <> nil) and FDragImageList.Dragging then FDragImageList.ShowDragImage; {new modification} if (FDragObject <> nil) then FDragObject.ShowDragImage; end; end; procedure TCustomdxTreeList.UpdateCustomizingColumns; begin if (FCustomizingBandListBox <> nil) then begin FCustomizingBandListBox.Flat := Boolean(Self.LookAndFeel <> lfStandard); FCustomizingBandListBox.UpdateItems; end; if (FCustomizingHeaderListBox <> nil) then begin FCustomizingHeaderListBox.Flat := Boolean(Self.LookAndFeel <> lfStandard); FCustomizingHeaderListBox.UpdateItems; end; end; procedure TCustomdxTreeList.UpdateDragging; begin UpdateWindow(Handle); end; // Copy to text format const EndOfLine = #13#10; ColumnSeparator = #9; function TCustomdxTreeList.GetHeaderTabText: string; var I, C: Integer; begin Result := ''; C := GetVisibleHeaderCount; for I := 0 to C - 1 do begin Result := Result + GetHeaderText(GetFocusedAbsoluteIndex(I)); if I <> (C - 1) then Result := Result + ColumnSeparator; end; Result := Result + EndOfLine; end; function TCustomdxTreeList.GetNodeTabText(ANode: TdxtreeListNode): string; var I, C: Integer; begin Result := ''; if IsRowGroup(ANode) then Result := ANode.Strings[0] else begin C := GetVisibleHeaderCount; for I := 0 to C - 1 do begin Result := Result + ANode.Strings[GetFocusedAbsoluteIndex(I)]; if I <> (C - 1) then Result := Result + ColumnSeparator; end; end; end; // based function TCustomdxTreeList.AcquireFocus: Boolean; begin Result := True; end; procedure TCustomdxTreeList.AddNode(Node: TdxTreeListNode); var RedrawNode: TdxTreeListNode; begin {Close Edit} CancelEditor; if TopVisibleNode = nil then SetTopVisibleNode(Node);// FTopVisibleNode := Node; if FocusedNode = nil then FFocused := TopVisibleNode; if (FLockUpdate = 0) then {**} begin RedrawNode := Node.GetPriorParentNode{GetPriorNode}; if RedrawNode = nil then RedrawNode := Node; {**} if not (csLoading in ComponentState) and not (csDestroying in ComponentState) then //MakeListNodes; MakeListNode(Node, False); {**} UpdateNode(RedrawNode, True {Below}); end; end; procedure TCustomdxTreeList.BeforeDestroy; begin Destroying; if HandleAllocated then DestroyHandle; Parent := nil; CancelEditor; end; procedure TCustomdxTreeList.BeginCustomLayout; begin end; function TCustomdxTreeList.CanDblClick: Boolean; begin Result := True; end; function TCustomdxTreeList.CheckHasChildren(Node : TdxTreeListNode) : Boolean; begin if Node.Count = 0 then Result := False else Result := True; end; procedure TCustomdxTreeList.ClearBoundsInfo; begin end; procedure TCustomdxTreeList.ClearListNodes; begin if FClearListNodesFlag then Exit; FMakeListNodesFlag := False; if FListNodes <> nil then FListNodes.Clear; if FListIndexes <> nil then FListIndexes.Clear; if FListRealNodes <> nil then FListRealNodes.Clear; FFocusedAbsoluteIndex := -1; ClearNodeRowHeight; end; procedure TCustomdxTreeList.ClearNodeRowHeight; procedure ClearRowHeightInfo(Node: TdxTreeListNode); var I: Integer; begin Node.FRowHeight := 0; for I := 0 to Node.Count - 1 do ClearRowHeightInfo(TdxTreeListNode(Node.FList.List^[I])); end; var I: Integer; begin if FClearNodes or (csDestroying in ComponentState) then Exit; for I := 0 to FNodeList.Count - 1 do ClearRowHeightInfo(TdxTreeListNode(FNodeList.List^[I])); end; procedure TCustomdxTreeList.DoAfterCollapse(Node : TdxTreeListNode); begin if Assigned(FOnCollapsed) then FOnCollapsed(Self, Node); end; procedure TCustomdxTreeList.DoAfterEditing(Node : TdxTreeListNode); begin if Assigned(FOnEdited) then FOnEdited(Self, Node); end; procedure TCustomdxTreeList.DoAfterExpand(Node : TdxTreeListNode); begin if Assigned(FOnExpanded) then FOnExpanded(Self, Node); end; procedure TCustomdxTreeList.DoBeforeCollapse(Node : TdxTreeListNode; var AllowCollapse: Boolean); begin if Assigned(FOnCollapsing) then FOnCollapsing(Self, Node, AllowCollapse); end; procedure TCustomdxTreeList.DoBeforeEditing(Node : TdxTreeListNode; var AllowEditing: Boolean); begin if Assigned(FOnEditing) then FOnEditing(Self, Node, AllowEditing); end; procedure TCustomdxTreeList.DoBeforeExpand(Node : TdxTreeListNode; var AllowExpand: Boolean); begin if Assigned(FOnExpanding) then FOnExpanding(Self, Node, AllowExpand); end; procedure TCustomdxTreeList.DoBestFitBand(BandIndex: Integer); begin end; procedure TCustomdxTreeList.DoBestFitColumn(AbsoluteIndex: Integer); begin end; procedure TCustomdxTreeList.DoChangeColumn(Node : TdxTreeListNode; Column : Integer); begin if Assigned(FOnChangeColumn) then FOnChangeColumn(Self, Node, Column); end; procedure TCustomdxTreeList.DoChangeLeftCoord; begin if Assigned(FOnChangeLeftCoord) then FOnChangeLeftCoord(Self); end; procedure TCustomdxTreeList.DoChangeNode(OldNode, Node : TdxTreeListNode); begin if Assigned(FOnChangeNode) then FOnChangeNode(Self, OldNode, Node); end; procedure TCustomdxTreeList.DoEditChange(Sender: TObject); begin if Assigned(FOnEditChange) then FOnEditChange(Sender{Column}); end; procedure TCustomdxTreeList.DoEditValidate(Sender: TObject; var ErrorText: string; var Accept: Boolean); begin if Assigned(FOnEditValidate) then FOnEditValidate(Sender{Column}, ErrorText, Accept); end; procedure TCustomdxTreeList.DoRestoreLayout; begin end; procedure TCustomdxTreeList.DoSaveLayout; begin end; procedure TCustomdxTreeList.SetEmptyNodes; begin SetTopVisibleNode(nil); // FTopVisibleNode := Nil; FFocused := nil; FInplaceColumn := -1; FInplaceNode := nil; FSelectionAnchor := nil; FSelecting := False; OldFocusedNode := nil; FDragNode := nil; FHotTrackInfo.Node := nil; end; procedure TCustomdxTreeList.DeleteNode(Node, Prior, Next: TdxTreeListNode; IsLast, Redraw: Boolean); var RedrawNode: TdxTreeListNode; begin if Assigned(FOnDeletion) then FOnDeletion(Self, Node); if FClearNodes then Exit; if IsNodeSelected(Node) then Node.Selected := False; if not (csDestroying in ComponentState) and not FClearListNodesFlag and (Count = 0) then ClearListNodes; if Count = 0 then begin SetEmptyNodes; if (FLockUpdate = 0) and not (csDestroying in ComponentState) then begin UpdateScrollBars; Invalidate; end; Exit; end; RedrawNode := nil; if TopVisibleNode = Node then begin SetTopVisibleNode(Prior); if FTopVisibleNode = nil then SetTopVisibleNode(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 OldFocusedNode = Node then OldFocusedNode := nil; if FSelectionAnchor = Node then begin FSelectionAnchor := Prior; if FSelectionAnchor = nil then FSelectionAnchor := Next; end; if FDragNode = Node then FDragNode := nil; if FHotTrackInfo.Node = Node then FHotTrackInfo.Node := nil; CancelEditor; if FMakeListNodeVisible and (FLockUpdate = 0) and not (csDestroying in ComponentState) then MakeListNode(Node, True); 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 TCustomdxTreeList.DeleteStrings(Node: TdxTreeListNode; Index: Integer); var I: Integer; begin if Index < TdxTreeListTextNode(Node).FStrings.Count then TdxTreeListTextNode(Node).FStrings.Delete(Index); for I := 0 to Node.Count - 1 do DeleteStrings(Node[I], Index); end; function TCustomdxTreeList.DoMoveFocusedColumn(FlagUp, IsTest: Boolean): Boolean; var AIndex, BIndex, RIndex, CIndex, RCount, CCount: Integer; FlagCol, FlagRow: Boolean; begin Result := False; if IsRowSelect then Exit; if (FocusedNode <> nil) and IsRowGroup(FocusedNode) then Exit; FlagCol := False; FlagRow := False; CIndex := -1; RIndex := -1; AIndex := GetFocusedAbsoluteIndex(FocusedColumn); if AIndex = -1 then Exit; BIndex := GetVisibleBandIndex(GetHeaderBandIndex(AIndex)); RCount := GetHeaderRowCount(BIndex); if RCount > 1 then begin RIndex := GetHeaderRowIndex(AIndex); CIndex := GetHeaderColIndex(AIndex); if FlagUp then begin if (RIndex = 0) and IsTopNode(FocusedNode) then Exit; if RIndex > 0 then begin Dec(RIndex); FlagCol := True; end else begin RIndex := GetHeaderRowCount(BIndex) - 1; FlagCol := True; FlagRow := True; end; end else begin if (RIndex = (RCount - 1)) and IsLastNode(FocusedNode) then Exit; if RIndex < (RCount - 1) then begin Inc(RIndex); FlagCol := True; end else // if FocusedNumber < (GetAbsoluteCount - 1) then begin RIndex := 0; FlagCol := True; FlagRow := True; end; end; end; if FlagCol then begin CCount := GetHeaderColCount(BIndex, RIndex); if CIndex >= CCount then CIndex := CCount - 1; if CIndex >= 0 then begin AIndex := GetHeaderAbsoluteIndex(BIndex, RIndex, CIndex); if AIndex <> -1 then begin CIndex := GetFocusedVisibleIndex(AIndex); if CIndex <> -1 then begin if not IsTest then FocusedColumn := CIndex; if not FlagRow then Result := True; end; end; end; end; end; procedure TCustomdxTreeList.EndCustomLayout; begin end; function TCustomdxTreeList.GetAbsoluteCount: Integer; function GetExpandedCount(Node:TdxTreeListNode):Integer; var i: Integer; begin Result := Node.Count; for I := 0 to Result - 1 do if TdxTreeListNode(Node.FList.List^[I]).Expanded then Inc(Result, GetExpandedCount(TdxTreeListNode(Node.FList.List^[I]))); end; var i: Integer; begin {**} if IsSmartNavigation then begin Result := FListNodes.Count; Exit; end; {**} Result := FNodeList.Count; for i := 0 to FNodeList.Count - 1 do if TdxTreeListNode(FNodeList.List^[I]).Expanded then Inc(Result, GetExpandedCount(TdxTreeListNode(FNodeList.List^[I]))); end; function TCustomdxTreeList.GetAbsoluteIndex(Node: TdxTreeListNode): Integer; var Ret, i: Integer; CurNode: TdxTreeListNode; function FoundNode(ParentNode, FindNode : TdxTreeListNode) : Boolean; var i : Integer; CurNode : TdxTreeListNode; 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; {**} if IsSmartNavigation then begin Result := Integer(FListIndexes[FindListNode(Node)]); Exit; end; {**} 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 TCustomdxTreeList.GetAbsoluteNode(AIndex : Integer) : TdxTreeListNode; var i : Integer; k : Integer; CurNode : TdxTreeListNode; function GetNextNodes (Node:TdxTreeListNode) : TdxTreeListNode; 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; {**} if IsSmartNavigation then begin if (0 <= AIndex) and (AIndex < FListRealNodes.Count) then Result := TdxTreeListNode(FListRealNodes[AIndex]) else Result := nil; Exit; end; {**} 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 TCustomdxTreeList.GetRectNode(Node:TdxTreeListNode): TRect; var DrawInfo: TdxGridDrawInfo; CurNode: TdxTreeListNode; Y, H: Integer; begin Result := Rect(-1, -1, -1, -1); CalcRectInfo(DrawInfo); with DrawInfo do begin CurNode := TopVisibleNode; Y := CellsRect.Top; while (CurNode <> nil) and (Y < CellsRect.Bottom) do begin H := GetRowHeight(CurNode, FRowHeight, False{ReCalc}); if CurNode = Node then begin with CellsRect do Result := Rect(Left, Y, Right, Y + H); if not IsRectEmpty(IndicatorRect) then Result.Left := IndicatorRect.Left; Break; end; Inc(Y, H); CurNode := GetNextVisible(CurNode); end; end; end; function TCustomdxTreeList.GetRectNodeBelow(Node:TdxTreeListNode): TRect; var DrawInfo: TdxGridDrawInfo; begin CalcRectInfo(DrawInfo); Result := GetRectNode(Node); Result.Bottom := DrawInfo.CellsRect.Bottom; end; function TCustomdxTreeList.GetRowNode(Node:TdxTreeListNode) : Integer; var CurRow : Integer; CurNode : TdxTreeListNode; begin Result := -1; CurNode := TopVisibleNode; CurRow := 0; While (CurNode <> Nil) and (CurRow <= VisibleRowCount) Do begin if CurNode = Node then begin Result := CurRow; Exit; end; CurNode := GetNextVisible(CurNode); Inc(CurRow); end; end; function TCustomdxTreeList.GetScrollVertGridRect: TRect; var DrawInfo: TdxGridDrawInfo; begin CalcRectInfo(DrawInfo); Result := DrawInfo.CellsRect; if not IsRectEmpty(DrawInfo.IndicatorRect) then Result.Left := DrawInfo.IndicatorRect.Left; end; function TCustomdxTreeList.GetTopNode : TdxTreeListNode; begin Result := GetNode(0); end; procedure TCustomdxTreeList.FreeClickTimer; begin if ClickTimerID <> -1 then begin KillTimer(Handle, 2{ClickTimerID}); ClickTimerID := -1; end; end; function TCustomdxTreeList.IsColumnHotTrack(X, Y: Integer; Node: TdxTreeListNode; ColumnAbsoluteIndex: Integer; var ActiveIndex: Integer): Boolean; begin Result := aoHotTrack in OptionsEx; end; function TCustomdxTreeList.IsHeaderHotTrack(X, Y: Integer; ColumnAbsoluteIndex: Integer; var HeaderHotTrack: TdxTreeListHeaderHotTrack): Boolean; var DrawInfo: TdxGridDrawInfo; I: Integer; R: TRect; begin // Result := aoHotTrack in OptionsEx; // TODO Option + Filter Result := True; HeaderHotTrack := hhtBody; CalcDrawInfo(DrawInfo); try with DrawInfo do for I := 0 to HeaderCount - 1 do if HeadersInfo^[I].AbsoluteIndex = ColumnAbsoluteIndex then begin if PtInRect(HeadersInfo^[I].HeaderClipRect, Point(X, Y)) then begin R := HeadersInfo^[I].HeaderRect; InflateRect(R, -2, -2); if (R.Right - R.Left) > dxGridHeaderFilterBoxWidth then begin R.Left := R.Right - dxGridHeaderFilterBoxWidth; if PtInRect(R, Point(X, Y)) then HeaderHotTrack := hhtDropDownButton; end; end; Break; end; finally FreeDrawInfo(DrawInfo); end; end; procedure TCustomdxTreeList.LayoutChanged; begin if FLockUpdate <> 0 then Exit; Inc(FLockUpdate); try InternalLayout; finally Dec(FLockUpdate); end; end; procedure TCustomdxTreeList.MakeBandHeaderList(CalcBounds: Boolean); begin end; procedure TCustomdxTreeList.MakeBoundsInfo; begin end; procedure TCustomdxTreeList.MakeListNode(Node: TdxTreeListNode; Deleteing: Boolean); begin FMakeListNode := Node; FMakeListNodeVisible := FMakeListNodeVisible or Node.IsVisible; try FNodeDeleteing := Deleteing; MakeListNodes; finally FMakeListNode := nil; FMakeListNodeVisible := False; end; end; procedure TCustomdxTreeList.MakeListNodes; var K: Integer; FList: TList; procedure LoadNode(ANode: TdxTreeListNode); var PValue: PdxNodeInfo; begin New(PValue); PValue^.Node := ANode; PValue^.Index := k; FList.Add(PValue); FListRealNodes.Add(ANode); Inc(k); end; procedure LoadExpanded(ANode: TdxTreeListNode); var i : Integer; begin LoadNode(ANode); for i := 0 to ANode.Count-1 do if ANode[i].Expanded then LoadExpanded(ANode[i]) else LoadNode(ANode[i]); end; function CalcAbsoluteIndex(Node: TdxTreeListNode): Integer; function CalcNextNode(Node: TdxTreeListNode): TdxTreeListNode; var I: Integer; begin if Node.Parent = nil then begin if Node = Items[Count - 1] then Result := nil else begin I := Node.FOwner.IndexOf(Node); Result := Items[I + 1]; end; end else begin I := Node.Parent.IndexOf(Node); if I < (Node.Parent.Count - 1) then Result := Node.Parent.Items[I + 1] else Result := CalcNextNode(Node.Parent); end; end; var N: TdxTreeListNode; begin N := CalcNextNode(Node); if N = nil then Result := FListRealNodes.Count else Result := Integer(FListIndexes[FindListNode(N)]); end; function FindNearestNode(Node: TdxTreeListNode): Integer; var L, H, I, C: Integer; begin L := 0; H := FListNodes.Count - 1; while L <= H do begin I := (L + H) shr 1; C := Integer(FListNodes[I]) - Integer(Node); if C < 0 then L := I + 1 else begin H := I - 1; if C = 0 then L := I; end; end; Result := L; end; var I, J: Integer; N: TdxTreeListNode; begin if (FListIndexes = nil) or (FListNodes = nil) or (FListRealNodes = nil) then Exit; if FMakeListNode <> nil then begin if FMakeListNodeVisible then begin if IsSmartNavigation then // NEW 3.0 begin if FNodeDeleteing then begin K := FindListNode(FMakeListNode); J := Integer(FListIndexes[K]); for I := 0 to FListIndexes.Count - 1 do if Integer(FListIndexes.List^[I]) >= J then FListIndexes.List^[I] := Pointer(Integer(FListIndexes.List^[I]) - 1); FListIndexes.Delete(K); FListNodes.Delete(K); FListRealNodes.Delete(J); // Check RowHeight with FMakeListNode do if (Parent <> nil) and IsLast and (Parent.Count > 1) then Parent.Items[Parent.Count - 1].FRowHeight := 0; end else begin J := CalcAbsoluteIndex(FMakeListNode); for I := 0 to FListIndexes.Count - 1 do begin if Integer(FListIndexes.List^[I]) >= J then FListIndexes.List^[I] := Pointer(Integer(FListIndexes.List^[I]) + 1); end; I := FindNearestNode(FMakeListNode); FListIndexes.Insert(I, Pointer(J)); FListNodes.Insert(I, FMakeListNode); FListRealNodes.Insert(J, FMakeListNode); // Check RowHeight with FMakeListNode do if (Parent <> nil) and IsLast and (Parent.Count > 1) then Parent.Items[Parent.Count - 2].FRowHeight := 0; end; end; end; end else begin FList := TList.Create; try FList.Capacity := Count; FListRealNodes.Clear; FListRealNodes.Capacity := Count; k := 0; for I := 0 to FNodeList.Count{Count} - 1 do begin N := TdxTreeListNode(FNodeList.List^[I]); if N.Expanded then LoadExpanded(N) else LoadNode(N); end; // sort List FList.Sort(CompareItems); // load list's FListIndexes.Clear; FListIndexes.Capacity := FList.Count; FListNodes.Clear; FListNodes.Capacity := FList.Count; for i := 0 to FList.Count - 1 do begin FListIndexes.Add(Pointer(PdxNodeInfo(FList[i])^.Index)); FListNodes.Add(Pointer(PdxNodeInfo(FList[i])^.Node)); Dispose(PdxNodeInfo(FList[i])); end; finally FList.Free; end; end; if not FClearListNodesFlag and IsRowAutoHeight then ClearNodeRowHeight; FMakeListNodesFlag := True; end; function TCustomdxTreeList.NeedShowButtonEdit(X, Y: Integer; IsCurrentNode: Boolean; ColumnAbsoluteIndex: Integer): Boolean; begin Result := IsShowButtonAlways; end; procedure TCustomdxTreeList.SetState(Value : TdxTreeListState); var PrevState: TdxTreeListState; begin PrevState := FState; FState := Value; if (FState = tsEditing) and (FInplaceEdit <> nil) then FInplaceEdit.Deselect; if (State = tsNormal) and (PrevState in [tsColumnDown, tsColumnSizing, tsBandSizing, tsBandPanelSizing, tsHeaderPanelSizing, tsRowSizing, tsColumnDragging, tsBandDragging]) then UpdateDesigner; if (FState = tsEditing) and FSearching then EndSearch; end; procedure TCustomdxTreeList.UpdateNode(Node : TdxTreeListNode; 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 UpdateScrollBars; UpdateTopLeftCoord; InvalidateRect(GetRectNodeBelow(Node)) end else InvalidateRect(GetRectNode(Node)); end; end; // based virtual & abstract function TCustomdxTreeList.CanSetData : Boolean; begin Result := True; end; function TCustomdxTreeList.GetNodeVariant(Node: TdxTreeListNode; Column: Integer) : Variant; begin Result := ''; end; procedure TCustomdxTreeList.SetFocusedNode(Node:TdxTreeListNode; Column:Integer; MakeVisibleFlag : Boolean); var NewRect, OldRect: TRect; OldNode: TdxTreeListNode; OldColumn: Integer; begin if Node = nil then Exit; HideEditor; FFocusedAbsoluteIndex := -1; OldNode := FocusedNode; OldColumn := FocusedColumn; try if FLockUpdate <> 0 then begin FFocused := Node; FFocusedColumn := Column; Exit; end; // if (Node <> nil) and MakeVisibleFlag then // ppp // Node.MakeVisible; if (FocusedNode = Node) then begin if IsRowSelect then Exit else if (FocusedColumn = Column) then Exit; end; if (FocusedNode = Node) and (not IsRowSelect) then begin MakeColumnVisible(GetFocusedAbsoluteIndex(Column)); OldRect := CellRect(FocusedNode, FocusedColumn); FFocusedColumn := Column; NewRect := CellRect(FocusedNode, FocusedColumn); InvalidateRect(OldRect); InvalidateRect(NewRect); InvalidateNewItemRow; Exit; end else if not IsRowSelect then begin FFocusedColumn := Column; MakeColumnVisible(GetFocusedAbsoluteIndex(Column)); end; OldRect := GetRectNode(FocusedNode); FFocused := Node; NewRect := GetRectNode(FocusedNode); InvalidateRect(OldRect); InvalidateRect(NewRect); NewItemRowActive := False; finally if (FocusedNode <> nil) and MakeVisibleFlag then FocusedNode.MakeVisible; // ppp if ((OldNode <> FocusedNode) and (FLockSearching = 0)) or (OldColumn <> FocusedColumn) then EndSearch; if OldNode <> FocusedNode then DoChangeNode(OldNode, FocusedNode); if OldColumn <> FocusedColumn then DoChangeColumn(FocusedNode, FocusedColumn); end; end; procedure TCustomdxTreeList.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 begin SetFocusedNode(GetAbsoluteNode(AIndex), FocusedColumn, True); end; end; end; procedure TCustomdxTreeList.SetTopVisibleNode(Node: TdxTreeListNode); begin FTopVisibleNode := Node; if Assigned(FOnChangeTopVisibleNode) then FOnChangeTopVisibleNode(Self); end; // DESIGN // GroupPanel function TCustomdxTreeList.GetGroupPanelHeight: Integer; begin Result := 0; end; // Bands function TCustomdxTreeList.GetAbsoluteBandAlignment(AbsoluteIndex: Integer): TAlignment; begin Result := taLeftJustify; end; function TCustomdxTreeList.GetAbsoluteBandCount: Integer; begin Result := 0; end; function TCustomdxTreeList.GetAbsoluteBandIndex(VisibleIndex: Integer): Integer; begin Result := VisibleIndex; end; function TCustomdxTreeList.GetAbsoluteBandText(AbsoluteIndex: Integer): string; begin Result := ''; end; function TCustomdxTreeList.GetAbsoluteBandWidth(AbsoluteIndex: Integer): Integer; begin Result := 0; end; function TCustomdxTreeList.GetBandAlignment(VisibleIndex: Integer): TAlignment; begin Result := taLeftJustify; end; function TCustomdxTreeList.GetBandCount: Integer; begin Result := 0; end; function TCustomdxTreeList.GetBandFixedLeft: Integer; begin Result := -1; end; function TCustomdxTreeList.GetBandFixedRight: Integer; begin Result := -1; end; function TCustomdxTreeList.GetBandMinWidthSize(VisibleIndex: Integer): Integer; begin Result := 0; end; function TCustomdxTreeList.GetBandSizeWidth(VisibleIndex: Integer): Integer; begin Result := 0; end; function TCustomdxTreeList.GetBandText(VisibleIndex: Integer): string; begin Result := ''; end; function TCustomdxTreeList.GetIndentWidth: Integer; begin Result := 0; end; function TCustomdxTreeList.GetVisibleBandIndex(AbsoluteIndex: Integer): Integer; begin Result := AbsoluteIndex; end; // Headers function TCustomdxTreeList.GetHeaderAbsoluteCount: Integer; begin Result := 0; end; function TCustomdxTreeList.GetHeaderAbsoluteIndex(BandIndex, RowIndex, ColIndex: Integer): Integer; begin Result := -1; end; function TCustomdxTreeList.GetHeaderAlignment(AbsoluteIndex: Integer): TAlignment; begin Result := taLeftJustify; end; function TCustomdxTreeList.GetHeaderBandIndex(AbsoluteIndex: Integer): Integer; begin Result := 0; end; function TCustomdxTreeList.GetHeaderColCount(BandIndex, RowIndex: Integer): Integer; begin Result := 0; end; function TCustomdxTreeList.GetHeaderColIndex(AbsoluteIndex: Integer): Integer; begin Result := 0; end; function TCustomdxTreeList.GetHeaderDropDownButtonState(AbsoluteIndex: Integer): TdxHeaderDropDownButtonState; begin if IsAutoFilter then begin Result := [hdbNormal]; if (FHotTrackInfo.Column = AbsoluteIndex) and (FHotTrackInfo.HeaderHotTrack = hhtDropDownButton) then begin Result := Result + [hdbSelected]; if (FDropDownButtonColumnIndex = AbsoluteIndex) and FDropDownButtonColumnPushed then Result := Result + [hdbPushed]; end; end else Result := []; end; function TCustomdxTreeList.GetHeaderGlyph(AbsoluteIndex: Integer): TBitmap; begin Result := nil; end; function TCustomdxTreeList.GetHeaderMaxLineCount(AbsoluteIndex: Integer): Integer; begin Result := 1; end; function TCustomdxTreeList.GetHeaderMinWidth(AbsoluteIndex: Integer): Integer; begin Result := 0; end; function TCustomdxTreeList.GetHeaderRowCount(BandIndex: Integer): Integer; begin Result := 0; end; function TCustomdxTreeList.GetHeaderRowIndex(AbsoluteIndex: Integer): Integer; begin Result := 0; end; function TCustomdxTreeList.GetHeaderSorted(AbsoluteIndex: Integer): TdxTreeListColumnSort; begin Result := csNone; end; function TCustomdxTreeList.GetHeaderTabStop(AbsoluteIndex: Integer): Boolean; begin Result := True; end; function TCustomdxTreeList.GetHeaderText(AbsoluteIndex: Integer): string; begin Result := ''; end; function TCustomdxTreeList.GetHeaderTextListBox(AbsoluteIndex: Integer): string; begin Result := GetHeaderText(AbsoluteIndex); end; function TCustomdxTreeList.GetHeaderWidth(AbsoluteIndex: Integer): Integer; begin Result := 0; end; function TCustomdxTreeList.GetColumnColor(AbsoluteIndex: Integer): TColor; begin Result := Self.Color; end; function TCustomdxTreeList.GetColumnFont(AbsoluteIndex: Integer): TFont; begin Result := Self.Font; end; function TCustomdxTreeList.IsExistColumnFont(AbsoluteIndex: Integer): Boolean; begin Result := False; end; function TCustomdxTreeList.IsExistHeaderGlyph(AbsoluteIndex: Integer): Boolean; begin Result := False; end; // Cells function TCustomdxTreeList.GetCellAlignment(Node: TdxTreeListNode; AbsoluteIndex: Integer): TAlignment; begin Result := taLeftJustify; end; function TCustomdxTreeList.GetCellText(Node: TdxTreeListNode; AbsoluteIndex: Integer): string; begin Result := ''; end; function TCustomdxTreeList.GetNewItemCellText(AbsoluteIndex: Integer): string; begin Result := ''; end; function TCustomdxTreeList.IsCellMultiLine(AbsoluteIndex: Integer): Boolean; begin Result := False; end; function TCustomdxTreeList.IsNewItemRowEditing: Boolean; begin Result := True; end; // Indicator function TCustomdxTreeList.GetIndicatorWidth: Integer; begin Result := 12; end; // Rows function TCustomdxTreeList.GetHeaderMaxRowHeight(ACanvas: TCanvas; AbsoluteIndex: Integer): Integer; begin Result := 0; if IsExistColumnFont(AbsoluteIndex) then begin ACanvas.Font.Assign(GetColumnFont(AbsoluteIndex)); Result := CalcTextRowHeight(ACanvas.TextHeight('Wg')); end; end; function TCustomdxTreeList.GetPreviewText(Node: TdxTreeListNode): string; begin Result := ''; end; function TCustomdxTreeList.GetRowIndicatorKind(Node: TdxTreeListNode; ASelected: Boolean): TdxGridIndicatorKind; begin Result := ikNone; end; function TCustomdxTreeList.GetRowLineCount(Node: TdxTreeListNode; var LineHeight: Integer): Integer; var I, J, AIndex, W, H, MaxLineHeight: Integer; Text: string; Ind, Indent: Integer; begin Result := -1; if (Node.FRowHeight <> 0) and (Node.FRowLineCount <> 0) then Result := Node.FRowLineCount // TODO NEW else if IsRowGroup(Node) then Result := 1 else begin J := GetVisibleHeaderCount - 1; for I := 0 to J do begin AIndex := GetFocusedAbsoluteIndex(I); Text := GetCellText(Node, AIndex); W := GetHeaderBoundsWidth(AIndex); if I = 0 then begin GetNodeIndent(Node, Ind, Indent); Dec(W, Indent); if IsInvertSelect then Dec(W); end; if I = J then if IsInvertSelect then Dec(W); MaxLineHeight := LineHeight; H := -1; // TODO PAINT2 if ShowGrid and ShowPreviewGrid then Dec(W); if ColumnCalcLineCount(Node, AIndex, Text, W, FTextHeight, MaxRowLineCount, IsInvertSelect, ShowGrid and ShowPreviewGrid{obsolete}, H, LineHeight) then begin if ShowGrid and ShowPreviewGrid then Inc(LineHeight); if IsInvertSelect then Inc(LineHeight, 2); end; if LineHeight > MaxLineHeight then MaxLineHeight := LineHeight; LineHeight := MaxLineHeight; if H > Result then Result := H; end; end; end; function TCustomdxTreeList.GetStatusButtonVisible: Boolean; begin Result := False; end; function TCustomdxTreeList.GetStatusText: string; begin Result := ''; end; function TCustomdxTreeList.GetStatusCloseButtonHint: string; begin Result := ''; end; function TCustomdxTreeList.GetStatusCloseButtonRect: TRect; var DI: TdxGridDrawInfo; begin CalcRectInfo(DI); if not IsRectEmpty(DI.StatusRect) then with DI.StatusRect do begin Result := Rect(Left, Top, Left + dxGridStatusCloseButtonSizeX, Top + dxGridStatusCloseButtonSizeY); OffsetRect(Result, 3, (Bottom - Top - dxGridStatusCloseButtonSizeY) div 2); end; end; function TCustomdxTreeList.ColumnCalcLineCount(ANode: TdxTreeListNode; AbsoluteIndex: Integer; const Text: string; BoundsWidth, TextHeight, MaxLineCount: Integer; InflateFlag, GridFlag: Boolean; var LineCount, LineHeight: Integer): Boolean; begin Result := False; end; procedure TCustomdxTreeListControl.LoadFromIniFile(const AFileName: string); var Ini: {$IFDEF DELPHI4}TMemIniFile{$ELSE}TIniFile{$ENDIF}; APath: string; begin {$IFDEF DELPHI4} Ini := TMemIniFile.Create(AFileName); {$ELSE} Ini := TIniFile.Create(AFileName); {$ENDIF} try if IniSectionName = '' then begin if GetParentForm(Self) <> nil then APath := GetParentForm(Self).Name; APath := APath + '_' + Self.Name; end else APath := IniSectionName; LoadFromRegIni(Ini, APath); finally Ini.Free; end; end; procedure TCustomdxTreeListControl.LoadFromRegistry(const ARegPath: string); var Reg: TRegIniFile; begin Reg := TRegIniFile.Create(''); try if Reg.OpenKey(ARegPath, False) then begin Reg.CloseKey; LoadFromRegIni(Reg, ARegPath); end; finally Reg.Free; end; end; procedure TCustomdxTreeListControl.SaveToIniFile(const AFileName: string); var Ini: {$IFDEF DELPHI4}TMemIniFile{$ELSE}TIniFile{$ENDIF}; APath: string; begin {$IFDEF DELPHI4} Ini := TMemIniFile.Create(AFileName); {$ELSE} Ini := TIniFile.Create(AFileName); {$ENDIF} try if IniSectionName <> '' then APath := IniSectionName else APath := FParentFormName + '_' + Self.Name; SaveToRegIni(Ini, APath); {$IFDEF DELPHI4} Ini.UpdateFile; {$ENDIF} finally Ini.Free; end; end; procedure TCustomdxTreeListControl.SaveToRegistry(const ARegPath: string); var Reg: TRegIniFile; begin Reg := TRegIniFile.Create(''); try SaveToRegIni(Reg, ARegPath); finally Reg.Free; end; end; function TCustomdxTreeList.GetRowMaxColumnHeight(ACanvas: TCanvas): Integer; var I, H: Integer; begin Result := 0; for I := 0 to GetHeaderAbsoluteCount - 1 do if IsHeaderVisible(I) then begin H := GetHeaderMaxRowHeight(ACanvas, I); if H > Result then Result := H; end; end; function TCustomdxTreeList.GetRowPreviewLineCount(Node: TdxTreeListNode): Integer; var Text: string; W, H: Integer; begin if (Node <> nil) and IsAutoCalcPreviewLines then begin Text := GetPreviewText(Node); if Text <> '' then begin W := GetPreviewBoundsWidth(Node) - IndentDesc; Result := GetTextLineCount(Text, W, FDescTextHeight, PreviewLines, FPreviewFont.Handle, False, False, H); end else Result := 0; end else Result := PreviewLines; if Result < 0 then Result := 0; end; function TCustomdxTreeList.GetRowSeparatorLineWidth: Integer; begin Result := FRowSeparatorLineWidth; if Result < 1 then Result := 1; end; procedure TCustomdxTreeList.HeaderPanelBestFit; begin end; function TCustomdxTreeList.IsRowGroup(Node: TdxTreeListNode): Boolean; begin Result := False; end; // Footer function TCustomdxTreeList.GetFooterCellAlignment(Node: TdxTreeListNode; AbsoluteIndex, FooterIndex: Integer): TAlignment; begin Result := GetCellAlignment(Node, AbsoluteIndex); end; function TCustomdxTreeList.GetFooterCellText(Node: TdxTreeListNode; AbsoluteIndex, FooterIndex: Integer): string; begin Result := ''; end; function TCustomdxTreeList.IsExistFooterCell(AbsoluteIndex: Integer): Boolean; begin Result := False; end; function TCustomdxTreeList.IsExistRowFooterCell(Node: TdxTreeListNode; AbsoluteIndex, FooterIndex: Integer): Boolean; begin Result := False; end; function TCustomdxTreeList.IsLevelFooter(Level: Integer): Boolean; begin Result := False; end; // Style function TCustomdxTreeList.IsAnsiSort: Boolean; begin Result := aoAnsiSort in OptionsEx; end; function TCustomdxTreeList.IsAutoCalcPreviewLines: Boolean; begin Result := aoAutoCalcPreviewLines in OptionsEx; end; function TCustomdxTreeList.IsAutoDragCopy: Boolean; begin Result := False; end; function TCustomdxTreeList.IsAutoSearch: Boolean; begin Result := aoAutoSearch in OptionsEx; end; function TCustomdxTreeList.IsAutoSort: Boolean; begin Result := aoAutoSort in Options; end; function TCustomdxTreeList.IsAutoHeaderPanelRowCount: Boolean; begin Result := aoAutoHeaderPanelHeight in OptionsEx; end; function TCustomdxTreeList.IsAutoSortRefresh: Boolean; begin Result := aoAutoSortRefresh in OptionsEx; end; function TCustomdxTreeList.IsAutoWidth: Boolean; begin Result := aoAutoWidth in Options; end; function TCustomdxTreeList.IsBandHeaderWidth: Boolean; begin Result := aoBandHeaderWidth in OptionsEx; end; function TCustomdxTreeList.IsCaseInsensitive: Boolean; begin Result := aoCaseInsensitive in Options; end; function TCustomdxTreeList.IsCellMultiSelect: Boolean; begin Result := aoCellMultiSelect in OptionsEx; end; function TCustomdxTreeList.IsDragCollapse: Boolean; begin Result := aoDragCollapse in OptionsEx; end; function TCustomdxTreeList.IsDrawEndEllipsis: Boolean; begin Result := aoDrawEndEllipsis in Options; end; function TCustomdxTreeList.IsDragExpand: Boolean; begin Result := aoDragExpand in OptionsEx; end; function TCustomdxTreeList.IsDragScroll: Boolean; begin Result := aoDragScroll in OptionsEx; end; function TCustomdxTreeList.IsEditing: Boolean; begin Result := aoEditing in Options; end; function TCustomdxTreeList.IsEnterShowEditor: Boolean; begin Result := aoEnterShowEditor in OptionsEx; end; function TCustomdxTreeList.IsEnterThrough: Boolean; begin Result := (aoEnterThrough in OptionsEx) and IsEnterShowEditor; end; function TCustomdxTreeList.IsExtCustomizing: Boolean; begin Result := aoExtCustomizing in Options; end; function TCustomdxTreeList.IsExtMultiSelect: Boolean; begin Result := aoExtMultiSelect in Options; end; function TCustomdxTreeList.IsFilterStatusVisible: Boolean; begin Result := False; end; function TCustomdxTreeList.IsHorzThrough: Boolean; begin Result := aoHorzThrough in OptionsEx; end; function TCustomdxTreeList.IsHScrollBarVisible: Boolean; begin Result := (FScrollBars = ssBoth) or (FScrollBars = ssHorizontal); end; function TCustomdxTreeList.IsImmediateEditor: Boolean; begin Result := aoImmediateEditor in Options; end; function TCustomdxTreeList.IsMouseScroll: Boolean; begin Result := (IsRowSelect or not IsEditing) and (aoMouseScroll in OptionsEx); end; function TCustomdxTreeList.IsMultiSelect: Boolean; begin Result := aoMultiSelect in Options; end; function TCustomdxTreeList.IsMultiSort: Boolean; begin Result := aoMultiSort in OptionsEx; end; function TCustomdxTreeList.IsNewItemRowActive: Boolean; begin Result := FNewItemRowActive; end; function TCustomdxTreeList.IsNewItemRowVisible: Boolean; begin Result := ShowNewItemRow and (NewItemRowHeight > 0); end; function TCustomdxTreeList.IsRowAutoHeight: Boolean; begin Result := (aoRowAutoHeight in OptionsEx) and (MaxRowLineCount <> 0); end; function TCustomdxTreeList.IsRowSelect: Boolean; begin Result := aoRowSelect in Options; end; function TCustomdxTreeList.IsShowHourGlass: Boolean; begin Result := aoShowHourGlass in OptionsEx; end; function TCustomdxTreeList.IsShowPreview: Boolean; begin Result := (aoPreview in Options) and (PreviewLines <> 0); end; function TCustomdxTreeList.IsShowRowFooter: Boolean; begin Result := FShowRowFooter; end; function TCustomdxTreeList.IsSmartRecalcRowHeight: Boolean; begin Result := True; end; function TCustomdxTreeList.IsTabs: Boolean; begin Result := (aoTabs in Options) and (GetAsyncKeyState(VK_CONTROL) >= 0); end; function TCustomdxTreeList.IsTabThrough: Boolean; begin Result := aoTabThrough in Options; end; function TCustomdxTreeList.IsVertThrough: Boolean; begin Result := aoVertThrough in OptionsEx; end; function TCustomdxTreeList.IsVScrollBarDisableHide: Boolean; begin Result := False; end; function TCustomdxTreeList.IsVScrollBarVisible: Boolean; begin Result := (FScrollBars = ssBoth) or (FScrollBars = ssVertical); end; function TCustomdxTreeList.IsUseBitmap: Boolean; begin Result := aoUseBitmap in OptionsEx; end; // Sizing, Clicking function TCustomdxTreeList.CanBandButtonClicking: Boolean; begin Result := aoBandButtonClicking in OptionsEx; end; function TCustomdxTreeList.CanBandFullSizing(VisibleIndex: Integer): Boolean; begin Result := aoFullSizing in OptionsEx; end; function TCustomdxTreeList.CanBandPanelSizing: Boolean; begin Result := aoBandPanelSizing in OptionsEx; end; function TCustomdxTreeList.CanBandSizing(VisibleIndex: Integer): Boolean; begin Result := True; //aoBandSizing in OptionsEx; end; function TCustomdxTreeList.CanHeaderBandSizing: Boolean; begin Result := IsBandHeaderWidth and not ShowBands {and not IsAutoWidth}; end; function TCustomdxTreeList.CanHeaderButtonClicking: Boolean; begin Result := aoHeaderButtonClicking in OptionsEx; end; function TCustomdxTreeList.CanHeaderFullSizing(AbsoluteIndex: Integer): Boolean; begin Result := aoFullSizing in OptionsEx; end; function TCustomdxTreeList.CanHeaderPanelSizing: Boolean; begin Result := aoHeaderPanelSizing in OptionsEx; end; function TCustomdxTreeList.CanHeaderSizing(AbsoluteIndex: Integer): Boolean; begin Result := True; end; function TCustomdxTreeList.CanHeaderReSizing(AbsoluteIndex: Integer): Boolean; begin Result := (aoColumnSizing in Options) and CanHeaderSizing(AbsoluteIndex); end; function TCustomdxTreeList.CanRowSizing: Boolean; begin Result := aoRowSizing in OptionsEx; end; procedure TCustomdxTreeList.ChangedBandRowCount(BandRowCount: Integer); begin end; procedure TCustomdxTreeList.ChangedBandWidth(VisibleIndex, Width: Integer); begin end; procedure TCustomdxTreeList.ChangedHeaderMaxRowCount(RowCount: Integer); begin end; procedure TCustomdxTreeList.ChangedHeaderWidth(AbsoluteIndex, Width: Integer); begin end; procedure TCustomdxTreeList.ChangeHiddenBandWidth(ScaleNum, ScaleDenom: Integer); begin end; procedure TCustomdxTreeList.ChangeHiddenHeaderWidth(BandIndex: Integer; ScaleNum, ScaleDenom: Integer); begin end; procedure TCustomdxTreeList.ChangedRowHeight(NewRowHeight: Integer); begin DefaultRowHeight := NewRowHeight; end; procedure TCustomdxTreeList.DoBandButtonClick; begin end; procedure TCustomdxTreeList.DoBandClick(VisibleIndex: Integer); begin end; procedure TCustomdxTreeList.DoChangedColumnsWidth; begin end; procedure TCustomdxTreeList.DoHeaderButtonClick; begin end; procedure TCustomdxTreeList.DoHeaderClick(AbsoluteIndex: Integer); begin end; procedure TCustomdxTreeList.DoHeaderDropDownButtonClick(AbsoluteIndex: Integer); begin end; procedure TCustomdxTreeList.DoStatusCloseButtonClick; begin end; function TCustomdxTreeList.GetBandMaxRowCount: Integer; begin Result := 5; end; function TCustomdxTreeList.GetBandRowCount: Integer; begin Result := 1; end; function TCustomdxTreeList.GetHeaderMaxLimitRowCount: Integer; begin Result := 4; end; function TCustomdxTreeList.GetHeaderMaxRowCount: Integer; begin Result := 1; end; function TCustomdxTreeList.GetHeaderLineRowCount: Integer; begin Result := 1; end; // DragDrop function TCustomdxTreeList.IsOwnBand(ABandIndex: Integer{VisibleIndex}): Boolean; begin Result := False; end; procedure TCustomdxTreeList.CalcArrowsPos(var P: TPoint; PPosInfo: Pointer; IsBand: Boolean; DownIndex, DragIndex: Integer); function IsOnlyOwnFlag(ADragIndex, AIndex, ABandIndex: Integer): Boolean; var ABandIndexDragColumn: Integer; begin ABandIndexDragColumn := GetHeaderBandIndex(ADragIndex); if AIndex <> -1 then ABandIndex := GetHeaderBandIndex(AIndex); Result := (IsOwnBand(ABandIndex) or IsOwnBand(ABandIndexDragColumn)) and (ABandIndexDragColumn <> ABandIndex); end; var DrawInfo: TdxGridDrawInfo; TempIndex: Integer; FlagBefore: Boolean; ArrowDelta: Integer; Pos, TempPos: TPoint; i, Index1, Index2: Integer; begin if IsBand then SetBandInfo(PPosInfo, -1) else SetInfo(PPosInfo, -1, -1, -1, -1); Pos := ScreenToClient(P); P := Point(-100, -100); TempIndex := -1; FlagBefore := False; ArrowDelta := arWidth div 2; if PointInCustomizingForm(ClientToScreen(Pos)) then Exit; CalcDrawInfo(DrawInfo); with DrawInfo do try if IsBand then begin if (BandRect.Top <= Pos.Y) and (Pos.Y < BandRect.Bottom) then begin SetBandInfo(PPosInfo, dxGridHeaderTempIndex); // calc band index and before-flag for i := 0 to BandCount - 1 do with BandsInfo^[i] do begin if PtInRect(BandClipRect, Pos) then begin if (Index = DownIndex{FDownBandIndex}) then Exit; FlagBefore := Pos.X <= (BandRect.Left + BandRect.Right) div 2; TempIndex := i; SetBandInfo(PPosInfo, Index); if (DownIndex <> -1) then if (FlagBefore and (Index = ({FDownBandIndex}DownIndex + 1))) or (not FlagBefore and ((Index + 1) = DownIndex{FDownBandIndex})) then begin SetBandInfo(PPosInfo, dxGridHeaderTempIndex); Exit; end; if FlagBefore and (GetBandFixedLeft = BandsInfo^[TempIndex].Index) then begin SetBandInfo(PPosInfo, dxGridHeaderTempIndex); Exit; end; if not FlagBefore and (GetBandFixedRight = BandsInfo^[TempIndex].Index) then begin SetBandInfo(PPosInfo, dxGridHeaderTempIndex); Exit; end; Break; end; end; if BandCount = 0 then begin SetBandInfo(PPosInfo, 0); Pos.Y := BandRect.Top - arHeight; Pos.X := BandRect.Left - ArrowDelta; P := ClientToScreen(Pos); Exit; end else begin if (TempIndex = -1) and (Pos.X >= BandsInfo^[BandCount - 1].BandClipRect.Right) and (BandsInfo^[BandCount - 1].Index <> DownIndex{FDownBandIndex}) and (GetBandFixedRight <> BandsInfo^[BandCount - 1].Index) then begin TempIndex := BandCount - 1; FlagBefore := False; end; end; // calc coord if TempIndex <> -1 then begin if PPosInfo <> nil then begin SetBandInfo(PPosInfo, BandsInfo^[TempIndex].Index); if not FlagBefore then begin if ((DownIndex <> -1) and (DownIndex > Integer(PPosInfo^))) or ((DownIndex = -1) and (DragIndex <> -1)) then Inc(Integer(PPosInfo^)); end else if (DownIndex <> -1) and (DownIndex < Integer(PPosInfo^)) then Dec(Integer(PPosInfo^)); end; Pos.Y := BandsInfo^[TempIndex].BandRect.Top - arHeight; if FlagBefore then Pos.X := BandsInfo^[TempIndex].BandClipRect.Left - ArrowDelta else Pos.X := BandsInfo^[TempIndex].BandClipRect.Right - ArrowDelta; // check limits if Pos.X < BandRect.Left - ArrowDelta then Pos.X := BandRect.Left - ArrowDelta; if Pos.X > BandRect.Right then Pos.X := BandRect.Right; end; end; end else if (BandCount > 0) then begin // calc header index and before-flag if (HeaderRect.Top <= Pos.Y) and (Pos.Y < HeaderRect.Bottom) then begin SetInfo(PPosInfo, -1, -1, -1, dxGridHeaderTempIndex); for i := 0 to HeaderCount - 1 do with HeadersInfo^[i] do begin if not IsFixedBandHeader(AbsoluteIndex) and PtInRect(HeaderClipRect, Pos) then begin if IsOnlyOwnFlag(DragIndex, AbsoluteIndex, -1) or (AbsoluteIndex = DownIndex{FDownColumnIndex}) then begin SetInfo(PPosInfo, BandIndex, RowIndex, ColIndex, dxGridHeaderTempIndex); Exit; end; FlagBefore := Pos.X <= (HeaderRect.Left + HeaderRect.Right) div 2; TempIndex := i; SetInfo(PPosInfo, BandIndex, RowIndex, ColIndex, AbsoluteIndex); // check nearest columns if (DownIndex <> -1) and (GetVisibleBandIndex(GetHeaderBandIndex(DownIndex)) = BandIndex) and (GetHeaderRowIndex(DownIndex) = RowIndex) then begin Index1 := GetFocusedVisibleIndex(AbsoluteIndex); Index2 := GetFocusedVisibleIndex(DownIndex); if (FlagBefore and (Index1 = (Index2 + 1))) or (not FlagBefore and ((Index1 + 1) = Index2)) then begin SetInfo(PPosInfo, BandIndex, RowIndex, ColIndex, dxGridHeaderTempIndex); Exit; end; end; Break; end; end; if (TempIndex = -1) then begin if (Pos.X >= BandsInfo^[BandCount - 1].BandClipRect.Right) then // edge last band begin TempIndex := HeaderCount - 1; TempPos := Point(BandsInfo^[BandCount - 1].BandClipRect.Right - 1, Pos.Y); for i := HeaderCount - 1 downto 0 do with HeadersInfo^[i] do begin if not IsFixedBandHeader(AbsoluteIndex) and PtInRect(HeaderClipRect, TempPos) then begin if IsOnlyOwnFlag(DragIndex, AbsoluteIndex, -1) then begin SetInfo(PPosInfo, BandIndex, RowIndex, ColIndex, dxGridHeaderTempIndex); Exit; end else begin TempIndex := i; Break; end; end; end; FlagBefore := False; end else begin // under Header ? for i := HeaderCount - 1 downto 0 do with HeadersInfo^[i] do if not IsOnlyOwnFlag(DragIndex, AbsoluteIndex, -1) and not IsFixedBandHeader(AbsoluteIndex) then begin if (HeaderClipRect.Left <= Pos.X) and (Pos.X <{=} HeaderClipRect.Right) then begin SetInfo(PPosInfo, BandIndex, RowIndex + 1, ColIndex, dxGridHeaderNewIndex); Pos.X := HeaderClipRect.Left - ArrowDelta; // check limits if Pos.X < HeaderRect.Left - ArrowDelta then Pos.X := HeaderRect.Left - ArrowDelta; if Pos.X > HeaderRect.Right then Pos.X := HeaderRect.Right; Pos.Y := HeaderRect.Top + FHeaderRowHeight - arHeight; P := ClientToScreen(Pos); Exit; end; end; // under Band ? for i := 0 to BandCount - 1 do with BandsInfo^[i] do if not IsOnlyOwnFlag(DragIndex, -1, BandsInfo^[i].Index) and not IsFixedBand(BandsInfo^[i].Index) then begin if (BandClipRect.Left <= Pos.X) and (Pos.X <{=} BandClipRect.Right) then begin SetInfo(PPosInfo, Index, 0, 0, dxGridHeaderNewIndex); Pos.X := BandClipRect.Left - ArrowDelta; // check limits if Pos.X < HeaderRect.Left - ArrowDelta then Pos.X := HeaderRect.Left - ArrowDelta; if Pos.X > HeaderRect.Right then Pos.X := HeaderRect.Right; Pos.Y := BandRect.Bottom - arHeight; P := ClientToScreen(Pos); Exit; end; end; end; end; // calc coord if TempIndex <> -1 then begin if PPosInfo <> nil then begin I := HeadersInfo^[TempIndex].ColIndex; if not FlagBefore then begin if ((DownIndex <> -1) and (DownIndex > HeadersInfo^[TempIndex].AbsoluteIndex)) or ((DragIndex <> -1) and ( (GetHeaderBandIndex(DragIndex) <> GetAbsoluteBandIndex(HeadersInfo^[TempIndex].BandIndex)) or (GetHeaderRowIndex(DragIndex) <> HeadersInfo^[TempIndex].RowIndex) ) ) or ((DragIndex <> -1) and (DownIndex = -1)) then Inc(I); end else if (I > 0) and (DownIndex <> -1) and (DownIndex < HeadersInfo^[TempIndex].AbsoluteIndex) and (GetHeaderBandIndex(DownIndex) = GetAbsoluteBandIndex(HeadersInfo^[TempIndex].BandIndex)) then Dec(I); with HeadersInfo^[TempIndex] do SetInfo(PPosInfo, BandIndex, RowIndex, I, dxGridHeaderNewIndex {AbsoluteIndex}); end; Pos.Y := HeadersInfo^[TempIndex].HeaderRect.Top - arHeight; if FlagBefore then Pos.X := HeadersInfo^[TempIndex].HeaderClipRect.Left - ArrowDelta else Pos.X := HeadersInfo^[TempIndex].HeaderClipRect.Right - ArrowDelta; // check limits if Pos.X < HeaderRect.Left - ArrowDelta then Pos.X := HeaderRect.Left - ArrowDelta; if Pos.X > HeaderRect.Right then Pos.X := HeaderRect.Right; end; end; end; finally FreeDrawInfo(DrawInfo); end; if TempIndex <> -1 then P := ClientToScreen(Pos); end; procedure TCustomdxTreeList.GetDragImageCursor(P:TPoint; var ADragCursor: TCursor); begin P := ClientToScreen(P); if PointInCustomizingForm(P) then begin if not ((GetVisibleHeaderCount = 1) and (FDownColumnIndex <> -1)) then ADragCursor := crDrag; if (FDragAbsoluteHeaderIndex <> -1) and GetHeaderDisableCustomizing(FDragAbsoluteHeaderIndex) then ADragCursor := crdxTreeListDeleteCursor; end; if (State = tsColumnDragging) and (GetBandCount = 0) then ADragCursor := crdxTreeListDeleteCursor; end; function TCustomdxTreeList.GetIsCustomizing: Boolean; begin Result := FCustomizingForm <> nil; end; function TCustomdxTreeList.GetNodeDragText(Node: TdxTreeListNode; AbsoluteIndex: Integer): string; begin Result := GetCellText(Node, AbsoluteIndex); end; function TCustomdxTreeList.IsHeaderCustomizing: Boolean; begin Result := FCustomizingForm <> nil; end; procedure TCustomdxTreeList.SetBandInfo(PPosInfo: Pointer; AIndex: Integer); begin if PPosInfo <> nil then Integer(PPosInfo^) := AIndex; end; procedure TCustomdxTreeList.SetInfo(PPosInfo: Pointer; ABandIndex, ARowIndex, AColIndex, AAbsoluteIndex: Integer); begin if PPosInfo <> nil then with PdxHeaderPosInfo(PPosInfo)^ do begin BandIndex := ABandIndex; RowIndex := ARowIndex; ColIndex := AColIndex; AbsoluteIndex := AAbsoluteIndex; end; end; // DragDrop Bands procedure TCustomdxTreeList.BandMoved(FromIndex, ToIndex: Integer); begin end; function TCustomdxTreeList.CanBandDragging(VisibleIndex: Integer): Boolean; begin Result := aoBandMoving in OptionsEx; end; procedure TCustomdxTreeList.DoDragOverBand(P: TPoint{client}; AbsoluteIndex: Integer; var Accept: Boolean); begin end; procedure TCustomdxTreeList.DoEndDragBand(P: TPoint; AbsoluteIndex, VisibleIndex: Integer; var NewIndex: Integer; var Accept: Boolean); begin end; procedure TCustomdxTreeList.EndDragBand(Flag: Boolean); var DragBandIndex: Integer; NewIndex: Integer; Accept: Boolean; P: TPoint; function GetDragBand(Pos: TPoint): Integer; begin Result := -1; Pos := ClientToScreen(Pos); CalcArrowsPos(Pos, @Result, True, DragBandIndex, FDragAbsoluteBandIndex); end; begin SetState(tsNormal); FDragImageList.EndDrag; FreeImageList(FDragImageList); DrawArrows(False); // hide Arrows DragBandIndex := FDownBandIndex; FDownBandIndex := -1; InvalidateBand(-1); if Flag and (FDragAbsoluteBandIndex <> -1) then begin GetCursorPos(P); if not PointInCustomizingForm(P) then NewIndex := GetDragBand(ScreenToClient(P)) else NewIndex := -1; Accept := True; DoEndDragBand(ScreenToClient(P), FDragAbsoluteBandIndex {absolute Index}, DragBandIndex {prev visible index}, NewIndex {new visible index}, Accept); if Accept then if (DragBandIndex <> -1) then {is visible} begin if (NewIndex <> -1) and (NewIndex <> DragBandIndex) and (NewIndex <> dxGridHeaderTempIndex) then begin BandMoved(DragBandIndex, NewIndex); MakeBandVisible(NewIndex); end else if (IsCustomizing or IsExtCustomizing) and (NewIndex = -1) and not GetBandDisableCustomizing(FDragAbsoluteBandIndex) {and (GetBandCount > 1)} then // TODO HideBand(FDragAbsoluteBandIndex); end else if IsCustomizing and (NewIndex <> -1) and (NewIndex <> dxGridHeaderTempIndex) then begin ShowBand(NewIndex, FDragAbsoluteBandIndex); end; end; end; function TCustomdxTreeList.GetBandDisableCustomizing(AbsoluteIndex: Integer): Boolean; begin Result := False; end; procedure TCustomdxTreeList.HideBand(AbsoluteIndex: Integer); begin end; function TCustomdxTreeList.IsBandInListBox(AbsoluteIndex: Integer): Boolean; begin Result := False; end; procedure TCustomdxTreeList.StartDragBand(AbsoluteIndex: Integer); var P: TPoint; begin Application.CancelHint; PrepareArrowsRect(True); PrepareDragBand(AbsoluteIndex); FDragImageList.SetDragImage(0, FDragImageList.Width div 2, FDragImageList.Height div 2); GetCursorPos(P); FArrowsPos := Point(-100, -100); FFlagSaveArrowsRect := False; DrawArrows(False); // start - save screen FDragImageList.BeginDrag(GetDeskTopWindow, P.X, P.Y); SetState(tsBandDragging); // active page in customizing box if IsCustomizing and (FCustomizingBandListBox <> nil) then with TPageControl(FCustomizingForm.FindComponent('PageControl')) do ActivePage := Pages[0]; end; procedure TCustomdxTreeList.ShowBand(NewIndex, AbsoluteIndex: Integer); begin end; // DragDrop Headers function TCustomdxTreeList.CanHeaderDragging(AbsoluteIndex: Integer): Boolean; begin Result := aoColumnMoving in Options; end; procedure TCustomdxTreeList.DoDragOverHeader(P: TPoint{client}; AbsoluteIndex: Integer; var Accept: Boolean); begin end; procedure TCustomdxTreeList.DoEndDragHeader(P: TPoint; AbsoluteIndex: Integer; var NewPosInfo: TdxHeaderPosInfo; var Accept: Boolean); begin end; procedure TCustomdxTreeList.EndDragHeader(Flag: Boolean); var NewPosInfo: TdxHeaderPosInfo; DragColumnIndex: Integer; Accept: Boolean; P: TPoint; procedure ClearPosInfo(var PosInfo: TdxHeaderPosInfo); begin FillChar(PosInfo, SizeOf(PosInfo), 0); with PosInfo do begin BandIndex := -1; RowIndex := -1; ColIndex := -1; AbsoluteIndex := -1; end; end; function GetDragColumn(Pos: TPoint): TdxHeaderPosInfo; begin ClearPosInfo(Result); Pos := ClientToScreen(Pos); CalcArrowsPos(Pos, @Result, False, DragColumnIndex, FDragAbsoluteHeaderIndex); end; begin SetState(tsNormal); FDragImageList.EndDrag; FreeImageList(FDragImageList); DrawArrows(False); // hide Arrows DragColumnIndex := FDownColumnIndex; FDownColumnIndex := -1; InvalidateColumn(-1); if Flag and (FDragAbsoluteHeaderIndex <> -1) then begin GetCursorPos(P); if not PointInCustomizingForm(P) then NewPosInfo := GetDragColumn(ScreenToClient(P)) else ClearPosInfo(NewPosInfo); Accept := True; DoEndDragHeader(ScreenToClient(P), FDragAbsoluteHeaderIndex {absolute Index}, NewPosInfo {new pos info}, Accept); if Accept then if IsHeaderVisible(FDragAbsoluteHeaderIndex) then // is Visible begin if (NewPosInfo.AbsoluteIndex <> -1) and (NewPosInfo.AbsoluteIndex <> FDragAbsoluteHeaderIndex) and (NewPosInfo.AbsoluteIndex <> dxGridHeaderTempIndex) then begin with NewPosInfo do begin HeaderMoved(FDragAbsoluteHeaderIndex, BandIndex, RowIndex, ColIndex); MakeColumnVisible(AbsoluteIndex); end; end else if (IsHeaderCustomizing or IsExtCustomizing) and (NewPosInfo.AbsoluteIndex = -1) and not GetHeaderDisableCustomizing(FDragAbsoluteHeaderIndex) and (GetVisibleHeaderCount > 1) then HideHeader(FDragAbsoluteHeaderIndex); end else if IsHeaderCustomizing and (NewPosInfo.AbsoluteIndex <> -1) and (NewPosInfo.AbsoluteIndex <> dxGridHeaderTempIndex) then begin with NewPosInfo do ShowColumnHeader(BandIndex, RowIndex, ColIndex, FDragAbsoluteHeaderIndex); end; end; end; function TCustomdxTreeList.GetDragHeaderWidth(AbsoluteIndex: Integer): Integer; begin Result := 100; end; function TCustomdxTreeList.GetHeaderDisableCustomizing(AbsoluteIndex: Integer): Boolean; begin Result := False; end; procedure TCustomdxTreeList.HeaderMoved(FromAbsoluteIndex, ToBandIndex, ToRowIndex, ToColIndex: Integer); begin end; procedure TCustomdxTreeList.HideHeader(AbsoluteIndex: Integer); begin end; function TCustomdxTreeList.IsHeaderInListBox(AbsoluteIndex: Integer): Boolean; begin Result := False; end; function TCustomdxTreeList.IsHeaderVisible(AbsoluteIndex: Integer): Boolean; begin Result := True; end; procedure TCustomdxTreeList.StartDragHeader(AbsoluteIndex: Integer); var P: TPoint; begin Application.CancelHint; PrepareArrowsRect(False); PrepareDragHeader(AbsoluteIndex); FDragImageList.SetDragImage(0, FDragImageList.Width div 2, FDragImageList.Height div 2); GetCursorPos(P); FArrowsPos := Point(-100, -100); FFlagSaveArrowsRect := False; DrawArrows(False); // start - save screen FDragImageList.BeginDrag(GetDeskTopWindow, P.X, P.Y); SetState(tsColumnDragging); // active page in customizing box if IsCustomizing and (FCustomizingBandListBox <> nil) and (FCustomizingHeaderListBox <> nil) then with TPageControl(FCustomizingForm.FindComponent('PageControl')) do ActivePage := Pages[PageCount - 1]; end; procedure TCustomdxTreeList.ShowColumnHeader(BandIndex, RowIndex, ColIndex, AbsoluteIndex: Integer); begin end; // DragDrop Nodes procedure TCustomdxTreeList.DoBeginDragNode(Node: TdxTreeListNode); begin if Assigned(FOnBeginDragNode) then FOnBeginDragNode(Self, Node); end; procedure TCustomdxTreeList.DoEndDrag(Target: TObject; X, Y: Integer); begin inherited DoEndDrag(Target, X, Y); FDragNode := nil; SetDragObject(nil); {+++} SetState(tsNormal); FreeImageList(FDragImageList); end; procedure TCustomdxTreeList.DoStartDrag(var DragObject: TDragObject); var P: TPoint; Column: Integer; begin if State = tsEditing then HideEditor; FreeClickTimer; inherited DoStartDrag(DragObject); if FDragNode = nil then begin GetCursorPos(P); with ScreenToClient(P) do FDragNode := GetNodeAt(X, Y); end; if (FDragNode <> nil) {and (GetVisibleHeaderCount > 0) }then begin Column := FocusedAbsoluteIndex {FocusedColumn}; DoBeginDragNode(FDragNode); PrepareDragNode(FDragNode, Column); SetState(tsNodeDragging); end; SetDragObject(nil);{+++} end; procedure TCustomdxTreeList.DragOver(Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); var P: TPoint; DrawInfo: TdxGridDrawInfo; FHitTest: TdxTreeListHitInfo; LeftEdge, RightEdge: Integer; begin inherited; if not (Dragging or (FDragObject <> nil)) then Exit; if (ScrollTimerID <> -1) then begin KillTimer(Handle, ScrollTimerID); ScrollTimerID := -1; end; if (ScrollNodeTimerID <> -1) then begin KillTimer(Handle, ScrollNodeTimerID); ScrollNodeTimerID := -1; end; P := Point(X, Y); FHitTest := GetHitInfo(P); if IsDragExpand then begin if (FHitTest.hitType in DragExpandHitTests) then begin FDragExpandNode := FHitTest.Node; if FDragExpandTimerId <> 0 then KillTimer(Handle, dxDragExapndTimerId); FDragExpandTimerId := SetTimer(Handle, dxDragExapndTimerId, WaitForExpandNodeTime, nil); end; end; if IsDragScroll then begin CalcDrawInfo(DrawInfo); try with DrawInfo do begin {Hor scroll} LeftEdge := CellsRect.Left; if not IsRectEmpty(FixedBandLeftRect) then LeftEdge := FixedBandLeftRect.Right; RightEdge := CellsRect.Right; if not IsRectEmpty(FixedBandRightRect) then RightEdge := FixedBandRightRect.Left; if (P.X > LeftEdge) and (P.X < LeftEdge + 3 * dxTreeListMaxResizeWidth) then begin ScrollTimerLeftFlag := True; ScrollTimerID := SetTimer(Handle, 1, tiHScroll, @ScrollTimerProc); end else if (P.X > RightEdge - 3 * dxTreeListMaxResizeWidth) and (P.X <= RightEdge) then begin ScrollTimerLeftFlag := False; ScrollTimerID := SetTimer(Handle, 1, tiHScroll, @ScrollTimerProc); end; if FHitTest.hitType in RowHitTests then begin if FHitTest.Column = -1 then FHitTest.Column := FocusedAbsoluteIndex; if ((FHitTest.Node <> FocusedNode) and (True {(GetAbsoluteIndex(TopVisibleNode) + VisibleRowCount - 1) <> GetAbsoluteIndex(FHitTest.Node)})) or ((not IsRowSelect) and IsDragScroll and (FHitTest.Column <> -1) and (FHitTest.Column <> FocusedAbsoluteIndex{FocusedColumn})) then SetFocusedNode(FHitTest.Node, GetFocusedVisibleIndex(FHitTest.Column), True); {new modification} UpdateDragging; {Vert scroll} if (FHitTest.Node = TopVisibleNode) and not IsTopNode(TopVisibleNode) then {Up} begin ScrollNodeTimerTopFlag := True; ScrollNodeTimerID := SetTimer(Handle, 1, tiVScroll, @ScrollNodeTimerProc); end; if (GetAbsoluteIndex(FHitTest.Node) >= (GetAbsoluteIndex(TopVisibleNode) + Self.RowCount - 1)) and not IsLastNode(FHitTest.Node) then {Down} begin ScrollNodeTimerTopFlag := False; ScrollNodeTimerID := SetTimer(Handle, 1, tiVScroll, @ScrollNodeTimerProc); end; end; end; finally FreeDrawInfo(DrawInfo); end; end; end; function TCustomdxTreeList.GetDragImages: {$IFDEF DELPHI4}TDragImageList{$else}TCustomImageList{$ENDIF}; begin if ShowDragImage then Result := FDragImageList else Result := nil; end; function TCustomdxTreeList.IsLastNode(ANode: TdxTreeListNode) : Boolean; begin Result := ANode = GetAbsoluteNode(GetAbsoluteCount-1); end; function TCustomdxTreeList.IsTopNode(ANode: TdxTreeListNode) : Boolean; begin Result := ANode = TopNode; end; // Size function TCustomdxTreeList.CalcDistance(Distance: Integer) : Integer; var i, TotalHeight : Integer; CurNode : TdxTreeListNode; begin if Distance < 0 then begin TotalHeight := 0; CurNode := TopVisibleNode; i := 0; while (CurNode <> Nil) and (i < abs(Distance)) do begin Inc(TotalHeight, GetRowHeight(CurNode, FRowHeight, False{ReCalc})); CurNode := GetNextVisible(CurNode); Inc(i); end; Result := - TotalHeight; end else begin TotalHeight := 0; CurNode := TopVisibleNode; if CurNode <> nil then CurNode := CurNode.GetPriorNode; i := 0; while (CurNode <> Nil) and (i < abs(Distance)) do begin Inc(TotalHeight, GetRowHeight(CurNode, FRowHeight, False{ReCalc})); CurNode := CurNode.GetPriorNode; Inc(i); end; Result := TotalHeight; end; end; function TCustomdxTreeList.CalcNearTopIndex(AIndex: Integer): Integer; var i, TotalHeight, H: Integer; CurNode: TdxTreeListNode; DrawInfo: TdxGridDrawInfo; begin Result := AIndex - RowCount + 1; CurNode := GetAbsoluteNode(AIndex); CalcRectInfo(DrawInfo); TotalHeight := 0; H := DrawInfo.CellsRect.Bottom - DrawInfo.CellsRect.Top; i := AIndex; Inc(TotalHeight, GetRowHeight(CurNode, FRowHeight, False{ReCalc})); CurNode := CurNode.GetPriorNode; while (CurNode <> nil) do begin Inc(TotalHeight, GetRowHeight(CurNode, FRowHeight, False{ReCalc})); if TotalHeight > H then Break; Dec(i); CurNode := CurNode.GetPriorNode; end; if i >= 0 then Result := i; end; function TCustomdxTreeList.CalcRowCount(ATopVisibleNode: TdxTreeListNode; AHeight: Integer; var ARowCount, AVisibleRowCount: Integer): Integer; var RowHeight{, TotalHeight}: Integer; CurNode: TdxTreeListNode; begin CurNode := ATopVisibleNode; Result := 0; ARowCount := 0; AVisibleRowCount := 0; {go Down} while (CurNode <> nil) do begin RowHeight := GetRowHeight(CurNode, FRowHeight, False{ReCalc}); if (Result + RowHeight) > AHeight then begin if Result <= AHeight then Inc(AVisibleRowCount); Inc(Result, RowHeight); Break; end; Inc(Result, RowHeight); Inc(ARowCount); Inc(AVisibleRowCount); CurNode := GetNextVisible(CurNode); end; {go Up} CurNode := ATopVisibleNode; if CurNode <> nil then CurNode := CurNode.GetPriorNode; while CurNode <> nil do begin RowHeight := GetRowHeight(CurNode, FRowHeight, False{ReCalc}); if (Result + RowHeight) > AHeight then begin if Result <= AHeight then Inc(AVisibleRowCount); Break; end; Inc(Result, RowHeight); Inc(ARowCount); Inc(AVisibleRowCount); CurNode := CurNode.GetPriorNode; end; if AVisibleRowCount < 1 then AVisibleRowCount := 1; if ARowCount < 1 then ARowCount := 1; end; procedure TCustomdxTreeList.CheckSize; var R: TRect; AStyle: LongInt; ARowCount, Dummy: Integer; DrawInfo: TdxGridDrawInfo; begin if not HandleAllocated then Exit; AStyle := GetWindowLong(Handle, GWL_STYLE); if (AStyle and WS_HSCROLL = 0) or (AStyle and WS_VSCROLL = 0) or IsVScrollBarDisableHide then Exit; // Calc Full rect CalcRectInfo(DrawInfo); R := DrawInfo.CellsRect; with R do begin Inc(Right, GetSystemMetrics(SM_CXVSCROLL)); Inc(Bottom, GetSystemMetrics(SM_CYHSCROLL)); // Calc RowCount CalcRowCount(TopVisibleNode, Bottom - Top, ARowCount, Dummy); // Check ClientHeight and ClientWidht if (GetAbsoluteCount <= ARowCount) and (GetScrollableBandWidth <= (Right - Left)) then // hide Scroll Bars begin AStyle := AStyle and not WS_HSCROLL and not WS_VSCROLL; SetWindowLong(Handle, GWL_STYLE, AStyle); SetWindowPos(Handle, 0, 0, 0, 0, 0, SWP_NOZORDER or SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_FRAMECHANGED); end; end; end; function TCustomdxTreeList.GetVisibleRowCount: Integer; begin Result := FVisibleRowCount; end; procedure TCustomdxTreeList.GetVScrollInfo(var Min, Max, Pos : Integer; var Page, Mask : UINT); var FCount : Integer; begin Min := 0; Page := RowCount; FCount := GetAbsoluteCount; Max := FCount - 1; if FCount <= RowCount then Max := 0; Pos := TopIndex; end; procedure TCustomdxTreeList.UpdateRowCount; var DrawInfo: TdxGridDrawInfo; begin CalcRectInfo(DrawInfo); with DrawInfo.CellsRect do CalcRowCount(TopVisibleNode, Bottom - Top, FRowCount, FVisibleRowCount); if FVisibleRowCount < 1 then FVisibleRowCount := 1; if FRowCount < 1 then FRowCount := 1; end; procedure TCustomdxTreeList.UpdateScrollBars; begin if not HandleAllocated then Exit; UpdateVScrollBar; UpdateHScrollBar; UpdateVScrollBar; UpdateHScrollBar; end; // Editor function TCustomdxTreeList.AssignEditValue(ANode: TdxTreeListNode; AColumn: Integer; AInplaceEdit: TdxInplaceEdit): Variant; begin // DoAfterEditing(ANode); Result := ''; end; function TCustomdxTreeList.CanEditAcceptKey(Key: Char): Boolean; begin Result := True; end; function TCustomdxTreeList.CanEditModify: Boolean; begin Result := True; end; function TCustomdxTreeList.CanEditShow: Boolean; begin Result := (FState = tsEditing) and not (csDesigning in ComponentState) and (FLockUpdate = 0) and HandleAllocated {and IsActiveControl}; end; function TCustomdxTreeList.CanTreeListAcceptKey(Key: Word; Shift: TShiftState): Boolean; begin Result := True; end; procedure TCustomdxTreeList.CheckHotTrackNode(AHitInfo: TdxTreeListHitInfo); var PrevHotTrackInfo: TdxTreeListHotTrackInfo; ACursor: TCursor; AHeaderHotTrack: TdxTreeListHeaderHotTrack; // Hint PrevActive: Boolean; R: TRect; begin if State in [tsNormal, tsStatusCloseButtonDown] then begin PrevActive := FStatusCloseButtonActive; R := GetStatusCloseButtonRect; FStatusCloseButtonActive := PtInRect(R, Point(AHitInfo.X, AHitInfo.Y)); if PrevActive <> FStatusCloseButtonActive then begin InvalidateRect(R); if FStatusCloseButtonActive and (State in [tsNormal]) then ShowStatusCloseButtonHint(False) else HideStatusCloseButtonHint; end; end; if (aoHotTrack in OptionsEx) or IsAutoFilter then begin PrevHotTrackInfo := FHotTrackInfo; with AHitInfo do begin if (Node <> nil) and (Column <> -1) and IsColumnHotTrack(X, Y, Node, Column, FHotTrackInfo.ActiveIndex) then begin FHotTrackInfo.Node := Node; FHotTrackInfo.Column := Column; FHotTrackInfo.HeaderHotTrack := hhtNone; end else if (hitType in [htColumn]) and (Column <> -1) and IsHeaderHotTrack(X, Y, Column, AHeaderHotTrack) then begin FHotTrackInfo.Node := nil; FHotTrackInfo.Column := Column; FHotTrackInfo.HeaderHotTrack := AHeaderHotTrack; if FDropDownListVisible and (FDropDownButtonColumnIndex = Column) then FHotTrackInfo.HeaderHotTrack := hhtDropDownButtonDisabled; end else begin FHotTrackInfo.Node := nil; FHotTrackInfo.Column := -1; FHotTrackInfo.HeaderHotTrack := hhtNone; end; end; if (PrevHotTrackInfo.Node <> FHotTrackInfo.Node) or (PrevHotTrackInfo.Column <> FHotTrackInfo.Column) then begin ACursor := FDefaultCursor; DoHotTrackNode(FHotTrackInfo, ACursor); FCursorChange := True; try if Cursor <> ACursor then Cursor := ACursor; finally FCursorChange := False; end; InvalidateHotTrack(PrevHotTrackInfo); InvalidateHotTrack(FHotTrackInfo); end else if (PrevHotTrackInfo.Column <> FHotTrackInfo.Column) or (PrevHotTrackInfo.HeaderHotTrack <> FHotTrackInfo.HeaderHotTrack) then begin InvalidateHotTrack(PrevHotTrackInfo); InvalidateHotTrack(FHotTrackInfo); end; end; end; function TCustomdxTreeList.CreateEditor(AColumn: Integer): TdxInplaceEdit; begin Result := TdxInplaceTreeListTextEdit.Create(Self); end; function TCustomdxTreeList.CreateEditStyle(AEdit: TdxInplaceEdit): TdxEditStyle; begin Result := TdxTreeListEditStyle.Create(AEdit, Self); end; procedure TCustomdxTreeList.DoBeforeEditNewItemRow(var Allow: Boolean); begin end; procedure TCustomdxTreeList.DoBeginNewItemActive; begin end; procedure TCustomdxTreeList.DoHotTrackNode(AHotTrackInfo: TdxTreeListHotTrackInfo; var ACursor: TCursor); begin if Assigned(FOnHotTrackNode) then FOnHotTrackNode(Self, AHotTrackInfo, ACursor); end; function TCustomdxTreeList.EditStyleBorderColor: TColor; begin Result := clWindowFrame; end; function TCustomdxTreeList.EditStyleBorderStyle: TdxEditBorderStyle; begin if ShowGrid then Result := xbsNone else Result := xbsSingle; end; function TCustomdxTreeList.EditStyleButtonStyle: TdxEditButtonViewStyle; const AEditStyleButtonStyle: array [TdxLookAndFeel] of TdxEditButtonViewStyle = ( bts3D, btsFlat, btsHotFlat); begin Result := AEditStyleButtonStyle[LookAndFeel]; end; function TCustomdxTreeList.EditStyleButtonTransparence: TdxEditButtonTransparence; begin Result := ebtNone; end; function TCustomdxTreeList.EditStyleEdges: TdxEditEdges; begin Result := [edgLeft, edgTop, edgRight, edgBottom]; end; function TCustomdxTreeList.EditStyleHotTrack: Boolean; begin Result := False; end; function TCustomdxTreeList.EditStyleShadow: Boolean; begin Result := False; end; function TCustomdxTreeList.FindInplaceEdit(AColumn : Integer):TdxInplaceEdit; begin if FInplaceEdit <> nil then Result := FInplaceEdit else Result := nil; end; function TCustomdxTreeList.GetEditColor: TColor; var I: Integer; begin Result := inherited GetEditColor; I := FocusedAbsoluteIndex; if I <> -1 then Result := GetColumnColor(I); if Assigned(FOnGetEditColor) then FOnGetEditColor(Self, Result); end; function TCustomdxTreeList.GetEditFont: TFont; var I: Integer; begin Result := inherited GetEditFont; I := FocusedAbsoluteIndex; if (I <> -1) and IsExistColumnFont(I) then Result := GetColumnFont(I); end; function TCustomdxTreeList.GetEditingText : String; begin Result := ''; if (FState = tsEditing) and (FInplaceEdit <> Nil) then Result := FInplaceEdit.GetEditingText; end; procedure TCustomdxTreeList.InitEditProperties(AInplaceEdit: TdxInplaceEdit); var DC: HDC; begin with TdxInplaceTreeListEdit(AInplaceEdit) do // TODO 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); // Activate TODO? // SetActive(True); end; end; function TCustomdxTreeList.InitEditValue(ANode: TdxTreeListNode; AInplaceEdit: TdxInplaceEdit): Variant; begin Result := ''; end; procedure TCustomdxTreeList.InvalidateEditor; begin if FCanceling then Exit; FInplaceColumn := -1; FInplaceNode := nil; UpdateEdit(False); end; function TCustomdxTreeList.IsEditorMoved: Boolean; begin Result := (InplaceColumnIndex <> FocusedColumn); end; function TCustomdxTreeList.IsHotTrackNode(ANode: TdxTreeListNode; AIndex: Integer): Boolean; begin Result := (FHotTrackInfo.Node = ANode) and (FHotTrackInfo.Column = AIndex); end; procedure TCustomdxTreeList.MoveCol(ALeft: Boolean); begin CloseEditor; if ALeft then FocusedColumn := FocusedColumn - 1 else FocusedColumn := FocusedColumn + 1; end; procedure TCustomdxTreeList.RedrawSelection; begin InvalidateSelection; end; procedure TCustomdxTreeList.SetEditingText(Value : String); begin if (FState = tsEditing) and (FInplaceEdit <> Nil) then FInplaceEdit.SetEditingText(Value); end; function TCustomdxTreeList.CanFullMultiSelect: Boolean; begin Result := True; end; function TCustomdxTreeList.GetFirstSelectedNode: TdxTreeListNode; begin if SelectedCount > 0 then Result := SelectedNodes[0] else if FFirstSelectedNode <> nil then Result := FFirstSelectedNode else Result := nil; end; function TCustomdxTreeList.CanNodeSelected(ANode: TdxTreeListNode): Boolean; var Node: TdxTreeListNode; begin Result := True; if Assigned(FOnCanNodeSelected) then FOnCanNodeSelected(Self, ANode, Result); if Result and not IsExtMultiSelect then begin Node := GetFirstSelectedNode; if Node <> nil then Result := Node.Parent = ANode.Parent; end; end; procedure TCustomdxTreeList.ClearSelection; begin FSelecting := False; DoSelectedCountChange; end; function TCustomdxTreeList.CompareSelectionAnchor(ANode: TdxTreeListNode) : Integer; var i1, i2: Integer; begin i1 := GetAbsoluteIndex(ANode); i2 := GetAbsoluteIndex(SelectionAnchor); if i1 = i2 then Result := 0 else if i1 < i2 then Result := -1 else Result := 1; end; procedure TCustomdxTreeList.DeleteSelection; begin FSelecting := False; if GetSelectedCount = 0 then Exit; end; procedure TCustomdxTreeList.DoSelectedCountChange; begin if not (csDestroying in ComponentState) and (FLockSelection = 0) then if Assigned(FOnSelectedCountChange) then FOnSelectedCountChange(Self); end; function TCustomdxTreeList.GetSelectedCount : Integer; begin Result := 0; end; function TCustomdxTreeList.GetSelectedItem(AIndex : Integer) : TdxTreeListNode; begin Result := nil; end; procedure TCustomdxTreeList.InvalidateSelection; var i: Integer; begin if FocusedNode <> nil then InvalidateRect(GetRectNode(FocusedNode)); if SelectedCount > 10 then Invalidate else for i := 0 to SelectedCount - 1 do InvalidateRect(GetRectNode(SelectedNodes[i])); end; function TCustomdxTreeList.IsNodeSelected(ANode:TdxTreeListNode):Boolean; begin Result := False; end; procedure TCustomdxTreeList.NodeSelected(ANode: TdxTreeListNode; ASelected: Boolean); begin DoSelectedCountChange; end; procedure TCustomdxTreeList.SelectNodes(N1, N2 : TdxTreeListNode); var i1, i2, c : Integer; StartNode, EndNode : TdxTreeListNode; begin BeginSelection; try try StartNode := N1; EndNode := N2; i1 := GetAbsoluteIndex(N1); i2 := GetAbsoluteIndex(N2); if i1 > i2 then begin StartNode := N2; EndNode := N1; end; c := 0; while (StartNode <> Nil) Do begin StartNode.Selected := True; Inc(c); if (StartNode = EndNode) or ((c-1) >= Abs(i1-i2)) then Break; StartNode := GetNextVisible(StartNode); end; except end; finally EndSelection; end; end; procedure TCustomdxTreeList.SetSelectionAnchor(ANode : TdxTreeListNode); begin FSelectionAnchor := ANode; end; // Sorting procedure TCustomdxTreeList.ClearColumnsSorted; begin end; function TCustomdxTreeList.CompareEqual(Node1, Node2: TdxTreeListNode): Integer; begin Result := Integer(Node1) - Integer(Node2); end; procedure TCustomdxTreeList.DoSortColumn(StartIndex, ColIndex: Integer; FlagDesc: Boolean); procedure SortLevel(L: TList; C: Integer); var i: Integer; begin if C = 0 then DoSortNodes(L, ColIndex, FlagDesc) else if L <> nil then begin Dec(C); for i := 0 to L.Count - 1 do SortLevel(TdxTreeListNode(L[i]).FList, C); end; end; procedure SortTree(L: TList); var i: Integer; begin DoSortNodes(L, ColIndex, FlagDesc); if L <> nil then for i := 0 to L.Count - 1 do SortTree(TdxTreeListNode(L[i]).FList); end; var OldCursor : TCursor; {$IFDEF EGRID_DEBUG} t1, t2: LongInt; {$ENDIF} begin OldCursor := Screen.Cursor; if IsShowHourGlass then Screen.Cursor := crHourglass; {$IFDEF EGRID_DEBUG} t1 := GetTickCount; {$ENDIF} try if StartIndex <> -1 then SortLevel(FNodeList, StartIndex) else SortTree(FNodeList); finally Screen.Cursor := OldCursor; end; {$IFDEF EGRID_DEBUG} t2 := GetTickCount; if Assigned(OnDebugEvent) then OnDebugEvent(Self, etSort, t2 - t1); {$ENDIF} end; procedure TCustomdxTreeList.DoSortNodes(List: TList; Col: Integer; FlagDesc: Boolean); var PValue: PNodeVariant; PNext, PPrevNext: PNextVariant; PPNext: ^PNextVariant; FList: TList; I, J, C: Integer; FlagMulti: Boolean; begin if (List = nil) or (List.Count <= 1) then Exit; FList := TList.Create; try C := GetSortedColumnCount; // FlagMulti := IsMultiSort and (C > 1); FlagMulti := IsMultiSortColumn(Col) and (C > 1); FList.Capacity := List.Count; if FlagMulti then begin Col := GetSortedColumnIndex(0); FlagDesc := GetSortedColumnDesc(0); end; // load values for I := 0 to List.Count - 1 do begin New(PValue); PValue^.Node := TdxTreeListNode(List[I]); PValue^.Value := GetNodeVariant(PValue^.Node, Col); PValue^.Desc := FlagDesc; PValue^.PNext := nil; if FlagMulti then begin PPNext := @PValue^.PNext; for J := 1 to C - 1 do begin New(PNext); PNext.Node := PValue^.Node; PNext.Value := GetNodeVariant(PValue^.Node, GetSortedColumnIndex(J)); PNext.Desc := GetSortedColumnDesc(J); PNext.PNext := nil; PPNext^ := PNext; PPNext := @PNext^.PNext; end; end; FList.Add(PValue); end; // sort items if Assigned(FOnCompare) then begin FList.Sort(CustomCompareNodes); { MultiSort if not FlagDesc then FList.Sort(CustomCompareNodes) else FList.Sort(CustomCompareNodesDesc); } end else begin if not IsAnsiSort then FList.Sort(CompareVariantValues) else FList.Sort(CompareAnsiVariantValues); end; // assign order for I := 0 to List.Count - 1 do begin PValue := PNodeVariant(FList[I]); List[I] := PValue^.Node; if FlagMulti then begin PNext := PValue^.PNext; while PNext <> nil do begin PPrevNext := PNext; PNext := PNext^.PNext; Dispose(PPrevNext); end; end; Dispose(PValue); end; finally FList.Free; end; end; function TCustomdxTreeList.GetSortedColumnCount: Integer; begin Result := 0; end; function TCustomdxTreeList.GetSortedColumnDesc(Index: Integer): Boolean; begin Result := False; end; function TCustomdxTreeList.GetSortedColumnIndex(Index: Integer): Integer; begin Result := Index; end; function TCustomdxTreeList.IsMultiSortColumn(AbsoluteIndex: Integer): Boolean; begin Result := IsMultiSort; end; // Paint function TCustomdxTreeList.AssignedDrawBandEvent(VisibleIndex: Integer): Boolean; begin Result := False; end; function TCustomdxTreeList.AssignedDrawCellEvent(ANode: TdxTreeListNode; AbsoluteIndex: Integer): Boolean; begin Result := False; end; function TCustomdxTreeList.AssignedDrawFooterCellEvent(ANode: TdxTreeListNode; AbsoluteIndex, FooterIndex: Integer): Boolean; begin Result := False; end; function TCustomdxTreeList.AssignedDrawHeaderEvent(AbsoluteIndex: Integer): Boolean; begin Result := False; end; function TCustomdxTreeList.AssignedDrawPreviewEvent: Boolean; begin Result := False; end; function TCustomdxTreeList.AssignedLevelColorEvent: Boolean; begin Result := False; end; procedure TCustomdxTreeList.DoDrawBand(VisibleIndex: Integer; ACanvas: TCanvas; ARect, AClipRect: TRect; var AText: string; var AColor: TColor; AFont: TFont; var AAlignment: TAlignment; var ADone: Boolean); begin end; procedure TCustomdxTreeList.DoDrawCell(ACanvas: TCanvas; var ARect: TRect; ANode: TdxTreeListNode; AIndex: Integer; ASelected, AFocused: Boolean; ANewItemRow: Boolean; ALeftEdge, ARightEdge: Boolean; ABrush: HBRUSH; var AText: string; var AColor: TColor; AFont: TFont; var AAlignment: TAlignment; var ADone: Boolean); begin end; procedure TCustomdxTreeList.DoDrawFooterCell(ACanvas: TCanvas; ARect: TRect; ANode: TdxTreeListNode; AIndex, AFooterIndex: Integer; var AText: string; var AColor: TColor; AFont: TFont; var AAlignment: TAlignment; var ADone: Boolean); begin end; procedure TCustomdxTreeList.DoDrawHeader(AbsoluteIndex: Integer; ACanvas: TCanvas; ARect, AClipRect: TRect; var AText: string; var AColor: TColor; AFont: TFont; var AAlignment: TAlignment; var ASorted: TdxTreeListColumnSort; var ADone: Boolean); begin end; procedure TCustomdxTreeList.DoDrawPreview(ACanvas: TCanvas; ARect: TRect; ANode: TdxTreeListNode; ASelected: Boolean; var AText: string; var AColor, ATextColor: TColor; AFont: TFont; var ADone: Boolean); begin end; procedure TCustomdxTreeList.DoGetLevelColor(ALevel: Integer; var AColor: TColor); begin end; procedure TCustomdxTreeList.DefaultDrawCell(ADC: HDC; ARect: TRect; AAbsoluteIndex: Integer; ACellViewData: TdxTreeListCellViewData); begin end; procedure TCustomdxTreeListControl.CalcCellViewBoundsRect(const ACellRect: TRect; var AViewRect: TRect); begin AViewRect := ACellRect; InflateRect(AViewRect, 2, 2); end; procedure TCustomdxTreeListControl.DefaultDrawCell(ADC: HDC; ARect: TRect; AAbsoluteIndex: Integer; ACellViewData: TdxTreeListCellViewData); begin with Columns[AAbsoluteIndex] do begin FActualNode := ACellViewData.Cell_Node; try PrepareViewData(ViewData, ACellViewData); with ACellViewData do if Cell_InvertSelect then DrawColumnIndent(ADC, ARect, Cell_LeftEdge, Cell_RightEdge, Cell_Brush); CalcCellViewBoundsRect(ARect, ViewData.ViewBounds); GetdxInplaceEditClass.Draw(ADC, ARect, ViewData, 0); finally FActualNode := nil; end; end; end; procedure TCustomdxTreeList.DrawCellEx(ACanvas: TCanvas; ARect: TRect; ABitmap: TBitmap; {temp draw bitmap} ANode: TdxTreeListNode; AIndex: Integer; ASelected, AFocused: Boolean; ACellColor, ACellTextColor: TColor; ABrush: HBRUSH; AMultiLine: Boolean; ACellKind: TdxGridDrawCellKind; ALeftEdge, ARightEdge: Boolean; ACellBkColor: TColor; ACellBkBrush: HBRUSH); var S: string; Done, ExistEvent, ExistFont: Boolean; AAlignment: TAlignment; AColor, AFontColor: TColor; AFont: TFont; begin with ACanvas do begin if ANode <> nil then PrepareNode(ANode); try if ACellKind in [ckRow, ckGroup] then S := GetCellText(ANode, AIndex) else S := GetNewItemCellText(AIndex); AAlignment := GetCellAlignment(ANode, AIndex); // cell color if ACellKind in [ckRow, ckNewItemRow] then ExistFont := IsExistColumnFont(AIndex) else ExistFont := False; AColor := ACellColor; AFont := ACanvas.Font; AFontColor := AFont.Color; // begin custom draw ExistEvent := AssignedDrawCellEvent(ANode, AIndex); if ExistEvent or ExistFont then begin if not ExistFont then AFont.Color := ACellTextColor; FSaveFont.Assign(AFont); if ExistFont then begin AFont.Assign(GetColumnFont(AIndex)); if ASelected then AFont.Color := ACellTextColor else ACellTextColor := AFont.Color; end; AFontColor := AFont.Color; // TODO: check it end; Done := False; DoDrawCell(ACanvas, ARect, ANode, AIndex, ASelected, AFocused, (ACellKind = ckNewItemRow), ALeftEdge, ARightEdge, ABrush, S, ACellColor, AFont, AAlignment, Done); if not Done then // Default Drawing begin if ExistEvent then begin if ColorToRGB(AColor) <> ColorToRGB(ACellColor) then begin Brush.Color := ACellColor; ABrush := Brush.Handle; end; if ColorToRGB(AFontColor) <> ColorToRGB(AFont.Color) then // TODO ? ACellTextColor := AFont.Color; end; // Default Draw with FCellViewData do begin Cell_Brush := ABrush; Cell_Font := AFont.Handle; Cell_BkColor := ACellColor; Cell_TextColor := ACellTextColor; Cell_Alignment := AAlignment; Cell_Text := S; Cell_TextLength := 0; Cell_Selected := ASelected; Cell_InvertSelect := IsInvertSelect; Cell_LeftEdge := ALeftEdge; Cell_RightEdge := ARightEdge; Cell_MultiLine := AMultiLine; Cell_InvertText := False; Cell_DrawEndEllipsis := IsDrawEndEllipsis; Cell_Node := ANode; Cell_IsNullNode := (ACellKind = ckNewItemRow) and not IsNewItemRowEditing; if AFocused then Cell_SelectionColor := HighlightColor else Cell_SelectionColor := HideSelectionColor; Cell_CellBrush := ACellBkBrush; Cell_CellColor := ACellBkColor; Cell_HotTrackNode := IsHotTrackNode(ANode, AIndex); with ARect do Cell_Rect := Rect(0, 0, Right - Left, Bottom - Top); InflateRect(Cell_Rect, 2, 2); // TODO PAINT2 end; DefaultDrawCell(Handle, ARect, AIndex, FCellViewData); // Search Text Invert if FSearching and AFocused and (ACellKind = ckRow) and (FSearchColumnIndex = AIndex) then begin if FSearchText <> '' then begin if AutoSearchColor = clNone then ACellColor := ColorToRGB(ACellColor) xor $00FFFFFF else ACellColor := AutoSearchColor; Brush.Color := ACellColor; ABrush := Brush.Handle; if AutoSearchTextColor = clNone then ACellTextColor := ColorToRGB(ACellTextColor) xor $00FFFFFF else ACellTextColor := AutoSearchTextColor; // Default Draw with FCellViewData do begin Cell_Brush := ABrush; Cell_Font := AFont.Handle; Cell_BkColor := ACellColor; Cell_TextColor := ACellTextColor; Cell_Alignment := AAlignment; Cell_Text := S; Cell_TextLength := Length(FSearchText); // * Cell_Selected := ASelected; Cell_InvertSelect := IsInvertSelect; Cell_LeftEdge := ALeftEdge; Cell_RightEdge := ARightEdge; Cell_MultiLine := AMultiLine; Cell_InvertText := True; // * Cell_DrawEndEllipsis := IsDrawEndEllipsis; Cell_Node := ANode; if AFocused then Cell_SelectionColor := HighlightColor else Cell_SelectionColor := HideSelectionColor; Cell_CellBrush := ACellBkBrush; Cell_CellColor := ACellBkColor; Cell_HotTrackNode := IsHotTrackNode(ANode, AIndex); with ARect do Cell_Rect := Rect(0, 0, Right - Left, Bottom - Top); InflateRect(Cell_Rect, 2, 2); // TODO PAINT2 end; DefaultDrawCell(Handle, ARect, AIndex, FCellViewData); end; // Draw Focus Rect InflateRect(ARect, -1, -1); if IsRowSelect or IsInvertSelect then begin if not ALeftEdge then Dec(ARect.Left); if not ARightEdge then Inc(ARect.Right); end; DrawFocused(Handle, ARect); end; end; // end custom draw if ExistEvent or ExistFont then Font.Assign(FSaveFont); finally if ANode <> nil then UnPrepareNode(ANode); end; end; end; procedure TCustomdxTreeList.DrawCell(ACanvas: TCanvas; ARect: TRect; ABitmap: TBitmap; ANode: TdxTreeListNode; AIndex, AFooterIndex: Integer; ASelected, AFocused: Boolean; ACellColor: TColor; ABrush: HBRUSH; AMultiLine: Boolean; ACellKind: TdxGridDrawCellKind; ALeftEdge, ARightEdge: Boolean); var S: string; ExistEvent, Done, ExistFont: Boolean; AAlignment: TAlignment; AColor: TColor; AFont: TFont; PrevBkColor: TColorRef; begin with ACanvas do begin if ANode <> nil then PrepareNode(ANode); try if (ACellKind <> ckFooter) then begin if ACellKind in [ckRow, ckGroup] then S := GetCellText(ANode, AIndex) else S := GetNewItemCellText(AIndex); AAlignment := GetCellAlignment(ANode, AIndex); end else begin S := GetFooterCellText(ANode, AIndex, AFooterIndex); AAlignment := GetFooterCellAlignment(ANode, AIndex, AFooterIndex); end; // cell color if ACellKind in [ckRow, ckNewItemRow] then ExistFont := IsExistColumnFont(AIndex) else ExistFont := False; AColor := ACellColor; AFont := ACanvas.Font; Done := False; // begin custom draw if (ACellKind <> ckFooter) then ExistEvent := AssignedDrawCellEvent(ANode, AIndex) else ExistEvent := AssignedDrawFooterCellEvent(ANode, AIndex, AFooterIndex); if ExistEvent or ExistFont then begin AFont.Color := GetTextColor(Handle); FSaveFont.Assign(AFont); // Canvas.Font <- Self.Font if ExistFont then begin AFont.Assign(GetColumnFont(AIndex)); if ASelected then AFont.Color := FSaveFont.Color; end; end; PrevBkColor := GetBkColor(Handle); if (ACellKind <> ckFooter) then DoDrawCell(ACanvas, ARect, ANode, AIndex, ASelected, AFocused, (ACellKind = ckNewItemRow), ALeftEdge, ARightEdge, ABrush, S, AColor, AFont, AAlignment, Done) else DoDrawFooterCell(ACanvas, ARect, ANode, AIndex, AFooterIndex, S, AColor, AFont, AAlignment, Done); if not Done then begin if ColorToRGB(AColor) <> ColorToRGB(ACellColor) then begin Brush.Color := AColor; ABrush := Brush.Handle; SetBkColor(Handle, ColorToRGB(AColor)); end; DrawCellText(Handle, ARect, ABrush, AColor, ABitmap, S, Length(S), AMultiLine, IsDrawEndEllipsis{AEndEllipsis}, AAlignment, IsUseBitmap, (ACellKind <> ckFooter) and IsInvertSelect, False); // Search Text Invert if FSearching and AFocused and (ACellKind = ckRow) and ({FocusedAbsoluteIndex}FSearchColumnIndex = AIndex) then begin if FSearchText <> '' then begin if AutoSearchColor = clNone then AColor := ColorToRGB(AColor) xor $00FFFFFF else AColor := AutoSearchColor; Brush.Color := AColor; ABrush := Brush.Handle; if not (ExistEvent or ExistFont) then begin AFont.Color := GetTextColor(Handle); FSaveFont.Assign(AFont); // Canvas.Font <- Self.Font ExistFont := True; end; if AutoSearchTextColor = clNone then AFont.Color := ColorToRGB(AFont.Color) xor $00FFFFFF else AFont.Color := AutoSearchTextColor; SetBkColor(Handle, ColorToRGB(AColor)); SetTextColor(Handle, ColorToRGB(AFont.Color)); DrawCellText(Handle, ARect, ABrush, AColor, ABitmap, S, Length(FSearchText), AMultiLine, IsDrawEndEllipsis{AEndEllipsis}, AAlignment, IsUseBitmap, (ACellKind <> ckFooter) and IsInvertSelect, True); end; // Draw Focus Rect InflateRect(ARect, -1, -1); if IsRowSelect or IsInvertSelect then begin if not ALeftEdge then Dec(ARect.Left); if not ARightEdge then Inc(ARect.Right); end; DrawFocused(Handle, ARect); end; end; // end custom draw if ExistEvent or ExistFont then Font.Assign(FSaveFont); if ColorToRGB(AColor) <> ColorToRGB(ACellColor) then SetBkColor(Handle, PrevBkColor); finally if ANode <> nil then UnPrepareNode(ANode); end; end; end; procedure TCustomdxTreeList.DrawGroupPanel(ACanvas: TCanvas; ARect: TRect; HeaderBrush, PanelBrush: HBRUSH); begin end; procedure TCustomdxTreeList.DrawPreview(ACanvas: TCanvas; ARect: TRect; ABitmap: TBitmap; ANode: TdxTreeListNode; AColor, ATextColor: TColor; ABrush: HBRUSH; ASelected: Boolean); var S: string; ANewColor: TColor; AFont: TFont; PrevBkColor: TColorRef; Done{, ExistEvent}: Boolean; begin with ACanvas do begin S := GetPreviewText(ANode); if AColor <> FHighlightColor then ATextColor := FPreviewFont.Color; ANewColor := AColor; AFont := ACanvas.Font; FSaveFont.Assign(AFont); // Canvas.Font <- Self.Font AFont.Assign(FPreviewFont); Done := False; { ExistEvent := AssignedDrawPreviewEvent; if ExistEvent then begin AFont := FPreviewFont; AFont.Color := GetTextColor(Handle); FSaveFont.Assign(AFont); // Canvas.Font <- Self.Font end;} PrevBkColor := GetBkColor(Handle); DoDrawPreview(ACanvas, ARect, ANode, ASelected, S, ANewColor, ATextColor, AFont, Done); if not Done then begin if ColorToRGB(AColor) <> ColorToRGB(ANewColor) then begin Brush.Color := ANewColor; ABrush := Brush.Handle; SetBkColor(Handle, ColorToRGB(ANewColor)); end; DrawPreviewText(Handle, ARect, ABrush, AFont.Handle, ABitmap, ATextColor, S, IndentDesc, IsUseBitmap); end; // end custom draw // if ExistEvent then AFont.Assign(FSaveFont); if ColorToRGB(AColor) <> ColorToRGB(ANewColor) then SetBkColor(Handle, PrevBkColor); end; end; function TCustomdxTreeList.GetGridColor(ABrushColor : TColor) : TColor; begin if FGridLineColor <> clNone then Result := FGridLineColor else Result := FGridColor; end; procedure TCustomdxTreeList.InvalidateHotTrack(AHotTrackInfo: TdxTreeListHotTrackInfo); var Ind, FullInd: Integer; R: TRect; begin with AHotTrackInfo do begin // Node if (Node <> nil) and (Column <> -1) then begin R := CellRect(Node, GetFocusedVisibleIndex(Column)); InvalidateRect(R); // Indent TODO PAINT GetNodeIndent(Node, Ind, FullInd); R.Left := 0; R.Right := FullInd; InvalidateRect(R); end; // Header if (Column <> -1) and (HeaderHotTrack <> hhtNone) then begin InvalidateColumn(Column); end; end; end; procedure TCustomdxTreeList.InvalidateRect(ARect: TRect); begin if not HandleAllocated then Exit; Windows.InvalidateRect(Handle, @ARect, False); end; procedure TCustomdxTreeList.PrepareNode(ANode: TdxTreeListNode); begin end; procedure TCustomdxTreeList.UnPrepareNode(ANode: TdxTreeListNode); begin end; // private TCustomdxTreeList // based function TCustomdxTreeList.FindListNode(Node: TdxTreeListNode): Integer; var L, H, I, C: Integer; begin Result := -1; L := 0; H := FListNodes.Count - 1; while L <= H do begin I := (L + H) shr 1; C := {DWORD}Integer(FListNodes.List^[I]) - {DWORD}Integer(Node); if C = 0 then begin Result := I; Break; end else if (C < 0) then L := I + 1 else H := I - 1; end; end; function TCustomdxTreeList.GetCount: Integer; begin Result := FNodeList.Count; end; function TCustomdxTreeList.GetFocused: TdxTreeListNode; begin Result := FFocused; end; function TCustomdxTreeList.GetFocusedColumn: Integer; begin Result := 0; if IsRowSelect then Exit; if (FFocusedColumn >=0) and (FFocusedColumn < GetVisibleHeaderCount) then Result := FFocusedColumn; end; function TCustomdxTreeList.GetFocusedNumber: Integer; begin Result := 0; if FocusedNode <> Nil then Result := GetAbsoluteIndex(FocusedNode); end; function TCustomdxTreeList.GetLastNode: TdxTreeListNode; begin Result := nil; if Count > 0 then begin Result := Items[Count - 1]; while (Result.Count > 0) and (Result.Expanded) do Result := Result[Result.Count - 1]; end; end; function TCustomdxTreeList.GetNode(Index: Integer): TdxTreeListNode; begin if (Index > -1) and (Index < FNodeList.Count{Count}) then Result := FNodeList.List^[Index] else Result := nil; end; function TCustomdxTreeList.GetOptions: TdxTreeListOptions; begin Result := FOptions; end; function TCustomdxTreeList.GetOptionsEx: TdxTreeListOptionsEx; begin Result := FOptionsEx; end; function TCustomdxTreeList.GetTopIndex: Integer; begin Result := -1; if TopVisibleNode <> Nil then Result := GetAbsoluteIndex(TopVisibleNode); end; function TCustomdxTreeList.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 TCustomdxTreeList.IsSmartNavigation: Boolean; begin Result := (FListIndexes <> nil) and (FListNodes <> nil) and (FListRealNodes <> nil) and (FListNodes.Count > 0) and not (csDestroying in ComponentState); end; procedure TCustomdxTreeList.SetFocusedColumn(Value: Integer); begin if (FFocusedColumn <> Value) and (Value >=0) and (Value < GetVisibleHeaderCount) then SetFocusedNode(FocusedNode, Value, True); end; procedure TCustomdxTreeList.SetLeftCoord(ALeft: Integer); var FLeft, FTotal : Integer; Distance: Integer; begin HideEditor; FLeft := LeftCoord; if FLeft <> ALeft then begin if (ALeft < 0) then ALeft := 0; FTotal := GetScrollableBandWidth; if ((ALeft + GetScrollableWidth) > FTotal) then ALeft := FTotal - GetScrollableWidth; if ALeft < 0 then ALeft := 0; if (ALeft <> FLeft) then begin FLeftCoord := ALeft; UpdateScrollBars; if FLockUpdate <> 0 then Exit; Distance := (FLeft - ALeft); if ShowFooter or (abs(Distance) > GetScrollableWidth) or (GetBandFixedLeft <> -1) or (GetBandFixedRight <> -1) then Invalidate else begin HideDragImages; try ScrollGridHorz(Distance); finally ShowDragImages; end; end; // event DoChangeLeftCoord; end; end; end; procedure TCustomdxTreeList.SetOptions(Value: TdxTreeListOptions); var OldOptions: TdxTreeListOptions; begin if FOptions <> Value then begin HideEditor; BeginUpdate; try OldOptions := FOptions; if aoRowSelect in Value then OptionsEx := OptionsEx - [aoInvertSelect]; if (aoAutoSort in Value) and not (aoAutoSort in FOptions) then ClearColumnsSorted; if (aoKeepColumnWidth in OptionsEx) and (aoAutoWidth in OldOptions) and not (aoAutoWidth in Value) then StabilizeAutoWidth; FOptions := Value; if not (csLoading in ComponentState) then begin ClearSelection; if (FocusedNode <> Nil) then FocusedNode.Selected := True; if not IsRowSelect and (FocusedColumn = -1) then FocusedColumn := 0; end; finally EndUpdate; end; end; end; procedure TCustomdxTreeList.SetOptionsEx(Value: TdxTreeListOptionsEx); var OldOptions: TdxTreeListOptionsEx; begin if FOptionsEx <> Value then begin HideEditor; BeginUpdate; try OldOptions := FOptionsEx; if aoInvertSelect in Value then Options := Options - [aoRowSelect]; if ((aoMultiSort in FOptionsEx) and not (aoMultiSort in Value)) or ((aoAnsiSort in FOptionsEx) <> (aoAnsiSort in Value)) then ClearColumnsSorted; FOptionsEx := Value; if (aoAutoHeaderPanelHeight in FOptionsEx) and not (aoAutoHeaderPanelHeight in OldOptions) then HeaderPanelBestFit; if FSearching and not (aoAutoSearch in FOptionsEx) then EndSearch; finally EndUpdate; end; end; end; procedure TCustomdxTreeList.SetTopIndex(AIndex: Integer); var FTopIndex, FCount, FRealRowCount, FDummy: Integer; Distance, DScroll: Integer; OldRect, NewRect: TRect; DrawInfo: TdxGridDrawInfo; begin HideEditor; FTopIndex := TopIndex; if FTopIndex <> AIndex then begin if (AIndex < 0) then AIndex := 0; FCount := GetAbsoluteCount; if FCount <= 1 then Exit; FRealRowCount := RowCount; CalcRectInfo(DrawInfo); with DrawInfo.CellsRect do CalcRowCount(GetAbsoluteNode(AIndex), Bottom - Top, FRealRowCount, FDummy); if (AIndex + FRealRowCount{RowCount}) > FCount then AIndex := FCount - RowCount; if (AIndex < 0) then AIndex := 0; Distance := (FTopIndex - AIndex); if Distance = 0 then DScroll := 0 else DScroll := CalcDistance(Distance); if (AIndex <> FTopIndex) then begin OldRect := GetRectNode(FocusedNode); SetTopVisibleNode(GetAbsoluteNode(AIndex)); UpdateScrollBars; if FLockUpdate <> 0 then Exit; NewRect := GetRectNode(FocusedNode); ValidateRect(Handle, @OldRect); Windows.InvalidateRect(Handle, @OldRect, False); Windows.InvalidateRect(Handle, @NewRect, False); end; // scrolling if Abs(Distance) > RowCount then Invalidate else begin HideDragImages; try ScrollGridVert(DScroll); finally ShowDragImages; end; end; end; end; procedure TCustomdxTreeList.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 TCustomdxTreeList.UpdateHScrollBar; var SIOld, SINew: TScrollInfo; FTotalWidth : Integer; begin if not HandleAllocated then Exit; if IsHScrollBarVisible then begin SIOld.cbSize := sizeof(SIOld); SIOld.fMask := SIF_ALL; GetScrollInfo(SB_HORZ, SIOld); SINew := SIOld; SINew.nMin := 0; SINew.nPage := GetScrollableWidth; FTotalWidth := GetScrollableBandWidth; SINew.nMax := FTotalWidth - 1; if FTotalWidth <= GetScrollableWidth then SINew.nMax := 0; SINew.nPos := FLeftCoord; if (SINew.nMin <> SIOld.nMin) or (SINew.nMax <> SIOld.nMax) or (SINew.nPage <> SIOld.nPage) or (SINew.nPos <> SIOld.nPos) then begin HideDragImages; try SetScrollInfo(SB_HORZ, SINew, True); finally ShowDragImages; end; end; end; end; procedure TCustomdxTreeList.UpdateTopLeftCoord; var FTopIndex, FCount : Integer; begin if not HandleAllocated then Exit; {TopIndex} FTopIndex := TopIndex; FCount := GetAbsoluteCount; if ((FTopIndex + RowCount) > FCount) then FTopIndex := FCount - RowCount; if FTopIndex < 0 then FTopIndex := 0; if FTopIndex <> TopIndex then TopIndex := FTopIndex; {LeftCoord} if GetScrollableWidth >= GetScrollableBandWidth then begin if (LeftCoord <> 0) then LeftCoord := 0 end else if (LeftCoord + GetScrollableWidth) > GetScrollableBandWidth then begin FLeftCoord := GetScrollableBandWidth - GetScrollableWidth; Invalidate; end; end; procedure TCustomdxTreeList.UpdateVScrollBar; var SIOld, SINew: TScrollInfo; begin if not HandleAllocated then Exit; UpdateRowCount; if IsVScrollBarVisible then begin SIOld.cbSize := SizeOf(SIOld); SIOld.fMask := SIF_ALL; GetScrollInfo(SB_VERT, SIOld); SINew := SIOld; GetVScrollInfo(SINew.nMin, SINew.nMax, SINew.nPos, SINew.nPage, SINew.fMask); if (SINew.nMin <> SIOld.nMin) or (SINew.nMax <> SIOld.nMax) or (SINew.nPage <> SIOld.nPage) or (SINew.nPos <> SIOld.nPos) or (SINew.fMask <> SIOld.fMask) then begin HideDragImages; try SetScrollInfo(SB_VERT, SINew, True); finally ShowDragImages; end; end; end; end; // size function TCustomdxTreeList.GetDefaultRowHeight: Integer; begin Result := FRowHeight; end; function TCustomdxTreeList.IsRowHeightStored: Boolean; begin Result := FRowHeightAssigned; end; procedure TCustomdxTreeList.SetCustomizingRowCount(Value: Integer); begin if Value < 2 then Value := 2; FCustomizingRowCount := Value; end; procedure TCustomdxTreeList.SetDefaultRowHeight(Value: Integer); begin if FRowHeight <> Value then begin FRowHeight := Value; FRowHeightAssigned := True; LayoutChanged; end; end; procedure TCustomdxTreeList.SetFixedBandLineWidth(Value: Integer); begin if Value < 1 then Value := 1; if FFixedBandLineWidth <> Value then begin FFixedBandLineWidth := Value; LayoutChanged; end; end; procedure TCustomdxTreeList.SetIndentDesc(Value : Integer); begin if Value < 0 then Value := 0; if IndentDesc <> Value then begin FIndentDesc := Value; LayoutChanged; // Invalidate; end; end; procedure TCustomdxTreeList.SetMaxRowLineCount(Value: Integer); begin if Value < -1 then Value := -1; if FMaxRowLineCount <> Value then begin FMaxRowLineCount := Value; LayoutChanged; end; end; procedure TCustomdxTreeList.SetPreviewLines(Value: Integer); begin if Value < -1 then Value := -1; // if Value < 0 then Value := 0; // if Value > dxGridPreviewMaxLineCount then // Value := dxGridPreviewMaxLineCount; if FPreviewLines <> Value then begin FPreviewLines := Value; LayoutChanged; end; end; procedure TCustomdxTreeList.SetRowSeparatorLineWidth(Value: Integer); begin if Value < 1 then Value := 1; if FRowSeparatorLineWidth <> Value then begin FRowSeparatorLineWidth := Value; LayoutChanged; end; end; // paint methods procedure TCustomdxTreeList.DrawArrows(FlagHide : Boolean); const CurSize = 16; var PrevBrush: HBRUSH; PrevPen: HPEN; DC: HDC; P: array [0..6] of TPoint; Pos, HotSpot: TPoint; SizeX, SizeY: Integer; R: TRect; begin FSaveArrowsRect := Rect(FArrowsPos.X, FArrowsPos.Y, FArrowsPos.X + FArrowsRect.Right, FArrowsPos.Y + FArrowsRect.Bottom); if FlagHide and (FDragImageList <> nil) and FDragImageList.Dragging then // check intersect rect begin ImageList_GetIconSize(ImageList_GetDragImage(@Pos, @HotSpot), SizeX, SizeY); R := Rect(Pos.X, Pos.Y, Pos.X + SizeX, Pos.Y + SizeY); OffsetRect(R, -HotSpot.X, -HotSpot.Y); if not IntersectRect(R, R, FSaveArrowsRect) then FlagHide := False; end; if FlagHide and (FDragImageList <> nil) and FDragImageList.Dragging then FDragImageList.HideDragImage; DC := GetDC(0); with SaveArrowsBitmap, FArrowsRect Do begin Width := Max(Width, Right - Left); Height := Max(Height, Bottom - Top); end; if not FFlagSaveArrowsRect then // save Screen rect begin with FSaveArrowsRect do BitBlt(SaveArrowsBitmap.Canvas.Handle, 0, 0, Right-Left, Bottom-Top, DC, FSaveArrowsRect.Left, FSaveArrowsRect.Top, SRCCOPY); FFlagSaveArrowsRect := True; // Draw Arrows PrevPen := SelectObject(DC, GetStockObject(BLACK_PEN)); PrevBrush := SelectObject(DC, CreateSolidBrush(ColorToRGB(FArrowsColor))); with FSaveArrowsRect do begin P[0] := Point(Left + 5, Top + 8); P[1] := Point(Left, Top + 3); P[2] := Point(Left + 3, Top + 3); P[3] := Point(Left + 3, Top); P[4] := Point(Left + 7, Top); P[5] := Point(Left + 7, Top + 3); P[6] := Point(Left + 10, Top + 3); Polygon(DC, P, 7); P[0] := Point(Left + 5, Bottom - 9); P[1] := Point(Left + 10, Bottom - 4); P[2] := Point(Left + 7, Bottom - 4); P[3] := Point(Left + 7, Bottom - 1); P[4] := Point(Left + 3, Bottom - 1); P[5] := Point(Left + 3, Bottom - 4); P[6] := Point(Left, Bottom - 4); Polygon(DC, P, 7); end; DeleteObject(SelectObject(DC, PrevBrush)); SelectObject(DC, PrevPen); end else // restore Screen rect begin with FSaveArrowsRect do BitBlt(DC, Left, Top, Right - Left, Bottom - Top, SaveArrowsBitmap.Canvas.Handle, 0, 0, SRCCOPY); FFlagSaveArrowsRect := False; end; ReleaseDC(0, DC); if FlagHide and (FDragImageList <> nil) and FDragImageList.Dragging then FDragImageList.ShowDragImage; end; procedure TCustomdxTreeList.DrawSizingLine; var DC: HDC; PrevPen: HPEN; PrevROP2: Integer; DrawInfo: TdxGridDrawInfo; x1, y1, x2, y2, i, W: Integer; FlagVert: Boolean; begin DC := Canvas.Handle; PrevPen := SelectObject(DC, GetStockObject(BLACK_PEN)); PrevROP2 := GetROP2(DC); try SetROP2(DC, R2_NOTXORPEN); // draw line CalcRectInfo(DrawInfo); with DrawInfo do begin // vert line if FState in [tsColumnSizing, tsBandSizing] then begin x1 := FSizingPos; y1 := CellsRect.Top; x2 := FSizingPos; y2 := CellsRect.Bottom; FlagVert := True; if (FState = tsBandSizing) then if not IsRectEmpty(BandRect) then y1 := BandRect.Top else y1 := HeaderRect.Top else if (FState = tsColumnSizing) and not IsRectEmpty(HeaderRect) then y1 := HeaderRect.Top; if (FState = tsBandSizing) then W := 2 else W := 1; end else // horz line if FState in [tsBandPanelSizing, tsHeaderPanelSizing, tsRowSizing] then begin x1 := CellsRect.Left; y1 := FSizingPos; x2 := CellsRect.Right; y2 := FSizingPos; FlagVert := False; if FState = tsRowSizing then begin W := 1; if not IsRectEmpty(IndicatorRect) then x1 := IndicatorRect.Left; end else W := 2; end; for i := 0 to W - 1 do begin Windows.MoveToEx(DC, x1, y1, nil); Windows.LineTo(DC, x2, y2); if FlagVert then begin Inc(x1); Inc(x2); end else begin Inc(y1); Inc(y2); end; end; end; finally SelectObject(DC, PrevPen); SetROP2(DC, PrevROP2); end; end; function TCustomdxTreeList.GetFooterRect(Node: TdxTreeListNode; Index, YStart, SizeGrid: Integer; const DrawInfo: TdxGridDrawInfo): TRect; var I: Integer; begin with DrawInfo do begin I := GetNodeFooterLevel(Node, Index); if I <> -1 then I := (I + 1) * FIndent else I := 0; Result := Rect(CellsRect.Left + I, YStart + Index * FFooterRowNodeHeight, CellsRect.Left + GetBandTotalWidth - SizeGrid, YStart + (Index + 1) * FFooterRowNodeHeight); {.} if not ShowRoot then Dec(Result.Left, FIndent); if IsRectEmptyEx(FixedBandLeftRect) then OffsetRect(Result, - LeftCoord, 0) else Dec(Result.Right, LeftCoord); if not IsRectEmptyEx(FixedBandRightRect) then begin if (Result.Right >= CellsRect.Right) then Result.Right := CellsRect.Right - SizeGrid; if Result.Left > FixedBandRightRect.Left then Result.Left := FixedBandRightRect.Left; end; if Result.Left < CellsRect.Left then Result.Left := CellsRect.Left; end; end; procedure TCustomdxTreeList.InvalidateBand(BandIndex: Integer); var DrawInfo: TdxGridDrawInfo; begin CalcRectInfo(DrawInfo); Windows.InvalidateRect(Handle, @DrawInfo.BandRect, False); UpdateWindow(Handle); end; procedure TCustomdxTreeList.InvalidateBandButton; var DrawInfo: TdxGridDrawInfo; begin CalcRectInfo(DrawInfo); Windows.InvalidateRect(Handle, @DrawInfo.BandButtonRect, False); UpdateWindow(Handle); end; procedure TCustomdxTreeList.InvalidateColumn(ColumnIndex: Integer); var DrawInfo: TdxGridDrawInfo; begin CalcRectInfo(DrawInfo); Windows.InvalidateRect(Handle, @DrawInfo.HeaderRect, False); UpdateWindow(Handle); end; procedure TCustomdxTreeList.InvalidateHeaderButton; var DrawInfo: TdxGridDrawInfo; begin CalcRectInfo(DrawInfo); Windows.InvalidateRect(Handle, @DrawInfo.HeaderButtonRect, False); UpdateWindow(Handle); end; procedure TCustomdxTreeList.InvalidateNewItemRow; var DrawInfo: TdxGridDrawInfo; begin CalcRectInfo(DrawInfo); Windows.InvalidateRect(Handle, @DrawInfo.NewItemRowRect, False); end; // style function TCustomdxTreeList.GetRootVisible: Boolean; begin Result := FShowRoot or not FPaintStandard; end; procedure TCustomdxTreeList.HeaderFontChanged(Sender: TObject); begin if (not FSelfChangingTitleFont) and not (csLoading in ComponentState) then ParentFont := False; LayoutChanged; end; procedure TCustomdxTreeList.ImageListChange(Sender: TObject); begin if HandleAllocated then if (Sender = Images) or (Sender = StateImages) then LayoutChanged; end; procedure TCustomdxTreeList.InternalLayout; var H: Integer; begin if (csLoading in ComponentState) or (csDestroying in ComponentState) then Exit; Canvas.Handle := GetDC(0); try FBandRowCount := GetBandRowCount; FHeaderRowCount := GetHeaderMaxRowCount; FHeaderLineCount := GetHeaderLineRowCount; FFlat := Boolean(LookAndFeel <> lfStandard); FPaintStandard := not Boolean(PaintStyle); // Band Canvas.Font.Assign(BandFont); FBandTextHeight := Canvas.TextHeight('Wg'); FBandHeight := CalcBandHeight(FBandRowCount); if not FShowBands then FBandHeight := 0; // Header Canvas.Font.Assign(HeaderFont); FHeaderRowHeight := FHeaderLineCount * Canvas.TextHeight('Wg') + 3{indent} + 2 + Byte(not FFlat){black line -> right_bottom}; FHeaderHeight := FHeaderRowHeight * FHeaderRowCount; if not ShowHeader then FHeaderHeight := 0; // Arrows FArrowsRect := Rect(0, 0, arWidth{9}, FHeaderRowHeight + 2*arHeight{9}); // Group Panel FGroupPanelHeight := GetGroupPanelHeight; // Indicator Width if FShowIndicator then FIndicatorWidth := GetIndicatorWidth{12} else FIndicatorWidth := 0; // Ground Canvas.Font.Assign(Self.Font); FTextHeight := Canvas.TextHeight('Wg'); // Footer FFooterRowHeight := FTextHeight + 3 {text} + 2 {text frame} + 2 {text indent}; FFooterHeight := FFooterRowHeight * FHeaderRowCount + 3 {frame} + Byte(not FFlat); FFooterRowNodeHeight := FFooterRowHeight * FHeaderRowCount + 2 + Byte(FShowGrid and FShowPreviewGrid); if not FShowFooter then FFooterHeight := 0; // Filter (Status) if IsFilterStatusVisible then begin FStatusHeight := FTextHeight + 3 + 2; if FStatusHeight < dxGridStatusCloseButtonMinHeight then FStatusHeight := dxGridStatusCloseButtonMinHeight; end else FStatusHeight := 0; // TODO // Row FMinRowHeight := CalcTextRowHeight(FTextHeight); FDeltaHScroll := Canvas.TextWidth('0'); FImageW := 0; FImageH := 0; FImageStateW := 0; FImageStateH := 0; FImageButtonW := 16; FImageButtonH := 16; if Images <> nil then begin FImageW := Images.Width; FImageH := Images.Height; end; if StateImages <> nil then begin FImageStateW := StateImages.Width; FImageStateH := StateImages.Height; end; FIndent := FImageButtonW; // correct FMinRowHeight - Image Height if FMinRowHeight < FImageButtonH then FMinRowHeight := FImageButtonH; H := FMinRowHeight + Byte(FShowGrid and FShowPreviewGrid); // Text and Grid Line if FHeaderRowCount*H < FImageH then FMinRowHeight := FImageH; H := FMinRowHeight + Byte(FShowGrid and FShowPreviewGrid); // Text and Grid Line if FHeaderRowCount*H < FImageStateH then FMinRowHeight := FImageStateH; // check FMinRowHeight - column Image Height H := GetRowMaxColumnHeight(Canvas); //* if {FHeaderRowCount*}(FMinRowHeight + Byte(FShowGrid and FShowPreviewGrid)) < H then //* FMinRowHeight := H; if FHeaderRowCount*(FMinRowHeight + Byte(FShowGrid and FShowPreviewGrid)) < H then FMinRowHeight := H; // if FMinRowHeight < H then FMinRowHeight := H; Inc(FMinRowHeight, Byte(FShowGrid and FShowPreviewGrid)); if IsInvertSelect then Inc(FMinRowHeight, 2); // correct FMinRowHeight - custom resing if not FRowHeightAssigned then FRowHeight := FMinRowHeight; if FRowHeight < FMinRowHeight then FRowHeight := FMinRowHeight; if FRowHeight = FMinRowHeight then FRowHeightAssigned := False; // New Item Row Height FNewItemRowHeight := 0; if FFlat then FNewItemRowSeparatorHeight := 5 else FNewItemRowSeparatorHeight := 6; if FHeaderRowCount = 1 then FNewItemRowHeight := FRowHeight + FNewItemRowSeparatorHeight; if not IsNewItemRowVisible or (GetBandCount = 0) then FNewItemRowHeight := 0; // Preview Canvas.Font.Assign(PreviewFont); FDescTextHeight := Canvas.TextHeight('Wg'); finally ReleaseDC(0, Canvas.Handle); Canvas.Handle := 0; end; {**} ClearListNodes; {**} BeginCustomLayout; UpdateScrollBars; UpdateTopLeftCoord; UpdateCustomizingColumns; {**} MakeListNodes; {**} EndCustomLayout; if not FMakeListNodesFlag then MakeListNodes; CheckSize; Invalidate; end; function TCustomdxTreeList.IsHeaderFontStored: Boolean; begin Result := not ParentFont and not DesktopFont; end; procedure TCustomdxTreeList.LoadButtonFaces; var Bmp: TBitmap; R : TRect; procedure DrawOutlookButton(B: TBitmap; R: TRect; IsPlus: Boolean); begin with B.Canvas do begin DrawEdge(Handle, R, BDR_RAISEDINNER, BF_LEFT or BF_TOP); DrawEdge(Handle, R, BDR_RAISEDOUTER, BF_RIGHT or BF_BOTTOM); InflateRect(R, -1, -1); DrawEdge(Handle, R, BDR_RAISEDINNER, BF_RIGHT or BF_BOTTOM); Dec(R.Right); Dec(R.Bottom); Windows.FillRect(Handle, R, COLOR_BTNFACE + 1); Windows.FillRect(Handle, Rect(3, 5, 8, 5 + 1), COLOR_BTNTEXT + 1); if IsPlus then Windows.FillRect(Handle, Rect(5, 3, 5 + 1, 8), COLOR_BTNTEXT + 1); end; end; begin Bmp := TBitmap.Create; try Bmp.Width :=12; Bmp.Height := 12; R := Rect(0, 0, Bmp.Width, Bmp.Height); DrawOutlookButton(Bmp, R, True{+}); OutButtonPlus.Assign(Bmp); DrawOutlookButton(Bmp, R, False{-}); OutButtonMinus.Assign(Bmp); finally Bmp.Free; end; end; procedure TCustomdxTreeList.SetBandColor(Value: TColor); begin if FBandColor <> Value then begin FBandColor := Value; Invalidate; end; end; procedure TCustomdxTreeList.SetBandFont(Value: TFont); begin FBandFont.Assign(Value); LayoutChanged; end; procedure TCustomdxTreeList.SetBandVisible(Value: Boolean); begin if FShowBands <> Value then begin FShowBands := Value; LayoutChanged; end; end; procedure TCustomdxTreeList.SetBorderStyle(Value: TBorderStyle); begin if FBorderStyle <> Value then begin FBorderStyle := Value; {if LookAndFeel = lfStandard then }RecreateWnd; end; end; procedure TCustomdxTreeList.SetButtonVisible(Value: Boolean); begin if FShowButtons <> Value then begin FShowButtons := Value; Invalidate; end; end; procedure TCustomdxTreeList.SetFixedBandLineColor(Value: TColor); begin if FFixedBandLineColor <> Value then begin FFixedBandLineColor := Value; Invalidate; end; end; procedure TCustomdxTreeList.SetFooterColor(Value: TColor); begin if FFooterColor <> Value then begin FFooterColor := Value; Invalidate; end; end; procedure TCustomdxTreeList.SetFooterTextColor(Value: TColor); begin if FFooterTextColor <> Value then begin FFooterTextColor := Value; Invalidate; end; end; procedure TCustomdxTreeList.SetFooterVisible(Value: Boolean); begin if FShowFooter <> Value then begin FShowFooter := Value; LayoutChanged; end; end; procedure TCustomdxTreeList.SetGridLineColor(Value: TColor); begin if FGridLineColor <> Value then begin FGridLineColor := Value; Invalidate; end; end; procedure TCustomdxTreeList.SetGridVisible(Value: Boolean); begin if FShowGrid <> Value then begin FShowGrid := Value; LayoutChanged; end; end; procedure TCustomdxTreeList.SetGroupColor(Value : TColor); begin if FGroupColor <> Value then begin FGroupColor := Value; Invalidate; end; end; procedure TCustomdxTreeList.SetGroupTextColor(Value : TColor); begin if FGroupTextColor <> Value then begin FGroupTextColor := Value; Invalidate; end; end; procedure TCustomdxTreeList.SetHeaderColor(Value: TColor); begin if FHeaderColor <> Value then begin FHeaderColor := Value; Invalidate; end; end; procedure TCustomdxTreeList.SetHeaderFont(Value: TFont); begin FHeaderFont.Assign(Value); LayoutChanged; end; procedure TCustomdxTreeList.SetHeaderVisible(Value: Boolean); begin if FShowHeaders <> Value then begin FShowHeaders := Value; LayoutChanged; end; end; procedure TCustomdxTreeList.SetHideFocusRect(Value: Boolean); begin if HideFocusRect <> Value then begin FHideFocusRect := Value; Invalidate; end; end; procedure TCustomdxTreeList.SetHideSelection(Value: Boolean); begin if HideSelection <> Value then begin FHideSelection := Value; Invalidate; end; end; procedure TCustomdxTreeList.SetHideSelectionColor(Value: TColor); begin if FHideSelectionColor <> Value then begin FHideSelectionColor := Value; Invalidate; end; end; procedure TCustomdxTreeList.SetHideSelectionTextColor(Value: TColor); begin if FHideSelectionTextColor <> Value then begin FHideSelectionTextColor := Value; Invalidate; end; end; procedure TCustomdxTreeList.SetHighlightColor(Value : TColor); begin if FHighlightColor <> Value then begin FHighlightColor := Value; Invalidate; end; end; procedure TCustomdxTreeList.SetHighlightTextColor(Value : TColor); begin if FHighlightTextColor <> Value then begin FHighlightTextColor := Value; Invalidate; end; end; procedure TCustomdxTreeList.SetImages(Value: TImageList); begin BeginUpdate; if Images <> nil then Images.UnRegisterChanges(FImageChangeLink); FImages := Value; if Value <> nil then begin Images.RegisterChanges(FImageChangeLink); Value.FreeNotification(Self); end; EndUpdate; end; procedure TCustomdxTreeList.SetIndicatorVisible(Value: Boolean); begin if FShowIndicator <> Value then begin FShowIndicator := Value; LayoutChanged; end; end; procedure TCustomdxTreeList.SetLineVisible(Value: Boolean); begin if ShowLines <> Value then begin FShowLines := Value; Invalidate; end; end; procedure TCustomdxTreeList.SetLookAndFeel(Value: TdxLookAndFeel); begin if LookAndFeel <> Value then begin CancelEditor; FLookAndFeel := Value; {$IFDEF DELPHI4} if FLookAndFeel = lfUltraFlat then ScrollBarStyle := ssHotTrack else ScrollBarStyle := ssRegular; {$ENDIF} LoadButtonFaces; RecreateWnd; LayoutChanged; end; end; procedure TCustomdxTreeList.SetNewItemRowVisible(Value: Boolean); begin if FShowNewItemRow <> Value then begin if not Value and NewItemRowActive then NewItemRowActive := False; FShowNewItemRow := Value; LayoutChanged; end; end; procedure TCustomdxTreeList.SetPaintStyle(Value: TdxTreeListPaintStyle); begin if PaintStyle <> Value then begin FPaintStyle := Value; LayoutChanged; end; end; procedure TCustomdxTreeList.SetPreviewFont(Value: TFont); begin FPreviewFont.Assign(Value); LayoutChanged; end; procedure TCustomdxTreeList.SetPreviewGridVisible(Value: Boolean); begin if FShowPreviewGrid <> Value then begin FShowPreviewGrid := Value; LayoutChanged; end; end; procedure TCustomdxTreeList.SetRootVisible(Value: Boolean); begin if FShowRoot <> Value then begin FShowRoot := Value; LayoutChanged; //Invalidate; end; end; procedure TCustomdxTreeList.SetRowFooterVisible(Value: Boolean); begin if FShowRowFooter <> Value then begin FShowRowFooter := Value; LayoutChanged; end; end; procedure TCustomdxTreeList.SetScrollBars(Value: TScrollStyle); begin if FScrollBars <> Value then begin FScrollBars := Value; RecreateWnd; end; end; procedure TCustomdxTreeList.SetStateImages(Value: TImageList); begin BeginUpdate; if StateImages <> nil then StateImages.UnRegisterChanges(FStateChangeLink); FStateImages := Value; if Value <> nil then begin StateImages.RegisterChanges(FStateChangeLink); Value.FreeNotification(Self); end; EndUpdate; end; procedure TCustomdxTreeList.SetTreeLineColor(Value : TColor); begin if FTreeLineColor <> Value then begin FTreeLineColor := Value; Invalidate; end; end; procedure TCustomdxTreeList.SetTreeLineStyle(Value: TdxTreeLineStyle); begin if FTreeLineStyle <> Value then begin FTreeLineStyle := Value; Invalidate; end; end; // Other procedure TCustomdxTreeList.ActivateCustomizingForm(Sender: TObject); begin HideEditor; end; procedure TCustomdxTreeList.CloseCustomizingForm(Sender: TObject; var Action: TCloseAction); begin FCustomizingPos.X := FCustomizingForm.Left; FCustomizingPos.Y := FCustomizingForm.Top; if FCustomizingBandListBox <> nil then FCustomizingLastBandIndex := FCustomizingBandListBox.ItemIndex else FCustomizingLastBandIndex := -1; if FCustomizingHeaderListBox <> nil then FCustomizingLastHeaderIndex := FCustomizingHeaderListBox.ItemIndex else FCustomizingLastHeaderIndex := -1; Action := caFree; FCustomizingForm := nil; FCustomizingBandListBox := nil; FCustomizingHeaderListBox := nil; if Assigned(FOnEndColumnsCustomizing) then FOnEndColumnsCustomizing(Self); end; procedure TCustomdxTreeList.SetDragObject(Value: TDragObject); var PrevDragObject: TDragObject; begin if FDragObject <> Value then begin PrevDragObject := FDragObject; FDragObject := Value; if (FDragObject = nil) and (PrevDragObject <> nil) then PrevDragObject.HideDragImage; if FocusedNode <> nil then InvalidateRect(GetRectNode(FocusedNode)); UpdateDragging; if (FDragObject = nil) and (PrevDragObject <> nil) then PrevDragObject.ShowDragImage; if FDragObject = nil then FDragExpandNode := nil; end; end; procedure TCustomdxTreeList.SetNewItemRowActive(Value: Boolean); begin if IsNewItemRowVisible and (FNewItemRowActive <> Value) then begin FNewItemRowActive := Value; if FocusedNode <> nil then InvalidateRect(GetRectNode(FocusedNode)); InvalidateNewItemRow; end; end; // Editor procedure TCustomdxTreeList.HideEdit(ABackFocus: Boolean); begin if (FInplaceEdit <> nil) then try FInplaceEdit.CloseFlag := True; if not (csDestroying in FInplaceEdit.ComponentState) then UpdateText; finally FInplaceColumn := -1; FInplaceNode := nil; FInplaceEdit.Hide; ABackFocus := ABackFocus or (FInplaceEdit.HandleAllocated and (GetFocus = FInplaceEdit.Handle)); if ABackFocus and Self.HandleAllocated and IsWindowVisible(Self.Handle) and not FCanceling then Windows.SetFocus(Self.Handle); end; end; procedure TCustomdxTreeList.UpdateText; var PrevInplaceNode: TdxTreeListNode; begin if (FInplaceColumn <> -1) and (FInplaceNode <> nil) and (FInplaceEdit <> nil) then begin PrevInplaceNode := FInplaceNode; if FInplaceEdit.Modified then AssignEditValue(FInplaceNode, FInplaceColumn, FInplaceEdit); // TODO: FInplaceNode OnDelete notification DoAfterEditing(PrevInplaceNode); end; end; procedure TCustomdxTreeList.UpdateEdit(Activate: Boolean); var EditRect: TRect; procedure UpdateEditor; begin FInplaceColumn := 0; FInplaceNode := FocusedNode; if FocusedColumn <> -1 then FInplaceColumn := FocusedColumn; FInplaceColumnIndex := FInplaceColumn; FInplaceEdit.Parent := Self; if FInplaceNode <> nil then begin BeginInitEdit; try InitEditProperties(FInplaceEdit); InitEditValue(FInplaceNode, FInplaceEdit); with TdxInplaceTreeListEdit(FInplaceEdit) do begin Modified := False; if Self.GetReadOnly then ReadOnly := True; SetActive(True); end; // TODO InitEvents -> OnChange, ... // TODO Event finally EndInitEdit; end; end; end; begin if CanEditShow then begin FInplaceEdit := FindInplaceEdit(FocusedColumn); if FInplaceEdit = nil then begin FInplaceEdit := CreateEditor(FocusedColumn); UpdateEditor; end else begin if (FocusedColumn <> FInplaceColumn) or (FocusedNode <> FInplaceNode) then begin HideEdit(False); SetState(tsEditing); UpdateEditor; end; end; EditRect := GetEditRect(FocusedNode, FocusedColumn); if CanEditShow then begin if not Activate then FInplaceEdit.LockActivate; try FInplaceEdit.Move(EditRect); finally if not Activate then FInplaceEdit.UnLockActivate; end; end else begin FInplaceColumn := -1; FInplaceNode := nil; end; end; end; procedure TCustomdxTreeList.ShowStatusCloseButtonHint(AImmediately: Boolean); var P: TPoint; R: TRect; begin HideStatusCloseButtonHint; if AImmediately then begin GetCursorPos(P); P := ScreenToClient(P); R := GetStatusCloseButtonRect; P := Point(R.Right + 4, R.Top - FTextHeight); P := ClientToScreen(P); if FHintWindow = nil then FHintWindow := TdxContainerHintWindow.Create(nil); FHintWindow.ActivateHint(P, GetStatusCloseButtonHint, Self.Font); FHideHintTimerId := SetTimer(Handle, HideHintTimerId, WaitForHideHintTime, nil); end else begin FShowHintTimerId := SetTimer(Handle, ShowHintTimerId, WaitForShowHintTime, nil); end; end; procedure TCustomdxTreeList.HideStatusCloseButtonHint; 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 begin FHintWindow.Free; FHintWindow := nil; end; end; // Messages procedure TCustomdxTreeList.WMCancelMode(var Msg: TMessage); begin CancelDragSizing; inherited; end; procedure TCustomdxTreeList.WMDestroy(var Msg: TWMDestroy); begin HideStatusCloseButtonHint; inherited; end; procedure TCustomdxTreeList.WMEraseBkgnd(var Message: TWMEraseBkgnd); begin Message.Result := 1; end; procedure TCustomdxTreeList.WMGetDlgCode(var Msg: TWMGetDlgCode); begin Msg.Result := DLGC_WANTARROWS; if IsEditing or FSearching or (IsAutoSearch and (GetAsyncKeyState(VK_MENU) >= 0)) then Msg.Result := Msg.Result or DLGC_WANTCHARS; if IsRowSelect and not IsTabs then Exit; if IsTabs {and (GetAsyncKeyState(VK_CONTROL) >= 0) }then Msg.Result := Msg.Result or DLGC_WANTTAB; end; procedure TCustomdxTreeList.WMHScroll(var Message: TWMHScroll); var SI: TScrollInfo; begin if not AcquireFocus or (GetVisibleHeaderCount = 0) then Exit; with Message do case ScrollCode of SB_LINEUP: LeftCoord := LeftCoord - FDeltaHScroll; SB_LINEDOWN: LeftCoord := LeftCoord + FDeltaHScroll; SB_PAGEUP: LeftCoord := LeftCoord - GetScrollableWidth; SB_PAGEDOWN: LeftCoord := LeftCoord + GetScrollableWidth; SB_THUMBTRACK, SB_THUMBPOSITION: begin SI.cbSize := SizeOf(SI); SI.fMask := SIF_ALL; GetScrollInfo(SB_HORZ, SI); if SI.nTrackPos <= 0 then LeftCoord := 0 else if SI.nTrackPos >= GetScrollableBandWidth then LeftCoord := GetScrollableBandWidth else begin if (SI.nTrackPos + 1 + GetScrollableWidth) >= GetScrollableBandWidth then LeftCoord := (SI.nTrackPos + 1) else LeftCoord := ((SI.nTrackPos + 1) div 4) * 4; end; end; SB_BOTTOM: LeftCoord := GetScrollableBandWidth; SB_TOP: LeftCoord := 0; end; end; procedure TCustomdxTreeList.WMIMEStartComp(var Message: TMessage); begin inherited; ShowEditor; end; procedure TCustomdxTreeList.WMKillFocus(var Msg: TWMKillFocus); begin inherited; if (FInplaceEdit <> nil) and (Msg.FocusedWnd = FInplaceEdit.Handle) then Exit; InvalidateRect(GetRectNode(FocusedNode)); if (FInplaceEdit <> nil) and (Msg.FocusedWnd <> FInplaceEdit.Handle) then HideEditor; {Redraw Selection} if IsMultiSelect and (SelectedCount > 0) then InvalidateSelection; // invalidate new item row if IsNewItemRowVisible then InvalidateNewItemRow; if State = tsNodeDown then SetState(tsNormal); //after Abort end; procedure TCustomdxTreeList.WMLButtonDown(var Message: TWMLButtonDown); begin FreeClickTimer; inherited; if FInplaceEdit <> nil then FInplaceEdit.FClickTime := GetMessageTime; end; procedure TCustomdxTreeList.WMNCCalcSize(var Message: TWMNCCalcSize); begin if (BorderStyle <> bsNone) and (LookAndFeel <> lfStandard) then InflateRect(Message.CalcSize_Params.rgrc[0], -1, -1); inherited; end; procedure TCustomdxTreeList.WMNCHitTest(var Msg: TWMNCHitTest); begin DefaultHandler(Msg); FHitTest := SmallPointToPoint(Msg.Pos); end; procedure TCustomdxTreeList.WMNCPaint(var Message: TMessage); var R: TRect; DC: HDC; H, W: Integer; AStyle: LongInt; begin inherited; if (LookAndFeel = lfStandard) or (BorderStyle = bsNone) then Exit; GetWindowRect(Handle, R); OffsetRect(R, -R.Left, -R.Top); DC := GetWindowDC(Handle); if LookAndFeel = lfUltraFlat then FrameRect(DC, R, GetSysColorBrush(COLOR_BTNSHADOW)) // TODO else DrawEdge(DC, R, BDR_SUNKENOUTER, BF_RECT); AStyle := GetWindowLong(Handle, GWL_STYLE); if (AStyle and WS_HSCROLL <> 0) and (AStyle and WS_VSCROLL <> 0) then begin W := GetSystemMetrics(SM_CXVSCROLL); H := GetSystemMetrics(SM_CYHSCROLL); InflateRect(R, -1, -1); with R do R := Rect(Right-W, Bottom-H, Right, Bottom); FillRect(DC, R, GetSysColorBrush(COLOR_BTNFACE)); end; ReleaseDC(Handle, DC); end; procedure TCustomdxTreeList.WMSetCursor(var Msg: TWMSetCursor); var hInfo: TdxTreeListHitInfo; State: TdxTreeListState; Cur: HCURSOR; begin Cur := 0; with Msg do begin if HitTest = HTCLIENT then begin State := tsNormal; if FState in [tsNormal, tsEditing] then begin FHitTest := ScreenToClient(FHitTest); hInfo := GetHitInfo(FHitTest); {Band} if (hInfo.hitType = htBandEdge) and (hInfo.Band <> -1) then State := tsColumnSizing; {Column} if (hInfo.hitType = htColumnEdge) then State := tsColumnSizing; {Row} if (hInfo.hitType in [htBandPanelEdge, htHeaderPanelEdge, htRowEdge]) then State := tsRowSizing; end else State := FState; if (State in [tsColumnSizing, tsBandSizing]) then Cur := Screen.Cursors[crHSplit]; if (State in [tsBandPanelSizing, tsHeaderPanelSizing, tsRowSizing]) then Cur := Screen.Cursors[crVSplit]; end; end; if Cur <> 0 then SetCursor(Cur) else inherited; end; procedure TCustomdxTreeList.WMSetFocus(var Msg: TWMSetFocus); begin inherited; if FocusedNode = Nil then FFocused := TopVisibleNode; if (Not IsRowSelect) and (FocusedColumn = -1) then FFocusedColumn := 0; if (FInplaceEdit = nil) or (Msg.FocusedWnd <> FInplaceEdit.Handle) then begin InvalidateRect(GetRectNode(FocusedNode)); UpdateEdit(False); end; {Redraw Selection} if IsMultiSelect and (SelectedCount > 0) then InvalidateSelection; // invalidate new item row if IsNewItemRowVisible then InvalidateNewItemRow; end; procedure TCustomdxTreeList.WMSize(var Msg: TWMSize); begin ClearNodeRowHeight; CloseEditor; CheckSize; inherited; UpdateScrollBars; UpdateTopLeftCoord; // if not (csLoading in ComponentState) then // MakeBoundsInfo; // new end; procedure TCustomdxTreeList.WMTimer(var Msg: TWMTimer); var P: TPoint; FHitInfo: TdxTreeListHitInfo; begin inherited; if (Msg.TimerId = ClickTimerID) then begin FreeClickTimer; if State = tsNormal then ShowEditor; end else if (Msg.TimerId = dxDragExapndTimerId) then begin if dxDragExapndTimerId <> 0 then KillTimer(Handle, dxDragExapndTimerId); FDragExpandTimerId := 0; GetCursorPos(P); P := ScreenToClient(P); FHitInfo := GetHitInfo(P); if FHitInfo.hitType in DragExpandHitTests then begin if (FHitInfo.Node <> nil) and (FHitInfo.Node = FDragExpandNode) then begin if IsDragCollapse then begin FHitInfo.Node.Expanded := not FHitInfo.Node.Expanded; FDragExpandTimerId := SetTimer(Handle, dxDragExapndTimerId, WaitForExpandNodeTime * 2, nil); end else FHitInfo.Node.Expanded := True; end; end; end else if (Msg.TimerId = HideHintTimerId) then // hint HideStatusCloseButtonHint else if (Msg.TimerId = ShowHintTimerId) then // show hint ShowStatusCloseButtonHint(True); end; procedure TCustomdxTreeList.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, SB_THUMBPOSITION: 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; SB_BOTTOM: TopIndex := GetAbsoluteCount; SB_TOP: TopIndex := 0; end; end; type TWinControlCracker = class(TWinControl); procedure TCustomdxTreeList.CMCancelMode(var Msg: TMessage); begin CancelDragSizing; if Assigned(FInplaceEdit) then TWinControlCracker(FInplaceEdit).WndProc(Msg); inherited; end; procedure TCustomdxTreeList.CMColorChanged(var Message: TMessage); begin inherited; LayoutChanged; end; procedure TCustomdxTreeList.CMCtl3DChanged(var Message: TMessage); begin inherited; if (FBorderStyle = bsSingle) and (LookAndFeel = lfStandard) then RecreateWnd; end; procedure TCustomdxTreeList.CMDesignHitTest(var Msg: TCMDesignHitTest); var HType: TdxTreeListHitTest; begin Msg.Result := 0; HType := GetHitInfo(Point(Msg.Pos.X, Msg.Pos.Y)).hitType; if (HType in [htBandEdge, htColumnEdge, htBandPanelEdge, htHeaderPanelEdge, htRowEdge, htColumn, htBand]) or (State in [tsColumnSizing, tsBandSizing, tsBandPanelSizing, tsHeaderPanelSizing, tsRowSizing, tsColumnDragging, tsBandDragging, tsColumnDown, tsBandDown]) then Msg.Result := 1; end; procedure TCustomdxTreeList.CMDrag(var Message: TCMDrag); const DragCursors: array [Boolean, Boolean] of Integer = ((crDrag, crdxTreeListDragCopy), (crMultiDrag, crdxTreeListMultiDragCopy)); begin // check Cursor // TODO DragCursor := DragCursors[SelectedCount > 1, IsAutoDragCopy and (GetAsyncKeyState(VK_CONTROL) < 0)]; inherited; if (State <> tsNodeDragging) and not Dragging then with Message, DragRec^ do case DragMessage of dmDragEnter: if Assigned(OnDragOver) then {if IsDragScroll then }SetDragObject(TDragObject(Source)); dmDragLeave, dmDragDrop: SetDragObject(nil); end; end; procedure TCustomdxTreeList.CMFontChanged(var Message: TMessage); begin inherited; LayoutChanged; end; procedure TCustomdxTreeList.CMMouseEnter(var Message: TMessage); var AHitInfo: TdxTreeListHitInfo; P: TPoint; begin inherited; GetCursorPos(P); P := ScreenToClient(P); AHitInfo := GetHitInfo(P); CheckHotTrackNode(AHitInfo); // TODO Event end; procedure TCustomdxTreeList.CMMouseLeave(var Message: TMessage); var AHitInfo: TdxTreeListHitInfo; begin inherited; AHitInfo.hitType := htNowhere; AHitInfo.Node := nil; CheckHotTrackNode(AHitInfo); // Hide Hints HideStatusCloseButtonHint; // TODO Event end; procedure TCustomdxTreeList.CMParentFontChanged(var Message: TMessage); begin inherited; if ParentFont then begin FSelfChangingTitleFont := True; try BandFont := Font; HeaderFont := Font; FPreviewFont.Name := Font.Name; FPreviewFont.Size := Font.Size; FPreviewFont.Style := Font.Style; FPreviewFont.Color := clBlue; finally FSelfChangingTitleFont := False; end; LayoutChanged; end; end; procedure TCustomdxTreeList.CMSysColorChange(var Message: TMessage); begin inherited; LoadButtonFaces; end; {TdxCustomizingListBox} constructor TdxCustomizingListBox.Create(AOwner : TComponent); begin inherited Create(AOwner); Style := lbOwnerDrawFixed; FDragFlag := False; FDragItemIndex := -1; end; // protected TdxCustomizingListBox procedure TdxCustomizingListBox.CreateParams(var Params: TCreateParams); begin inherited CreateParams(Params); with Params do begin if FFlat then begin Style := Style and not WS_BORDER; ExStyle := ExStyle and not WS_EX_CLIENTEDGE; end; end; end; procedure TdxCustomizingListBox.DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState); begin DrawItem_(Canvas, Index, Rect, {odFocused}(odSelected in State) and (GetParentForm(Self) <> nil) and GetParentForm(Self).Active); end; procedure TdxCustomizingListBox.KeyDown(var Key: Word; Shift: TShiftState); begin if Key = VK_ESCAPE then DoCancelDragging; inherited KeyDown(Key, Shift); end; procedure TdxCustomizingListBox.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if Button in [mbMiddle, mbRight] then DoCancelDragging; if (Button = mbLeft) and (Items.Count > 0) and (ItemIndex > -1) and (ItemAtPos(Point(X, Y), False) = ItemIndex) and (TreeList <> nil) and IsWindowVisible(TreeList.Handle) and not (ssDouble in Shift) then begin FPointDragging.X := X; FPointDragging.Y := Y; FDragFlag := True; FDragItemIndex := ItemIndex; end; inherited MouseDown(Button, Shift, X, Y); end; procedure TdxCustomizingListBox.MouseMove(Shift: TShiftState; X, Y: Integer); begin if (FDragFlag) and (FDragItemIndex <> -1) then if ((X < FPointDragging.X - 3) or (X > FPointDragging.X + 3) or (Y < FPointDragging.Y - 3) or (Y > FPointDragging.Y + 3)) then begin FDragFlag := False; BeginDragging(FDragItemIndex); end; inherited MouseMove(Shift, X, Y); end; procedure TdxCustomizingListBox.BeginDragging(DragIndex: Integer); begin end; procedure TdxCustomizingListBox.DoCancelDragging; begin if (TreeList <> nil) then begin DoEndDragging(False); FDragFlag := False; FDragItemIndex := -1; end; end; procedure TdxCustomizingListBox.DoDragging; begin end; procedure TdxCustomizingListBox.DoEndDragging(Flag: Boolean); begin end; procedure TdxCustomizingListBox.LoadItems(List: TStrings); begin end; procedure TdxCustomizingListBox.UpdateItems; var PrevItemIndex, PrevTopIndex: Integer; begin PrevTopIndex := TopIndex; PrevItemIndex := ItemIndex; Items.BeginUpdate; try Items.Clear; LoadItems(Items); if (PrevItemIndex > -1) and (Items.Count > 0) then begin if (PrevItemIndex >= Items.Count) then PrevItemIndex := Items.Count - 1; TopIndex := PrevTopIndex; ItemIndex := PrevItemIndex; end; finally Items.EndUpdate; end; end; // protected TdxCustomizingListBox procedure TdxCustomizingListBox.DrawItem_(ACanvas: TCanvas; Index: Integer; Rect: TRect; Focused: Boolean); begin if (Index < Items.Count) and (TreeList <> nil) then with ACanvas do begin DrawBand(Handle, Rect, Brush.Handle, Items[Index], False{ADown}, FMultiLine, taLeftJustify, csNone{no sorted}, nil {no glyph}, hbNormal, TreeList.LookAndFeel, []); {Draw FocusRect} if Focused then begin if TreeList.LookAndFeel <> lfStandard then // TODO InvertRect(Handle, Rect) else begin InflateRect(Rect, -2, -2); DrawFocusRect(Rect); end; end; end; end; procedure TdxCustomizingListBox.SetFlat(Value: Boolean); begin if FFlat <> Value then begin FFlat := Value; RecreateWnd; end; end; procedure TdxCustomizingListBox.SetTreeList(Value: TCustomdxTreeList); begin if (FTreeList <> Value) then begin FTreeList := Value; UpdateItems; end; end; procedure TdxCustomizingListBox.WMCaptureChanged(var Msg: TMessage); begin DoCancelDragging; inherited; end; procedure TdxCustomizingListBox.WMLButtonUp(var Message : TMessage); begin DoEndDragging(True); FDragFlag := False; FDragItemIndex := -1; inherited; end; procedure TdxCustomizingListBox.WMMouseMove(var Message: TMessage); begin if (TreeList = nil) or not (TreeList.State in [tsBandDragging, tsColumnDragging]) then inherited else DoDragging; end; procedure TdxCustomizingListBox.WMNCCalcSize(var Message: TWMNCCalcSize); begin if (BorderStyle <> bsNone) and Flat then InflateRect(Message.CalcSize_Params.rgrc[0], -1, -1); inherited; end; procedure TdxCustomizingListBox.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 TdxCustomizingListBox.CNDrawItem(var Message: TWMDrawItem); var State: TOwnerDrawState; begin with Message.DrawItemStruct^ do begin {$IFDEF DELPHI5} State := TOwnerDrawState(LongRec(itemState).Lo); {$ELSE} State := TOwnerDrawState(WordRec(LongRec(itemState).Lo).Lo); {$ENDIF} Canvas.Handle := hDC; Canvas.Font := Font; Canvas.Brush := Brush; if Integer(itemID) >= 0 then DrawItem(itemID, rcItem, State) else Canvas.FillRect(rcItem); Canvas.Handle := 0; end; end; {TdxBandsListBox} procedure TdxBandsListBox.BeginDragging(DragIndex: Integer); begin if (TreeList <> nil) and (TreeList.ShowBands) then with TreeList do begin FDragAbsoluteBandIndex := Integer(Self.Items.Objects[DragIndex]); StartDragBand(FDragAbsoluteBandIndex); end; end; procedure TdxBandsListBox.DoDragging; begin if TreeList <> nil then TreeList.DoBandDragging; end; procedure TdxBandsListBox.DoEndDragging(Flag: Boolean); begin if (TreeList <> nil) and (TreeList.State = tsBandDragging) then TreeList.EndDragBand(Flag); end; procedure TdxBandsListBox.LoadItems(List: TStrings); var i: Integer; begin if (TreeList <> nil) then with TreeList do begin for i := 0 to GetAbsoluteBandCount - 1 do begin if IsBandInListBox(I) then Self.Items.AddObject(GetAbsoluteBandText(I), Pointer(I)); end; end; end; procedure TdxBandsListBox.UpdateItems; begin ItemHeight := FTreeList.FBandHeight; FMultiLine := FTreeList.FBandRowCount > 1; inherited UpdateItems; end; {TdxHeadersListBox} procedure TdxHeadersListBox.BeginDragging(DragIndex: Integer); begin if (TreeList <> nil) and (TreeList.ShowHeader) then with TreeList do begin FDragAbsoluteHeaderIndex := Integer(Self.Items.Objects[DragIndex]); if not CanHeaderDragging(FDragAbsoluteHeaderIndex) then FDragAbsoluteHeaderIndex := -1 else StartDragHeader(FDragAbsoluteHeaderIndex); end; end; procedure TdxHeadersListBox.DoDragging; begin if TreeList <> nil then TreeList.DoHeaderDragging; end; procedure TdxHeadersListBox.DoEndDragging(Flag: Boolean); begin if (TreeList <> nil) and (TreeList.State = tsColumnDragging) then TreeList.EndDragHeader(Flag); end; procedure TdxHeadersListBox.LoadItems(List: TStrings); var I: Integer; begin if (TreeList <> nil) then with TreeList do begin for I := 0 to GetHeaderAbsoluteCount - 1 do begin if IsHeaderInListBox(I) then Self.Items.AddObject(GetHeaderTextListBox(I), Pointer(I)); end; end; end; procedure TdxHeadersListBox.UpdateItems; begin ItemHeight := FTreeList.FHeaderRowHeight; FMultiLine := TreeList.GetHeaderLineRowCount > 1; inherited UpdateItems; end; {TdxTreeListTextNode} constructor TdxTreeListTextNode.Create(AOwner: TCustomdxTreeList); begin inherited Create(AOwner); FSelectedIndex := -1; FStateIndex := -1; FStrings := TStringList.Create; end; destructor TdxTreeListTextNode.Destroy; begin FStrings.Free; inherited Destroy; end; procedure TdxTreeListTextNode.ReadData(Stream: TStream); var B: Byte; I, L, Size, ItemCount: Integer; Info: PdxTextNodeInfo; S: string; begin Stream.ReadBuffer(Size, SizeOf(Size)); GetMem(Info, Size); try Stream.ReadBuffer(Info^, Size); ImageIndex := Info^.ImageIndex; SelectedIndex := Info^.SelectedIndex; StateIndex := Info^.StateIndex; Data := Info^.Data; ItemCount := Info^.Count; for I := 0 to Info^.StrCount - 1 do begin if TdxTreeList(FOwner).FStreamVersion <> 0 then // new format (huge string) begin Stream.ReadBuffer(L, SizeOf(L)); end else begin Stream.ReadBuffer(B, SizeOf(B)); L := B; end; SetLength(S, L); Stream.ReadBuffer(S[1], L); Strings[I] := S; end; finally FreeMem(Info, Size); end; for I := 0 to ItemCount - 1 do with TdxTreeListTextNode(AddChild) do ReadData(Stream); end; procedure TdxTreeListTextNode.WriteData(Stream: TStream); var I, Size, L, ItemCount: Integer; Info: PdxTextNodeInfo; S: string; begin Size := SizeOf(TdxTextNodeInfo); GetMem(Info, Size); try Info^.ImageIndex := ImageIndex; Info^.SelectedIndex := SelectedIndex; Info^.StateIndex := StateIndex; Info^.Data := Data; ItemCount := Count; Info^.Count := ItemCount; Info^.StrCount := FStrings.Count; Stream.WriteBuffer(Size, SizeOf(Size)); Stream.WriteBuffer(Info^, Size); for I := 0 to Info^.StrCount - 1 do begin S := FStrings[I]; L := Length(S); // new format (huge string) Stream.WriteBuffer(L, SizeOf(L)); Stream.WriteBuffer(S[1], L); end; finally FreeMem(Info, Size); end; for I := 0 to ItemCount - 1 do TdxTreeListTextNode(Items[I]).WriteData(Stream); end; {TdxTreeListBand} constructor TdxTreeListBand.Create(Collection: TCollection); begin FAlignment := taCenter; FMinWidth := dxGridBandMinWidth; FSizing := True; FVisible := True; FWidth := dxGridBandDefaultWidth; inherited Create(Collection); end; destructor TdxTreeListBand.Destroy; var TreeList: TCustomdxTreeListControl; I, J: Integer; begin // remove headers TreeList := GetdxTreeListControl; if (TreeList <> nil) and not (csDestroying in TreeList.ComponentState) and not (csUpdating in TreeList.ComponentState) and not ((csInheritable in TreeLIst.ComponentStyle) and (csLoading in TreeList.ComponentState)) then with TreeList do begin J := Self.Index; for I := 0 to ColumnCount - 1 do begin if Columns[I].FBandIndex = J then Columns[I].FBandIndex := -1 else if Columns[I].FBandIndex > J then Dec(Columns[I].FBandIndex); end; end; inherited Destroy; end; procedure TdxTreeListBand.Assign(Source: TPersistent); begin if Source is TdxTreeListBand then begin if Assigned(Collection) then Collection.BeginUpdate; try RestoreDefaults; Alignment := TdxTreeListBand(Source).Alignment; Caption := TdxTreeListBand(Source).Caption; Fixed := TdxTreeListBand(Source).Fixed; MinWidth := TdxTreeListBand(Source).MinWidth; OnlyOwnColumns := TdxTreeListBand(Source).OnlyOwnColumns; Sizing := TdxTreeListBand(Source).Sizing; Visible := TdxTreeListBand(Source).Visible; Width := TdxTreeListBand(Source).Width; finally if Assigned(Collection) then Collection.EndUpdate; end; end else inherited Assign(Source); end; procedure TdxTreeListBand.RestoreDefaults; begin FAlignment := taCenter; FFixed := bfNone; FMinWidth := dxGridBandMinWidth; FOnlyOwnColumns := False; FSizing := True; FWidth := dxGridBandDefaultWidth; end; // protected TdxTreeListBand function TdxTreeListBand.GetdxTreeListControl: TCustomdxTreeListControl; begin if Assigned(Collection) and (Collection is TdxTreeListBands) then Result := TdxTreeListBands(Collection).TreeList else Result := nil; end; procedure TdxTreeListBand.SetIndex(Value: Integer); procedure SetHeaderIndexes(CurBandIndex, NewBandIndex: Integer); var TreeList: TCustomdxTreeListControl; I: Integer; begin TreeList := GetdxTreeListControl; if TreeList <> nil then with TreeList do begin for I := 0 to ColumnCount - 1 do if Columns[I].FBandIndex = CurBandIndex then Columns[I].FBandIndex := NewBandIndex; end; end; var FromIndex, ToIndex, I: Integer; begin if Value < 0 then Value := 0; if Value >= Collection.Count then Value := Collection.Count - 1; if (Fixed = bfNone) and (Index <> Value) then begin FromIndex := Self.Index; ToIndex := Value; SetHeaderIndexes(FromIndex, dxGridHeaderTempIndex); if ToIndex < FromIndex then begin for I := FromIndex - 1 downto ToIndex do SetHeaderIndexes(I, I + 1); end else begin for I := FromIndex + 1 to ToIndex do SetHeaderIndexes(I, I - 1); end; SetHeaderIndexes(dxGridHeaderTempIndex, ToIndex); inherited SetIndex(Value); end; end; // private TdxTreeListBand function TdxTreeListBand.GetHeaderColCount(RowIndex: Integer): Integer; var TreeList: TCustomdxTreeListControl; begin TreeList := GetdxTreeListControl; if TreeList <> nil then Result := TreeList.GetHeaderColCount(Self.VisibleIndex, RowIndex) else Result := 0; end; function TdxTreeListBand.GetHeaderColumn(RowIndex, ColIndex: Integer): TdxTreeListColumn; var TreeList: TCustomdxTreeListControl; I: Integer; begin TreeList := GetdxTreeListControl; Result := nil; if TreeList <> nil then begin I := TreeList.GetHeaderAbsoluteIndex(Self.VisibleIndex, RowIndex, ColIndex); if I <> -1 then Result := TreeList.Columns[I]; end; end; function TdxTreeListBand.GetHeaderRowCount: Integer; var TreeList: TCustomdxTreeListControl; begin TreeList := GetdxTreeListControl; if TreeList <> nil then Result := TreeList.GetHeaderRowCount(Self.VisibleIndex) else Result := 0; end; function TdxTreeListBand.GetVisibleIndex: Integer; begin Result := TdxTreeListBands(Collection).GetVisibleIndex(Self.Index); end; procedure TdxTreeListBand.SetAlignment(Value: TAlignment); begin if FAlignment <> Value then begin FAlignment := Value; Changed(False); end; end; procedure TdxTreeListBand.SetCaption(const Value: string); begin if FCaption <> Value then begin FCaption := Value; Changed(False); end; end; procedure TdxTreeListBand.SetDisableCustomizing(Value: Boolean); begin if FDisableCustomizing <> Value then begin FDisableCustomizing := Value; Changed(False); end; end; procedure TdxTreeListBand.SetFixed(Value: TdxGridBandFixed); var i: Integer; begin if FFixed <> Value then begin // clear fixed FFixed := bfNone; if (Value <> bfNone) and Assigned(Collection) and (Collection is TdxTreeListBands) then with Collection as TdxTreeListBands do begin for i := 0 to Count - 1 do if TdxTreeListBand(Items[i]).Fixed = Value then TdxTreeListBand(Items[i]).FFixed := bfNone; // set idnex case Value of bfLeft: Index := 0; bfRight: Index := Count - 1; end; end; if Visible then FFixed := Value; Changed(False); end; end; procedure TdxTreeListBand.SetMinWidth(Value: Integer); begin if Value < 0 then Value := 0; FMinWidth := Value; SetWidth(FWidth); end; procedure TdxTreeListBand.SetSizing(Value: Boolean); begin if FSizing <> Value then begin FSizing := Value; Changed(False); end; end; procedure TdxTreeListBand.SetVisible(Value: Boolean); begin if FVisible <> Value then begin FVisible := Value; if not FVisible then FFixed := bfNone; Changed(True); end; end; procedure TdxTreeListBand.SetWidth(Value: Integer); var TreeList: TCustomdxTreeListControl; begin if Value < FMinWidth then Value := FMinWidth; TreeList := GetdxTreeListControl; if (FWidth <> Value) or (Assigned(TreeList) and TreeList.IsBandHeaderWidth) then begin FWidth := Value; Changed(True); end; end; {TdxTreeListBands} constructor TdxTreeListBands.Create(ATreeList: TCustomdxTreeListControl; BandClass: TdxTreeListBandClass); begin inherited Create(BandClass); FTreeList := ATreeList; end; function TdxTreeListBands.Add: TdxTreeListBand; begin Result := TdxTreeListBand(inherited Add); end; procedure TdxTreeListBands.RestoreDefaults; var I: Integer; begin BeginUpdate; try for I := 0 to Count-1 do Items[I].RestoreDefaults; finally EndUpdate; end; end; function TdxTreeListBands.GetAbsoluteIndex(VisibleIndex: Integer): Integer; var i, j: Integer; begin Result := -1; // speed if (TreeList <> nil) and not TreeList.FBandListLoading and (TreeList.FBandList.Count > 0) then begin if VisibleIndex < TreeList.FBandList.Count then Result := Integer(TreeList.FBandList[VisibleIndex]); Exit; end; j := -1; for i := 0 to Count - 1 do begin if TdxTreeListBand(Items[i]).Visible then Inc(j); if j = VisibleIndex then begin Result := i; Break; end; end; end; function TdxTreeListBands.GetVisibleIndex(AbsoluteIndex: Integer): Integer; var i: Integer; begin Result := -1; // speed if (TreeList <> nil) and not TreeList.FBandListLoading and (TreeList.FBandVisibleList.Count > 0) then begin if AbsoluteIndex < TreeList.FBandVisibleList.Count then Result := Integer(TreeList.FBandVisibleList[AbsoluteIndex]); Exit; end; if (AbsoluteIndex < Count) and (TdxTreeListBand(Items[AbsoluteIndex]).Visible) then begin for i := 0 to AbsoluteIndex do if TdxTreeListBand(Items[i]).Visible then Inc(Result); end; end; // protected TdxTreeListBands function TdxTreeListBands.GetOwner: TPersistent; begin Result := FTreeList; end; procedure TdxTreeListBands.RefreshFixedBands; var LeftBand, RightBand: TdxTreeListBand; Flag: Boolean; i: Integer; begin Flag := False; LeftBand := nil; RightBand := nil; for i := 0 to Count - 1 do begin case TdxTreeListBand(Items[i]).Fixed of bfLeft: begin if LeftBand = nil then begin LeftBand := TdxTreeListBand(Items[i]); if GetVisibleIndex(i) <> 0 then Flag := True; end else Flag := True; end; bfRight: begin if RightBand = nil then begin RightBand := TdxTreeListBand(Items[i]); if GetVisibleIndex(i) <> VisibleCount - 1 then Flag := True; end else Flag := True; end; end; end; if Flag then begin // clear fixed for i := 0 to Count - 1 do TdxTreeListBand(Items[i]).FFixed := bfNone; // reorder bands BeginUpdate; try if LeftBand <> nil then LeftBand.Fixed := bfLeft; if RightBand <> nil then RightBand.Fixed := bfRight; finally EndUpdate; end; end; end; procedure TdxTreeListBands.Update(Item: TCollectionItem); begin if FTreeList = nil then Exit; if FTreeList.Bands.Count <> 1 then FTreeList.FDefaultLayout := False; if csLoading in FTreeList.ComponentState then Exit; // recalculate fixed FTreeList.ClearListNodes; RefreshFixedBands; FTreeList.UpdateBands; end; // private function TdxTreeListBands.GetItem(Index: Integer): TdxTreeListBand; begin Result := TdxTreeListBand(inherited GetItem(Index)); end; function TdxTreeListBands.GetVisibleCount: Integer; var i : Integer; begin Result := 0; // speed if (TreeList <> nil) and not TreeList.FBandListLoading and (TreeList.FBandList.Count > 0) then begin Result := Integer(TreeList.FBandList.Count); Exit; end; for i := 0 to Count - 1 do if TdxTreeListBand(Items[i]).Visible then Inc(Result); end; function TdxTreeListBands.GetVisibleItem(Index: Integer): TdxTreeListBand; var i : Integer; begin Result := nil; i := GetAbsoluteIndex(Index); if i <> -1 then Result := Items[i]; end; procedure TdxTreeListBands.SetItem(Index: Integer; Value: TdxTreeListBand); begin inherited SetItem(Index, Value); end; procedure TdxTreeListBands.SetVisibleItem(Index: Integer; Value: TdxTreeListBand); var i :Integer; begin i := GetAbsoluteIndex(Index); if i <> -1 then inherited SetItem(i, Value); end; { TdxTreeListColumn } constructor TdxTreeListColumn.Create(AOwner: TComponent); begin inherited Create(AOwner); FMinWidth := dxGridHeaderMinWidth; FTabStop := True; FWidth := 100; FVisible := True; FSizing := True; FHeaderMaxLineCount := 1; FSortedOrder := -1; FViewData := GetdxInplaceEditClass.GetViewDataClass.Create; FActualIndex := -1; end; destructor TdxTreeListColumn.Destroy; var I: Integer; begin if FTreeList <> nil then begin if not (csDestroying in FTreeList.ComponentState) then begin // Delete in Strings for I := 0 to FTreeList.Count - 1 do FTreeList.DeleteStrings(FTreeList.Items[I], Self.Index); // Hidden for I := 0 to FTreeList.FHiddenList.Count - 1 do FTreeList.DeleteStrings(TdxTreeListNode(FTreeList.FHiddenList[I]), Self.Index); end; FTreeList.RemoveColumn(Self); end; if FFont <> nil then begin FFont.Free; FFont := nil; end; if FHeaderGlyph <> nil then begin FHeaderGlyph.Free; FHeaderGlyph := nil; end; FViewData.Free; inherited Destroy; end; procedure TdxTreeListColumn.Assign(Source: TPersistent); begin if Source is TdxTreeListColumn then begin if Assigned(TreeList) then TreeList.BeginUpdate; try RestoreDefaults; if cvAlignment in TdxTreeListColumn(Source).AssignedValues then Alignment := TdxTreeListColumn(Source).Alignment; if cvCaption in TdxTreeListColumn(Source).AssignedValues then Caption := TdxTreeListColumn(Source).Caption; if cvReadOnly in TdxTreeListColumn(Source).AssignedValues then ReadOnly := TdxTreeListColumn(Source).ReadOnly; if cvWidth in TdxTreeListColumn(Source).AssignedValues then Width := TdxTreeListColumn(Source).Width; if cvColor in TdxTreeListColumn(Source).AssignedValues then Color := TdxTreeListColumn(Source).Color; if cvFont in TdxTreeListColumn(Source).AssignedValues then Font := TdxTreeListColumn(Source).Font; DisableCaption := TdxTreeListColumn(Source).DisableCaption; DisableCustomizing := TdxTreeListColumn(Source).DisableCustomizing; DisableEditor := TdxTreeListColumn(Source).DisableEditor; DisableFilter := TdxTreeListColumn(Source).DisableFilter; HeaderAlignment := TdxTreeListColumn(Source).HeaderAlignment; if TdxTreeListColumn(Source).FHeaderGlyph <> nil then HeaderGlyph := TdxTreeListColumn(Source).HeaderGlyph; MinWidth := TdxTreeListColumn(Source).MinWidth; Sizing := TdxTreeListColumn(Source).Sizing; Sorted := TdxTreeListColumn(Source).Sorted; VertAlignment := TdxTreeListColumn(Source).VertAlignment; Visible := TdxTreeListColumn(Source).Visible; TabStop := TdxTreeListColumn(Source).TabStop; // new indexes BandIndex := TdxTreeListColumn(Source).BandIndex; RowIndex := TdxTreeListColumn(Source).RowIndex; ColIndex := TdxTreeListColumn(Source).ColIndex; HeaderMaxLineCount := TdxTreeListColumn(Source).HeaderMaxLineCount; finally if Assigned(TreeList) then TreeList.EndUpdate; end; end else inherited Assign(Source); end; function TdxTreeListColumn.ConvertExportValue(var Value: Variant; IsHTML: Boolean): Boolean; begin Result := False; end; function TdxTreeListColumn.DefaultAlignment: TAlignment; begin Result := taLeftJustify; end; function TdxTreeListColumn.DefaultCaption: string; begin Result := ''; end; function TdxTreeListColumn.DefaultColor: TColor; begin if TreeList <> nil then Result := TreeList.Color else Result := clWindow; end; function TdxTreeListColumn.DefaultFont: TFont; begin if TreeList <> nil then Result := TreeList.Font else Result := FFont; end; function TdxTreeListColumn.DefaultMaxLength: Integer; begin Result := 0; end; function TdxTreeListColumn.DefaultReadOnly: Boolean; begin Result := False; end; function TdxTreeListColumn.DefaultWidth: Integer; begin Result := 100; end; function TdxTreeListColumn.GetBestFit(ACanvas: TCanvas; ANode: TdxTreeListNode): Integer; var S: string; begin S := ANode.Strings[Index]; if CharCase <> ecNormal then S := ConvertTextCase(S, CharCase); Result := ACanvas.TextWidth(S); end; function TdxTreeListColumn.GetDisplayValue(Node: TdxTreeListNode; const Value: string): string; begin Result := Value; end; function TdxTreeListColumn.GetParentComponent : TComponent; begin Result := TreeList; end; function TdxTreeListColumn.HasParent: Boolean; begin HasParent := True; end; procedure TdxTreeListColumn.RestoreDefaults; begin FAssignedValues := []; RefreshDefaultFont; RefreshDefaultWidth; FDisableEditor := False; FDisableCaption := False; FDisableCustomizing := False; FHeaderAlignment := taLeftJustify; FMinWidth := dxGridHeaderMinWidth; FSizing := True; FSorted := csNone; FTabStop := True; FVertAlignment := tlTop; end; procedure TdxTreeListColumn.RestoreDefaultWidth; begin FAssignedValues := FAssignedValues - [cvWidth]; RefreshDefaultWidth; end; procedure TdxTreeListColumn.DefineProperties(Filer: TFiler); begin inherited DefineProperties(Filer); Filer.DefineProperty('SortedOrder', ReadSortedOrder, WriteSortedOrder, (TreeList <> nil) and TreeList.IsMultiSort and (TreeList.SortedColumnCount > 1) and (Sorted <> csNone)); Filer.DefineProperty('StoredRowIndex', ReadStoredRowIndex, WriteStoredRowIndex, FStoredRowIndex <> 0); end; procedure TdxTreeListColumn.ReadState(Reader: TReader); begin inherited ReadState(Reader); if Reader.Parent is TCustomdxTreeListControl then TreeList := TCustomdxTreeListControl(Reader.Parent); end; procedure TdxTreeListColumn.SetName(const Value: TComponentName); begin inherited SetName(Value); if Assigned(FOnChangeName) then FOnChangeName(Self); end; procedure TdxTreeListColumn.SetParentComponent(AParent: TComponent); begin if not (csLoading in ComponentState) then TreeList:= AParent as TCustomdxTreeListControl; end; function TdxTreeListColumn.AssignEditValue(ANode: TdxTreeListNode; AInplaceEdit: TdxInplaceEdit): Variant; begin if AInplaceEdit is TdxInplaceTextEdit then ANode.Strings[Index] := TdxInplaceTreeListTextEdit(AInplaceEdit).Text; Result := ANode.Values[Index]; end; function TdxTreeListColumn.AssignedDrawCellEvent: Boolean; begin Result := Assigned(FOnCustomDrawCell); end; procedure TdxTreeListColumn.Changed(AllItems: Boolean); var Item: TdxTreeListColumn; begin if (FTreeList <> nil) then begin if AllItems then Item := nil else Item := Self; FTreeList.UpdateColumn(Item); end; end; procedure TdxTreeListColumn.ChangedWidth(Value: Integer); begin if Value < FMinWidth then Value := FMinWidth; FWidth := Value; Include(FAssignedValues, cvWidth); end; procedure TdxTreeListColumn.DoChange(Sender: TObject); begin if (FTreeList <> nil) and not FTreeList.IsInitEdit then begin FTreeList.DoEditChange(Self); if Assigned(FOnChange) then FOnChange(Self); end; end; procedure TdxTreeListColumn.DoDrawCell(ACanvas: TCanvas; var ARect: TRect; ANode: TdxTreeListNode; ASelected, AFocused: Boolean; ANewItemRow: Boolean; ALeftEdge, ARightEdge: Boolean; ABrush: HBRUSH; var AText: string; var AColor: TColor; AFont: TFont; var AAlignment: TAlignment; var ADone: Boolean); begin if Assigned(FOnCustomDrawCell) then FOnCustomDrawCell(Self, ACanvas, ARect, ANode, Self, ASelected, AFocused, ANewItemRow, AText, AColor, AFont, AAlignment, ADone); end; procedure TdxTreeListColumn.DoValidate(Sender: TObject; var ErrorText: string; var Accept: Boolean); begin // TODO State (Init Edit) if (FTreeList <> nil) and not FTreeList.IsInitEdit then begin FTreeList.DoEditValidate(Self, ErrorText, Accept); if Assigned(FOnValidate) then FOnValidate(Self, ErrorText, Accept); end; end; procedure TdxTreeListColumn.DrawColumnIndent(DC: HDC; var ARect: TRect; ALeftEdge, ARightEdge: Boolean; ABrush: HBRUSH); begin with ARect do begin Windows.FillRect(DC, Rect(Left, Top, Right, Top + 1), ABrush); Windows.FillRect(DC, Rect(Left, Bottom - 1, Right, Bottom), ABrush); InflateRect(ARect, 0, -1); if ALeftEdge then begin Windows.FillRect(DC, Rect(Left, Top, Left + 1, Bottom), ABrush); Inc(ARect.Left, 1); end; if ARightEdge then begin Windows.FillRect(DC, Rect(Right - 1, Top, Right, Bottom), ABrush); Dec(ARect.Right, 1); end; end; end; procedure TdxTreeListColumn.FontChanged(Sender: TObject); begin Include(FAssignedValues, cvFont); Changed(True); end; function TdxTreeListColumn.GetdxInplaceEditClass: TdxInplaceEditClass; begin Result := TdxInplaceTreeListTextEdit; end; function TdxTreeListColumn.GetDisplayText(ANode: TdxTreeListNode): string; begin Result := ANode.Strings[Index]; end; function TdxTreeListColumn.GetEnableEditor: Boolean; begin Result := not FDisableEditor; end; procedure TdxTreeListColumn.GetHotTrackCursor(ANode: TdxTreeListNode; var ACursor: TCursor); begin end; function TdxTreeListColumn.GetIndex: Integer; begin if FActualIndex <> -1 then Result := FActualIndex else if FTreeList <> nil then Result := FTreeList.FColumns.IndexOf(Self) else Result := -1; end; function TdxTreeListColumn.GetMaxRowHeight(ACanvas: TCanvas): Integer; begin Result := 0; end; function TdxTreeListColumn.GetViewData: TdxEditViewData; begin Result := FViewData; end; procedure TdxTreeListColumn.InitEditProperties(AInplaceEdit: TdxInplaceEdit); begin if AInplaceEdit is TdxInplaceEdit then with TdxInplaceTreeListEdit(AInplaceEdit) do begin ReadOnly := Self.ReadOnly; OnChange := Self.DoChange; OnValidate := Self.DoValidate; end; if AInplaceEdit is TdxInplaceTextEdit then with TdxInplaceTreeListTextEdit(AInplaceEdit) do begin CharCase := Self.CharCase; MaxLength := Self.MaxLength; OEMConvert := Self.OEMConvert; PasswordChar := Self.PasswordChar; if HandleAllocated then ClearUndo; end; end; function TdxTreeListColumn.InitEditValue(ANode: TdxTreeListNode; AInplaceEdit: TdxInplaceEdit): Variant; begin TdxInplaceTreeListEdit(AInplaceEdit).Text := ANode.Strings[Index]; Result := TdxInplaceTreeListEdit(AInplaceEdit).Text; end; function TdxTreeListColumn.IsColumnHotTrack(X, Y: Integer; Node: TdxTreeListNode; var ActiveIndex: Integer): Boolean; begin Result := False; end; function TdxTreeListColumn.IsHeaderHotTrack(X, Y: Integer; var HeaderHotTrack: TdxTreeListHeaderHotTrack): Boolean; begin Result := not DisableFilter and not (csDesigning in ComponentState); end; function TdxTreeListColumn.IsColumnMultiLine: Boolean; begin Result := False; end; function TdxTreeListColumn.NeedShowButtonEdit(X, Y: Integer; IsCurrentNode: Boolean): Boolean; begin Result := False; end; procedure TdxTreeListColumn.PrepareViewData(AViewData: TdxEditViewData; ACellViewData: TdxTreeListCellViewData); begin with AViewData do begin Enabled := True; Focused := False; Selected := ACellViewData.Cell_HotTrackNode; // Style BorderColor := clNone; //TreeList.EditStyleBorderColor; BorderStyle := xbsNone; //TreeList.EditStyleBorderStyle; ButtonStyle := TreeList.EditStyleButtonStyle; // if True {TODO Option} and not Selected then // ButtonStyle := btsSimple; ButtonTransparence := False; //TODO TreeList.EditStyleButtonTransparence; Edges := TreeList.EditStyleEdges; Shadow := TreeList.EditStyleShadow; Transparent := False; // TODO if ACellViewData.Cell_InvertText then begin Transparent := True; NoTransparentText := True; end; // ViewBounds OffsetSize := Rect(1, 0, 0, 0); ViewBounds := ACellViewData.Cell_Rect; // General if ACellViewData.Cell_MultiLine then DrawAlignment := daMultiLine else DrawAlignment := TdxDrawAlignment(VertAlignment); //daSinleLine; Font := ACellViewData.Cell_Font; Brush := ACellViewData.Cell_Brush; BkColor := ColorToRGB(ACellViewData.Cell_BkColor); TextColor := ColorToRGB(ACellViewData.Cell_TextColor); Alignment := ACellViewData.Cell_Alignment; IsEditClass := False; // TODO Data := ACellViewData.Cell_Text; DataLength := ACellViewData.Cell_TextLength; //LoadDisplayValue(Data, IsPaintCopy); // TODO 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 TdxTreeListColumn.RefreshDefaultFont; var Save: TNotifyEvent; begin if cvFont in FAssignedValues then Exit; if FFont <> nil then begin Save := FFont.OnChange; FFont.OnChange := nil; try FFont.Assign(DefaultFont); finally FFont.OnChange := Save; end; end; end; procedure TdxTreeListColumn.RefreshDefaultWidth; begin if (cvWidth in FAssignedValues) then Exit; FWidth := DefaultWidth; end; procedure TdxTreeListColumn.SetIndex(Value: Integer); var FromIndex, ToIndex: Integer; CurIndex: Integer; begin CurIndex := GetIndex; if (CurIndex < 0) or (TreeList = nil) then Exit; if Value < 0 then Value := 0; if Value >= TreeList.FColumns.Count then Value := TreeList.FColumns.Count - 1; if CurIndex <> Value then begin FromIndex := Index; ToIndex := Value; with TreeList do begin TreeList.MoveNodeValues(FromIndex, ToIndex); FColumns.Delete(CurIndex); FColumns.Insert(Value, Self); Self.Changed(True); end; end; end; function TdxTreeListColumn.GetAlignment: TAlignment; begin if cvAlignment in FAssignedValues then Result := FAlignment else Result := DefaultAlignment; end; function TdxTreeListColumn.GetCaption: string; begin if cvCaption in FAssignedValues then Result := FCaption else Result := DefaultCaption; end; function TdxTreeListColumn.GetColor: TColor; begin if cvColor in FAssignedValues then Result := FColor else Result := DefaultColor; end; function TdxTreeListColumn.GetFont: TFont; var Save: TNotifyEvent; begin if FFont = nil then begin FFont := TFont.Create; if DefaultFont <> nil then FFont.Assign(DefaultFont); FFont.OnChange := FontChanged; end else if not (cvFont in FAssignedValues) and (FFont.Handle <> DefaultFont.Handle) then begin Save := FFont.OnChange; FFont.OnChange := nil; FFont.Assign(DefaultFont); FFont.OnChange := Save; end; Result := FFont; end; function TdxTreeListColumn.GetHeaderGlyph: TBitmap; begin if FHeaderGlyph = nil then FHeaderGlyph := TBitmap.Create; Result := FHeaderGlyph; end; function TdxTreeListColumn.GetMaxLength: Integer; begin if cvMaxLength in FAssignedValues then Result := FMaxLength else Result := DefaultMaxLength; end; function TdxTreeListColumn.GetReadOnly: Boolean; begin if cvReadOnly in FAssignedValues then Result := FReadOnly else Result := DefaultReadOnly; if not Result and (TreeList <> nil) then Result := TreeList.ReadOnly; {container property} end; function TdxTreeListColumn.GetVisible: Boolean; begin Result := FVisible{and (BandIndex <> -1)}; end; function TdxTreeListColumn.GetWidth: Integer; begin Result := FWidth; end; function TdxTreeListColumn.IsAlignmentStored: Boolean; begin Result := (cvAlignment in FAssignedValues){ and (FAlignment <> DefaultAlignment)}; end; function TdxTreeListColumn.IsCaptionStored: Boolean; begin Result := (cvCaption in FAssignedValues) and (FCaption <> DefaultCaption); end; function TdxTreeListColumn.IsColorStored: Boolean; begin Result := (cvColor in FAssignedValues) and (FColor <> DefaultColor); end; function TdxTreeListColumn.IsFontStored: Boolean; begin Result := (cvFont in FAssignedValues); end; function TdxTreeListColumn.IsMaxLengthStored: Boolean; begin Result := (cvMaxLength in FAssignedValues) and (FMaxLength <> DefaultMaxLength); end; function TdxTreeListColumn.IsReadOnlyStored: Boolean; begin Result := (cvReadOnly in FAssignedValues) and (FReadOnly <> DefaultReadOnly); end; function TdxTreeListColumn.IsWidthStored: Boolean; begin Result := (cvWidth in FAssignedValues); end; procedure TdxTreeListColumn.SetAlignment(Value: TAlignment); begin if (cvAlignment in FAssignedValues) and (Value = FAlignment) then Exit; FAlignment := Value; Include(FAssignedValues, cvAlignment); Changed(False); end; procedure TdxTreeListColumn.SetCaption(const Value: string); begin if (cvCaption in FAssignedValues) and (Value = FCaption) then Exit; FCaption := Value; Include(FAssignedValues, cvCaption); RefreshDefaultWidth; Changed(False); end; procedure TdxTreeListColumn.SetCharCase(Value: TEditCharCase); begin if FCharCase <> Value then begin FCharCase := Value; Changed(True); end; end; procedure TdxTreeListColumn.SetColor(Value: TColor); begin if (cvColor in FAssignedValues) and (Value = FColor) then Exit; FColor := Value; Include(FAssignedValues, cvColor); Changed(False); end; procedure TdxTreeListColumn.SetDisableCaption(Value: Boolean); begin if FDisableCaption <> Value then begin FDisableCaption := Value; Changed(True); end; end; procedure TdxTreeListColumn.SetDisableCustomizing(Value: Boolean); begin if FDisableCustomizing <> Value then begin FDisableCustomizing := Value; Changed(True); end; end; procedure TdxTreeListColumn.SetDisableFilter(Value: Boolean); begin if FDisableFilter <> Value then begin FDisableFilter := Value; Changed(True); end; end; procedure TdxTreeListColumn.SetFont(Value: TFont); begin Font.Assign(Value); Include(FAssignedValues, cvFont); Changed(True); end; procedure TdxTreeListColumn.SetHeaderAlignment(Value: TAlignment); begin if FHeaderAlignment <> Value then begin FHeaderAlignment := Value; Changed(True); end; end; procedure TdxTreeListColumn.SetHeaderGlyph(Value: TBitmap); begin if (Value = nil) then begin FHeaderGlyph.Free; FHeaderGlyph := nil; end else HeaderGlyph.Assign(Value); Changed(True); end; procedure TdxTreeListColumn.SetMaxLength(Value: Integer); begin if FMaxLength <> Value then begin FMaxLength := Value; Include(FAssignedValues, cvMaxLength); Changed(False); end; end; procedure TdxTreeListColumn.SetMinWidth(Value: Integer); begin if Value < 0 then Value := 0; FMinWidth := Value; SetWidth(FWidth); end; procedure TdxTreeListColumn.SetOEMConvert(Value: Boolean); begin if FOEMConvert <> Value then begin FOEMConvert := Value; Changed(False); end; end; procedure TdxTreeListColumn.SetPasswordChar(Value: Char); begin if FPasswordChar <> Value then begin FPasswordChar := Value; Changed(False); end; end; procedure TdxTreeListColumn.SetReadOnly(Value: Boolean); begin if (cvReadOnly in FAssignedValues) and (Value = FReadOnly) then Exit; FReadOnly := Value; Include(FAssignedValues, cvReadOnly); Changed(False); end; procedure TdxTreeListColumn.SetSizing(Value: Boolean); begin if FSizing <> Value then begin FSizing := Value; Changed(False); end; end; procedure TdxTreeListColumn.SetSorted(Value: TdxTreeListColumnSort); begin if FSorted <> Value then begin if (TreeList <> nil) and not (csLoading in TreeList.ComponentState) then begin if (Value <> csNone) then begin TreeList.BeginUpdate; try TreeList.PrepareColumnSorted(Self); FSorted := Value; TreeList.SetColumnSorted(Self); finally TreeList.EndUpdate; end; end else begin TreeList.BeginSorting; try FSorted := Value; // TreeList.FSortedColumns.Remove(Self); TreeList.RemoveSortedColumn(Self); Changed(False); finally TreeList.EndSorting; end; end; end else begin FSorted := Value; Changed(False); end; end; end; procedure TdxTreeListColumn.SetVertAlignment(Value: TTextLayout); begin if FVertAlignment <> Value then begin FVertAlignment := Value; Changed(False); end; end; procedure TdxTreeListColumn.SetVisible(Value: Boolean); begin if FVisible <> Value then begin FVisible := Value; Changed(False); end; end; procedure TdxTreeListColumn.SetWidth(Value: Integer); begin if Value < FMinWidth then Value := FMinWidth; // else // if not (csLoading in ComponentState) and not Sizing then Exit; if (cvWidth in FAssignedValues) or (Value <> DefaultWidth) then begin FWidth := Value; Include(FAssignedValues, cvWidth); Changed(False); end; end; procedure TdxTreeListColumn.SetTreeList(TreeList: TCustomdxTreeListControl); begin if FTreeList <> TreeList then begin if FTreeList <> nil then FTreeList.RemoveColumn(Self); if TreeList <> nil then TreeList.AddColumn(Self); end; end; function TdxTreeListColumn.GetBandIndex: Integer; begin Result := FBandIndex; end; function TdxTreeListColumn.GetRowIndex: Integer; begin if (TreeList <> nil) then begin Result := FStoredRowIndex; if Result >= TreeList.HeaderPanelRowCount then Result := TreeList.HeaderPanelRowCount - 1; end else Result := FRowIndex; end; function TdxTreeListColumn.GetColIndex: Integer; var I: Integer; Column: TdxTreeListColumn; begin Result := -1; if TreeList <> nil then with TreeList do for I := 0 to ColumnCount - 1 do begin Column := Columns[I]; if Column.Visible and (Column.BandIndex = Self.BandIndex) and (Column.RowIndex = Self.RowIndex) then begin Inc(Result); if Column = Self then Break; end; end; end; function TdxTreeListColumn.GetHeaderMaxLineCount: Integer; begin Result := FHeaderMaxLineCount; end; procedure TdxTreeListColumn.SetBandIndex(Value: Integer); begin if Value < -1 then Value := -1; if (TreeList <> nil) and (Value >= TreeList.Bands.Count) then Value := TreeList.Bands.Count - 1; if FBandIndex <> Value then begin FBandIndex := Value; Changed(False); end; end; procedure TdxTreeListColumn.SetRowIndex(Value: Integer); begin if Value < 0 then Value := 0; if (TreeList <> nil) and (Value >= TreeList.HeaderPanelRowCount) then Value := TreeList.HeaderPanelRowCount - 1; if {FRowIndex} RowIndex <> Value then begin FRowIndex := Value; // store max index FStoredRowIndex := Value; Changed(False); end; end; procedure TdxTreeListColumn.SetColIndex(Value: Integer); var Band: TdxTreeListBand; Column: TdxTreeListColumn; ColCount: Integer; begin if GetColIndex <> Value then begin if Self.BandIndex = -1 then Exit; Band := TreeList.Bands[Self.BandIndex]; ColCount := Band.HeaderColCount[Self.RowIndex]; if Value < 0 then Value := 0; if Value >= ColCount then Value := ColCount - 1; Column := Band.HeaderColumn[Self.RowIndex, Value]; if Column <> nil then begin if Value = (ColCount - 1) then Self.Index := Column.Index + 1 else Self.Index := Column.Index; end; end; end; procedure TdxTreeListColumn.SetHeaderMaxLineCount(Value: Integer); begin if Value < 0 then Value := 0; if FHeaderMaxLineCount <> Value then begin FHeaderMaxLineCount := Value; Changed(True); end; end; function TdxTreeListColumn.GetSortedOrder: Integer; begin Result := TreeList.FSortedColumns.IndexOf(Self); end; procedure TdxTreeListColumn.ReadSortedOrder(Reader: TReader); begin FSortedOrder := Reader.ReadInteger; end; procedure TdxTreeListColumn.WriteSortedOrder(Writer: TWriter); begin Writer.WriteInteger(Self.SortedOrder{TreeList.FSortedColumns.IndexOf(Self)}); end; procedure TdxTreeListColumn.ReadStoredRowIndex(Reader: TReader); begin FStoredRowIndex := Reader.ReadInteger; end; procedure TdxTreeListColumn.WriteStoredRowIndex(Writer: TWriter); begin Writer.WriteInteger(FStoredRowIndex); end; {TCustomdxTreeListControl} constructor TCustomdxTreeListControl.Create(AOwner : TComponent); begin inherited Create(AOwner); FColumns := TList.Create; FBands := TdxTreeListBands.Create(Self, TdxTreeListBand); FBandRowCount := 1; FBandMaxRowCount := 5; FHeaderPanelRowCount := 1; FHeaderMinRowCount := 1; FHeaderPanelMaxRowCount := 5; FEditors := TList.Create; FSortedColumns := TList.Create; FBands.FTreeList := nil; try FBands.Add; finally FBands.FTreeList := Self; end; FDefaultLayout := True; // smart calc indexes FBandList := TList.Create; FBandVisibleList := TList.Create; FHeaderAbsoluteList := TList.Create; FHeaderBounds := TList.Create; end; procedure TCustomdxTreeListControl.DoRestoreLayout; begin if FLoadedLayout then Exit; FLoadedLayout := True; if (aoStoreToRegistry in Options) and not (csDesigning in ComponentState) and (RegistryPath <> '') then LoadFromRegistry(RegistryPath); if (aoStoreToIniFile in Options) and not (csDesigning in ComponentState) and (IniFileName <> '') then LoadFromIniFile(IniFileName); end; procedure TCustomdxTreeListControl.DoSaveLayout; begin if FSavedLayout then Exit; FSavedLayout := True; if (aoStoreToRegistry in Options) and not (csDesigning in ComponentState) and (RegistryPath <> '') then SaveToRegistry(RegistryPath); if (aoStoreToIniFile in Options) and not (csDesigning in ComponentState) and (IniFileName <> '') then SaveToIniFile(IniFileName); end; destructor TCustomdxTreeListControl.Destroy; begin try DoSaveLayout; finally BeforeDestroy; if FDesigner <> nil then FDesigner.Free; // smart calc indexes ClearListNodes; FHeaderBounds.Free; FHeaderBounds := nil; FHeaderAbsoluteList.Free; FHeaderAbsoluteList := nil; FBandVisibleList.Free; FBandVisibleList := nil; FBandList.Free; FBandList := nil; if Assigned(FColumns) then DestroyColumns; FBands.Free; FBands := nil; FColumns.Free; FColumns := nil; FEditors.Free; FEditors := nil; FSortedColumns.Free; FSortedColumns := nil; inherited Destroy; end; end; procedure TCustomdxTreeListControl.ApplyBestFit(AColumn: TdxTreeListColumn); var Col: TdxTreeListColumn; MaxWidth, CharWidth, W, I: Integer; LeftColumn: Boolean; procedure CalcMaxWidth(Node: TdxTreeListNode); var I, W: Integer; begin if Node.HasChildren then for I := 0 to Node.Count - 1 do CalcMaxWidth(Node[I]); // else if not IsRowGroup(Node) then begin W := Col.GetBestFit(Canvas, Node); if LeftColumn then W := W + (Node.Level + Byte(ShowRoot and (PaintStyle = psStandard)))*FIndent - GetIndentWidth + Byte(Node.StateIndex <> -1)*FImageStateW + Byte((Node.ImageIndex <> -1) or (Node.SelectedIndex <> -1))*FImageW; if W > MaxWidth then MaxWidth := W; end; end; procedure CalcBestFit; var I: Integer; begin if IsExistColumnFont(Col.Index) then Canvas.Font := Col.Font else Canvas.Font := Self.Font; for I := 0 to Count - 1 do CalcMaxWidth(Items[I]); // Header Canvas.Font := Self.HeaderFont; W := Canvas.TextWidth(Col.Caption) + Byte(not Col.DisableFilter) * dxGridHeaderFilterBoxWidth; if W > MaxWidth then MaxWidth := W; if Col.Sizing then Col.Width := MaxWidth + 2 * CharWidth; end; function IsLeftHeader(AbsoluteIndex: Integer): Boolean; begin Result := IsHeaderVisible(AbsoluteIndex) and (GetVisibleBandIndex(GetHeaderBandIndex(AbsoluteIndex)) = 0) and (GetHeaderColIndex(AbsoluteIndex) = 0); end; begin Canvas.Font := Self.Font; MaxWidth := 0; CharWidth := Canvas.TextWidth('0') div 2 + 1; Col := AColumn; if Col = nil then begin BeginUpdate; try for i := 0 to ColumnCount - 1 do begin Col := Columns[i]; LeftColumn := IsLeftHeader(Col.Index); MaxWidth := 0; CalcBestFit; end; finally EndUpdate; end; end else begin LeftColumn := IsLeftHeader(Col.Index); CalcBestFit; end; end; procedure TCustomdxTreeListControl.AssignColumns(ATreeListControl: TCustomdxTreeListControl); var I: Integer; Column, NewColumn: TdxTreeListColumn; PrevOwner: TComponent; begin BeginUpdate; try if ColumnCount > 0 then PrevOwner := Columns[0].Owner else PrevOwner := Self; DestroyColumns; for I := 0 to ATreeListControl.ColumnCount - 1 do begin Column := ATreeListControl.Columns[I]; NewColumn := CreateColumnEx(TdxTreeListColumnClass(Column.ClassType), PrevOwner); NewColumn.Assign(Column); NewColumn.Name := Column.Name; end; finally EndUpdate; end; end; function TCustomdxTreeListControl.ColumnByName(const AName: string): TdxTreeListColumn; var I: Integer; begin Result := nil; for I := 0 to ColumnCount - 1 do if {Ansi}CompareText(Columns[I].Name, AName) = 0 then begin Result := Columns[I]; Break; end; end; function TCustomdxTreeListControl.CreateColumn(ColumnClass: TdxTreeListColumnClass): TdxTreeListColumn; begin Result := CreateColumnEx(ColumnClass, Self); end; function TCustomdxTreeListControl.CreateColumnEx(ColumnClass: TdxTreeListColumnClass; AOwner: TComponent): TdxTreeListColumn; var I: Integer; begin Result := ColumnClass.Create(AOwner); I := ColumnCount + 1; while I <> -1 do try Result.Name := Name + 'Column' + IntToStr(I); I := -1; except Inc(I); end; Result.TreeList := Self; end; procedure TCustomdxTreeListControl.DestroyColumns; var Column: TdxTreeListColumn; begin while FColumns.Count > 0 do begin Column := FColumns.Last; RemoveColumn(Column); Column.Free; end; end; function TCustomdxTreeListControl.GetAbsoluteColumnIndex(VisibleIndex: Integer): Integer; var i, j: Integer; begin Result := -1; j := -1; for i := 0 to FColumns.Count - 1 do begin if TdxTreeListColumn(FColumns[i]).Visible then Inc(j); if j = VisibleIndex then begin Result := i; Break; end; end; end; function TCustomdxTreeListControl.GetDisplayValue(Node: TdxTreeListNode; AbsoluteIndex: Integer): string; begin Result := Columns[AbsoluteIndex].GetDisplayValue(Node, Node.Strings[AbsoluteIndex]); end; function TCustomdxTreeListControl.GetVisibleColumnIndex(AbsoluteIndex: Integer): Integer; var i: Integer; begin Result := -1; if AbsoluteIndex < FColumns.Count then begin for i := 0 to AbsoluteIndex do if TdxTreeListColumn(FColumns[i]).Visible then Inc(Result); end; end; procedure TCustomdxTreeListControl.RefreshDefaultColumnsWidths; var I: Integer; begin for i := 0 to ColumnCount - 1 do Columns[i].RefreshDefaultWidth; end; procedure TCustomdxTreeListControl.RestoreColumnsDefaults; var i: Integer; begin BeginUpdate; try for i := 0 to ColumnCount - 1 do Columns[I].RestoreDefaults; finally EndUpdate; end; end; // hit test functions function TCustomdxTreeListControl.GetBandAt(X, Y: Integer): TdxTreeListBand; var Info: TdxTreeListHitInfo; begin Info := GetHitInfo(Point(X, Y)); if (Info.hitType in [htBand, htBandEdge]) and (Info.Band <> -1) then Result := Bands.VisibleItems[Info.Band] else Result := nil; end; function TCustomdxTreeListControl.GetColumnAt(X, Y: Integer): TdxTreeListColumn; var Info: TdxTreeListHitInfo; begin Info := GetHitInfo(Point(X, Y)); if (Info.hitType in [htColumn, htColumnEdge, htButton, htIcon, htStateIcon, htIndent, htLabel]) and (Info.Column <> -1) then Result := Columns[Info.Column] else Result := nil; end; function TCustomdxTreeListControl.GetFooterColumnAt(X, Y: Integer): TdxTreeListColumn; var Info: TdxTreeListHitInfo; begin Info := GetHitInfo(Point(X, Y)); if (Info.hitType in [htSummaryFooter]) and (Info.Column <> -1) then Result := Columns[Info.Column] else Result := nil; end; function TCustomdxTreeListControl.GetHeaderColumnAt(X, Y: Integer): TdxTreeListColumn; var Info: TdxTreeListHitInfo; begin Info := GetHitInfo(Point(X, Y)); if (Info.hitType in [htColumn, htColumnEdge]) and (Info.Column <> -1) then Result := Columns[Info.Column] else Result := nil; end; function TCustomdxTreeListControl.GetNodeFooterColumnAt(X, Y: Integer): TdxTreeListColumn; var Info: TdxTreeListHitInfo; begin Info := GetHitInfo(Point(X, Y)); if (Info.hitType in [htSummaryNodeFooter]) and (Info.Column <> -1) then Result := Columns[Info.Column] else Result := nil; end; procedure TCustomdxTreeListControl.BeginSorting; begin Inc(FLockSorting); end; procedure TCustomdxTreeListControl.ClearColumnsSorted; begin FSortedColumns.Clear; end; procedure TCustomdxTreeListControl.EndSorting; begin Dec(FLockSorting); if FLockSorting = 0 then RefreshSorting; end; procedure TCustomdxTreeListControl.RefreshSorting; begin end; procedure TCustomdxTreeListControl.HeaderPanelBestFit; var I, H: Integer; begin H := -1; for I := 0 to ColumnCount - 1 do if IsHeaderVisible(I) and (Columns[I].StoredRowIndex > H) then H := Columns[I].StoredRowIndex; if H <> -1 then begin FSetAutoHeaderPanelRowCount := True; try HeaderPanelRowCount := H + 1; finally FSetAutoHeaderPanelRowCount := False; end; end; end; function TCustomdxTreeListControl.ColumnCalcLineCount(ANode: TdxTreeListNode; AbsoluteIndex: Integer; const Text: string; BoundsWidth, TextHeight, MaxLineCount: Integer; InflateFlag{obsolete}, GridFlag{obsolete}: Boolean; var LineCount, LineHeight: Integer): Boolean; var ViewInfo: TdxEditViewInfo; begin Result := False; if Assigned(FOnCalcRowLineHeight) then FOnCalcRowLineHeight(Self, ANode, Columns[AbsoluteIndex], Text, BoundsWidth, TextHeight, MaxLineCount, InflateFlag{obsolete}, GridFlag{obsolete}, LineCount, LineHeight, Result); if not Result then begin with FCellViewData do begin Cell_Brush := Self.Brush.Handle; if IsExistColumnFont(AbsoluteIndex) then Cell_Font := Columns[AbsoluteIndex].Font.Handle else Cell_Font := Self.Font.Handle; Cell_BkColor := clBlack; Cell_TextColor := clBlack; Cell_Alignment := Columns[AbsoluteIndex].Alignment; Cell_Text := Text; Cell_TextLength := 0; Cell_InvertSelect := False; Cell_LeftEdge := False; Cell_RightEdge := False; Cell_MultiLine := True; Cell_InvertText := False; Cell_DrawEndEllipsis := False; Cell_Node := ANode; Cell_IsNullNode := False; Cell_SelectionColor := HighlightColor; Cell_CellBrush := Cell_Brush; Cell_CellColor := Cell_BkColor; Cell_HotTrackNode := IsHotTrackNode(ANode, AbsoluteIndex); Cell_Rect := Rect(0, 0, BoundsWidth, TextHeight); InflateRect(Cell_Rect, 2, 2); // TODO PAINT2 end; with Columns[AbsoluteIndex] do begin FActualNode := ANode; try PrepareViewData(ViewData, FCellViewData); CalcCellViewBoundsRect(Rect(0, 0, BoundsWidth, TextHeight), ViewData.ViewBounds); GetdxInplaceEditClass.CalcViewInfo(ViewData, False, ViewInfo); ViewData.CalcHeight := True; ViewData.LineCount := 0; if GetdxInplaceEditClass.DrawClientArea(TempDC, ViewInfo.ClientBounds, ViewData, False) then begin LineHeight := ViewData.LineHeight; LineCount := ViewData.LineCount; if (MaxLineCount <> -1) and (LineCount > MaxLineCount) then begin LineCount := MaxLineCount; LineHeight := LineCount * ViewData.LineTextHeight; end; end else LineCount := 1; LineHeight := TCustomdxTreeList.CalcTextRowHeight(LineHeight); finally FActualNode := nil; end; end; Result := True; end; end; // protected TCustomdxTreeListControl function TCustomdxTreeListControl.GetAbsoluteBandAlignment(AbsoluteIndex: Integer): TAlignment; begin Result := FBands.Items[AbsoluteIndex].Alignment; end; function TCustomdxTreeListControl.GetAbsoluteBandCount: Integer; begin Result := FBands.Count; end; function TCustomdxTreeListControl.GetAbsoluteBandIndex(VisibleIndex: Integer): Integer; begin Result := FBands.GetAbsoluteIndex(VisibleIndex); end; function TCustomdxTreeListControl.GetAbsoluteBandText(AbsoluteIndex: Integer): string; begin Result := FBands.Items[AbsoluteIndex].Caption; end; function TCustomdxTreeListControl.GetAbsoluteBandWidth(AbsoluteIndex: Integer): Integer; begin Result := FBands.Items[AbsoluteIndex].Width; end; function TCustomdxTreeListControl.GetBandAlignment(VisibleIndex: Integer): TAlignment; begin Result := FBands.VisibleItems[VisibleIndex].Alignment; end; function TCustomdxTreeListControl.GetBandCount: Integer; begin Result := FBands.VisibleCount; end; function TCustomdxTreeListControl.GetBandFixedLeft: Integer; begin Result := -1; with FBands do if (VisibleCount > 0) and (VisibleItems[0].Fixed = bfLeft) then Result := 0; end; function TCustomdxTreeListControl.GetBandFixedRight: Integer; begin Result := -1; with FBands do if (VisibleCount > 0) and (VisibleItems[VisibleCount - 1].Fixed = bfRight) then Result := VisibleCount - 1; end; function TCustomdxTreeListControl.GetBandMinWidthSize(VisibleIndex: Integer): Integer; begin Result := FBands.VisibleItems[VisibleIndex].MinWidth; end; function TCustomdxTreeListControl.GetBandText(VisibleIndex: Integer): string; begin Result := FBands.VisibleItems[VisibleIndex].Caption; end; function TCustomdxTreeListControl.GetBandSizeWidth(VisibleIndex: Integer): Integer; begin Result := FBands.VisibleItems[VisibleIndex].Width; end; function TCustomdxTreeListControl.GetVisibleBandIndex(AbsoluteIndex: Integer): Integer; begin Result := FBands.GetVisibleIndex(AbsoluteIndex); end; function TCustomdxTreeListControl.IsOwnBand(ABandIndex: Integer{VisibleIndex}): Boolean; begin if (0 <= ABandIndex) and (ABandIndex < GetBandCount) then Result := FBands.VisibleItems[ABandIndex].OnlyOwnColumns else Result := False; end; function TCustomdxTreeListControl.GetColumnColor(AbsoluteIndex: Integer): TColor; begin Result := Columns[AbsoluteIndex].Color; end; function TCustomdxTreeListControl.GetColumnFont(AbsoluteIndex: Integer): TFont; begin Result := Columns[AbsoluteIndex].Font; end; function TCustomdxTreeListControl.GetHeaderAbsoluteCount: Integer; begin Result := FColumns.Count; end; function TCustomdxTreeListControl.GetHeaderAbsoluteIndex(BandIndex, RowIndex, ColIndex: Integer): Integer; var I: Integer; Column: TdxTreeListColumn; begin Result := -1; // speed if not FHeaderListLoading and (FHeaderAbsoluteList.Count > 0) then begin if (BandIndex < FHeaderAbsoluteList.Count) and (RowIndex < TList(FHeaderAbsoluteList[BandIndex]).Count) and (ColIndex < TList(TList(FHeaderAbsoluteList[BandIndex])[RowIndex]).Count) then Result := Integer(TList(TList(FHeaderAbsoluteList[BandIndex])[RowIndex])[ColIndex]); Exit; end; for I := 0 to ColumnCount - 1 do begin Column := Columns[I]; if Column.Visible and (Column.BandIndex = Bands.VisibleItems[BandIndex].Index) and (Column.RowIndex = RowIndex) and (Column.ColIndex = ColIndex) then begin Result := I; Break; end; end; end; function TCustomdxTreeListControl.GetHeaderAlignment(AbsoluteIndex: Integer): TAlignment; begin Result := Columns[AbsoluteIndex].HeaderAlignment; end; function TCustomdxTreeListControl.GetHeaderBoundsWidth(AbsoluteIndex: Integer): Integer; begin if (LockUpdate = 0) and (FHeaderBounds.Count = 0) and not FHeaderBoundsLoading then MakeBoundsInfo; if not FHeaderBoundsLoading and (FHeaderBounds.Count > 0) and (AbsoluteIndex < FHeaderBounds.Count) then // speed Result := Integer(FHeaderBounds[AbsoluteIndex]) else Result := inherited GetHeaderBoundsWidth(AbsoluteIndex); end; function TCustomdxTreeListControl.GetHeaderBandIndex(AbsoluteIndex: Integer): Integer; begin Result := Columns[AbsoluteIndex].BandIndex; end; function TCustomdxTreeListControl.GetHeaderColCount(BandIndex, RowIndex: Integer): Integer; var I: Integer; Column: TdxTreeListColumn; begin Result := 0; // new check if (BandIndex = -1) or (RowIndex = -1) then Exit; // speed if not FHeaderListLoading and (FHeaderAbsoluteList.Count > 0) then begin if (BandIndex < FHeaderAbsoluteList.Count) and (RowIndex < TList(FHeaderAbsoluteList[BandIndex]).Count) then Result := TList(TList(FHeaderAbsoluteList[BandIndex])[RowIndex]).Count; Exit; end; for I := 0 to ColumnCount - 1 do begin Column := Columns[I]; if Column.Visible and (Column.BandIndex = Bands.VisibleItems[BandIndex].Index) and (Column.RowIndex = RowIndex) then Inc(Result); end; end; function TCustomdxTreeListControl.GetHeaderColIndex(AbsoluteIndex: Integer): Integer; begin Result := Columns[AbsoluteIndex].ColIndex; end; function TCustomdxTreeListControl.GetHeaderDropDownButtonState(AbsoluteIndex: Integer): TdxHeaderDropDownButtonState; begin if Columns[AbsoluteIndex].DisableFilter then Result := [] else Result := inherited GetHeaderDropDownButtonState(AbsoluteIndex); end; function TCustomdxTreeListControl.GetHeaderGlyph(AbsoluteIndex: Integer): TBitmap; begin Result := Columns[AbsoluteIndex].HeaderGlyph; end; function TCustomdxTreeListControl.GetHeaderMaxLineCount(AbsoluteIndex: Integer): Integer; begin Result := Columns[AbsoluteIndex].HeaderMaxLineCount; end; function TCustomdxTreeListControl.GetHeaderMaxRowHeight(ACanvas: TCanvas; AbsoluteIndex: Integer): Integer; begin Result := Max(inherited GetHeaderMaxRowHeight(ACanvas, AbsoluteIndex), Columns[AbsoluteIndex].GetMaxRowHeight(ACanvas)); end; function TCustomdxTreeListControl.GetHeaderMinWidth(AbsoluteIndex: Integer): Integer; begin if not Columns[AbsoluteIndex].Sizing then Result := Columns[AbsoluteIndex].Width else Result := Columns[AbsoluteIndex].MinWidth; end; function TCustomdxTreeListControl.GetHeaderRowCount(BandIndex: Integer): Integer; var PIndexes: PIntArray; I, RCount: Integer; Column: TdxTreeListColumn; begin Result := 0; // new check visible if BandIndex = -1 then Exit; // speed if not FHeaderListLoading and (FHeaderAbsoluteList.Count > 0) then begin if (BandIndex < FHeaderAbsoluteList.Count) then Result := TList(FHeaderAbsoluteList[BandIndex]).Count; Exit; end; RCount := HeaderPanelRowCount + 1; PIndexes := AllocMem(RCount * SizeOf(Integer)); try for I := 0 to ColumnCount - 1 do begin Column := Columns[I]; if Column.Visible and (Column.BandIndex = Bands.VisibleItems[BandIndex].Index) and (0 <= Column.RowIndex) and (Column.RowIndex < RCount) then PIndexes^[Column.RowIndex] := 1; end; for I := 0 to RCount - 1 do if PIndexes^[I] = 1 then Inc(Result); finally FreeMem(PIndexes); end; end; function TCustomdxTreeListControl.GetHeaderRowIndex(AbsoluteIndex: Integer): Integer; begin Result := Columns[AbsoluteIndex].RowIndex; end; function TCustomdxTreeListControl.GetHeaderSorted(AbsoluteIndex: Integer): TdxTreeListColumnSort; begin Result := Columns[AbsoluteIndex].Sorted; if Assigned(FOnColumnSorted) then FOnColumnSorted(Self, Columns[AbsoluteIndex], Result); end; function TCustomdxTreeListControl.GetHeaderTabStop(AbsoluteIndex: Integer): Boolean; begin Result := Columns[AbsoluteIndex].TabStop; end; function TCustomdxTreeListControl.GetHeaderText(AbsoluteIndex: Integer): string; begin if Columns[AbsoluteIndex].DisableCaption then Result := '' else Result := Columns[AbsoluteIndex].Caption; end; function TCustomdxTreeListControl.GetHeaderTextListBox(AbsoluteIndex: Integer): string; begin Result := Columns[AbsoluteIndex].Caption; end; function TCustomdxTreeListControl.GetHeaderWidth(AbsoluteIndex: Integer): Integer; begin Result := Columns[AbsoluteIndex].Width; end; function TCustomdxTreeListControl.IsExistColumnFont(AbsoluteIndex: Integer): Boolean; begin Result := cvFont in Columns[AbsoluteIndex].AssignedValues; end; function TCustomdxTreeListControl.IsExistHeaderGlyph(AbsoluteIndex: Integer): Boolean; begin Result := Columns[AbsoluteIndex].FHeaderGlyph <> nil; end; function TCustomdxTreeListControl.GetCellAlignment(Node: TdxTreeListNode; AbsoluteIndex: Integer): TAlignment; begin Result := Columns[AbsoluteIndex].Alignment; end; function TCustomdxTreeListControl.GetCellText(Node: TdxTreeListNode; AbsoluteIndex: Integer): string; begin Result := GetNodeString(Node, AbsoluteIndex); end; function TCustomdxTreeListControl.IsCellMultiLine(AbsoluteIndex: Integer): Boolean; begin Result := Columns[AbsoluteIndex].IsColumnMultiLine; end; function TCustomdxTreeListControl.CanBandSizing(VisibleIndex: Integer): Boolean; begin Result := inherited CanBandSizing(VisibleIndex); if Result then with FBands do Result := (0 <= VisibleIndex) and (VisibleIndex < VisibleCount) and {(VisibleItems[VisibleIndex].Fixed = bfNone) and }VisibleItems[VisibleIndex].Sizing; end; function TCustomdxTreeListControl.CanHeaderSizing(AbsoluteIndex: Integer): Boolean; begin Result := inherited CanHeaderSizing(AbsoluteIndex); if Result then Result := Columns[AbsoluteIndex].Sizing; end; procedure TCustomdxTreeListControl.ChangedBandRowCount(BandRowCount: Integer); begin SetBandRowCount(BandRowCount); end; procedure TCustomdxTreeListControl.ChangedBandWidth(VisibleIndex, Width: Integer); begin if (0 <= VisibleIndex) and (VisibleIndex < FBands.VisibleCount) then FBands.VisibleItems[VisibleIndex].Width := Width; end; procedure TCustomdxTreeListControl.ChangedHeaderMaxRowCount(RowCount: Integer); begin HeaderPanelRowCount := RowCount; end; procedure TCustomdxTreeListControl.ChangedHeaderWidth(AbsoluteIndex, Width: Integer); var Column: TdxTreeListColumn; begin Column := Columns[AbsoluteIndex]; if Column.Sizing then begin if Width < Column.FMinWidth then Width := Column.FMinWidth; Column.FWidth := Width; Include(Column.FAssignedValues, cvWidth); end; end; procedure TCustomdxTreeListControl.ChangeHiddenBandWidth(ScaleNum, ScaleDenom: Integer); var I: Integer; begin BeginUpdate; try for I := 0 to Bands.Count - 1 do if not Bands[I].Visible and Bands[I].Sizing then Bands[I].Width := MulDiv(Bands[I].Width, ScaleNum, ScaleDenom); finally EndUpdate; end; end; procedure TCustomdxTreeListControl.ChangeHiddenHeaderWidth(BandIndex: Integer; ScaleNum, ScaleDenom: Integer); var I: Integer; Column: TdxTreeListColumn; begin BeginUpdate; try BandIndex := GetAbsoluteBandIndex(BandIndex); for I := 0 to ColumnCount - 1 do begin Column := Columns[I]; if (Column.BandIndex = BandIndex) and not Column.Visible and Column.Sizing then Column.Width := MulDiv(Column.Width, ScaleNum, ScaleDenom); end; finally EndUpdate; end; end; function TCustomdxTreeListControl.GetBandMaxRowCount: Integer; begin Result := FBandMaxRowCount; end; function TCustomdxTreeListControl.GetBandRowCount: Integer; begin Result := FBandRowCount; end; function TCustomdxTreeListControl.GetHeaderMaxLimitRowCount: Integer; begin Result := FHeaderPanelMaxRowCount; end; function TCustomdxTreeListControl.GetHeaderMaxRowCount: Integer; begin Result := FHeaderPanelRowCount; end; function TCustomdxTreeListControl.GetHeaderLineRowCount: Integer; begin Result := FHeaderMinRowCount; if Result < inherited GetHeaderLineRowCount then Result := inherited GetHeaderLineRowCount; end; procedure TCustomdxTreeListControl.DoBandButtonClick; begin if Assigned(FOnBandButtonClick) then FOnBandButtonClick(Self); end; procedure TCustomdxTreeListControl.DoBandClick(VisibleIndex: Integer); begin if Assigned(FOnBandClick) then FOnBandClick(Self, Bands.VisibleItems[VisibleIndex]); end; procedure TCustomdxTreeListControl.DoBestFitBand(BandIndex: Integer); var Band: TdxTreeListBand; I, J: Integer; begin BeginUpdate; try Band := Bands.VisibleItems[BandIndex]; for J := 0 to Band.HeaderRowCount - 1 do for I := 0 to Band.HeaderColCount[J] - 1 do ApplyBestFit(Band.HeaderColumn[J, I]); finally EndUpdate; end; DoChangedColumnsWidth; end; procedure TCustomdxTreeListControl.DoBestFitColumn(AbsoluteIndex: Integer); begin ApplyBestFit(Columns[AbsoluteIndex]); DoChangedColumnsWidth; end; procedure TCustomdxTreeListControl.DoChangedColumnsWidth; begin if Assigned(FOnChangedColumnsWidth) then FOnChangedColumnsWidth(Self); end; procedure TCustomdxTreeListControl.DoHeaderButtonClick; begin if Assigned(FOnHeaderButtonClick) then FOnHeaderButtonClick(Self); end; procedure TCustomdxTreeListControl.DoHeaderClick(AbsoluteIndex: Integer); var Column: TdxTreeListColumn; begin Column := Columns[AbsoluteIndex]; if Assigned(FOnColumnClick) then FOnColumnClick(Self, Column); if IsAutoSort then DoColumnSort(Column); end; function TCustomdxTreeListControl.IsBandHeaderWidth: Boolean; begin Result := DefaultLayout or inherited IsBandHeaderWidth; end; function TCustomdxTreeListControl.GetNodeDragText(Node: TdxTreeListNode; AbsoluteIndex: Integer): string; begin Result := inherited GetNodeDragText(Node, AbsoluteIndex); if Assigned(FOnGetNodeDragText) then FOnGetNodeDragText(Self, Node, Columns[AbsoluteIndex], Result); end; procedure TCustomdxTreeListControl.BandMoved(FromIndex, ToIndex: Integer); begin if FromIndex <> ToIndex then with FBands do Bands[GetAbsoluteIndex(FromIndex)].Index := GetAbsoluteIndex(ToIndex); end; function TCustomdxTreeListControl.CanBandDragging(VisibleIndex: Integer): Boolean; var Band: TdxTreeListBand; begin Result := inherited CanBandDragging(VisibleIndex); with FBands do if (0 <= VisibleIndex) and (VisibleIndex < VisibleCount) then Band := VisibleItems[VisibleIndex] else Band := nil; if Result and (Band <> nil) then begin Result := (Band.Fixed = bfNone) and not Band.DisableDragging; if Result and Assigned(FOnCanBandDragging) then FOnCanBandDragging(Self, Band, Result); end; end; procedure TCustomdxTreeListControl.DoDragOverBand(P: TPoint; AbsoluteIndex: Integer; var Accept: Boolean); begin inherited DoDragOverBand(P, AbsoluteIndex, Accept); if Assigned(FOnDragOverBand) then FOnDragOverBand(Self, Bands[AbsoluteIndex], P, Accept); end; procedure TCustomdxTreeListControl.DoEndDragBand(P: TPoint; AbsoluteIndex, VisibleIndex: Integer; var NewIndex: Integer; var Accept: Boolean); begin inherited DoEndDragBand(P, AbsoluteIndex, VisibleIndex, NewIndex, Accept); if Assigned(FOnDragEndBand) then FOnDragEndBand(Self, Bands[AbsoluteIndex], P, AbsoluteIndex, VisibleIndex, NewIndex, Accept); end; function TCustomdxTreeListControl.GetBandDisableCustomizing(AbsoluteIndex: Integer): Boolean; begin Result := FBands[AbsoluteIndex].DisableCustomizing; end; procedure TCustomdxTreeListControl.HideBand(AbsoluteIndex: Integer); begin FBands[AbsoluteIndex].Visible := False; if Assigned(FOnHideBand) then FOnHideBand(Self, Bands[AbsoluteIndex]); end; function TCustomdxTreeListControl.IsBandInListBox(AbsoluteIndex: Integer): Boolean; begin with FBands.Items[AbsoluteIndex] do Result := not Visible and not DisableCustomizing; end; procedure TCustomdxTreeListControl.ShowBand(NewIndex{visible index}, AbsoluteIndex: Integer); var Band: TdxTreeListBand; begin BeginUpdate; try Band := FBands[AbsoluteIndex]; Band.Visible := True; if NewIndex < 0 then NewIndex := 0; if FBands.VisibleCount > 1 then if NewIndex >= FBands.VisibleCount then Band.Index := FBands.Count - 1 else Band.Index := FBands.VisibleItems[NewIndex].Index; finally EndUpdate; end; if Assigned(FOnShowBand) then FOnShowBand(Self, Band, NewIndex); end; procedure TCustomdxTreeListControl.StartDragBand(AbsoluteIndex: Integer); begin inherited StartDragBand(AbsoluteIndex); if Assigned(FOnStartBandDragging) then FOnStartBandDragging(Self, Bands[AbsoluteIndex]); end; function TCustomdxTreeListControl.CanHeaderDragging(AbsoluteIndex: Integer): Boolean; begin Result := inherited CanHeaderDragging(AbsoluteIndex) and not IsFixedBandHeader(AbsoluteIndex) and not Columns[AbsoluteIndex].DisableDragging; if Result and Assigned(FOnCanHeaderDragging) then FOnCanHeaderDragging(Self, Columns[AbsoluteIndex], Result); end; procedure TCustomdxTreeListControl.DoDragOverHeader(P: TPoint; AbsoluteIndex: Integer; var Accept: Boolean); begin inherited DoDragOverHeader(P, AbsoluteIndex, Accept); if Assigned(FOnDragOverHeader) then FOnDragOverHeader(Self, Columns[AbsoluteIndex], P, Accept); end; procedure TCustomdxTreeListControl.DoEndDragHeader(P: TPoint; AbsoluteIndex: Integer; var NewPosInfo: TdxHeaderPosInfo; var Accept: Boolean); begin inherited DoEndDragHeader(P, AbsoluteIndex, NewPosInfo, Accept); if Assigned(FOnDragEndHeader) then FOnDragEndHeader(Self, Columns[AbsoluteIndex], P, NewPosInfo, Accept); // obsolete if GetBandCount = 1 then begin if Assigned(FOnColumnMoved) then FOnColumnMoved(Self, GetHeaderColIndex(AbsoluteIndex), NewPosInfo.ColIndex); if Assigned(FOnEndDragColumn) then FOnEndDragColumn(Self, P.X, P.Y, Columns[AbsoluteIndex], NewPosInfo.ColIndex); end; end; function TCustomdxTreeListControl.GetHeaderDisableCustomizing(AbsoluteIndex: Integer): Boolean; begin Result := Columns[AbsoluteIndex].DisableCustomizing; end; procedure TCustomdxTreeListControl.HeaderMoved(FromAbsoluteIndex, ToBandIndex, ToRowIndex, ToColIndex: Integer); var Column: TdxTreeListColumn; begin BeginUpdate; try Column := Columns[FromAbsoluteIndex]; Column.BandIndex := Bands.GetAbsoluteIndex(ToBandIndex); Column.RowIndex := ToRowIndex; Column.ColIndex := ToColIndex; finally EndUpdate; end; if Assigned(FOnHeaderMoved) then FOnHeaderMoved(Self, Column); end; procedure TCustomdxTreeListControl.HideHeader(AbsoluteIndex: Integer); begin Columns[AbsoluteIndex].Visible := False; if Assigned(FOnHideHeader) then FOnHideHeader(Self, Columns[AbsoluteIndex]); end; function TCustomdxTreeListControl.IsHeaderInListBox(AbsoluteIndex: Integer): Boolean; var Column: TdxTreeListColumn; begin Column := Columns[AbsoluteIndex]; Result := (not Column.Visible or (Column.BandIndex = -1)) and not Column.DisableCustomizing; if not Column.DisableCustomizing and not Result and ShowHiddenInCustomizeBox and not IsHeaderVisible(AbsoluteIndex) then Result := True; end; function TCustomdxTreeListControl.IsHeaderVisible(AbsoluteIndex: Integer): Boolean; var Column: TdxTreeListColumn; begin Column := Columns[AbsoluteIndex]; Result := Column.Visible and (Column.BandIndex <> -1) and (Bands.Count > 0) and Bands[Column.BandIndex].Visible; end; procedure TCustomdxTreeListControl.ShowColumnHeader(BandIndex, RowIndex, ColIndex, AbsoluteIndex: Integer); var Column: TdxTreeListColumn; begin BeginUpdate; try Column := Columns[AbsoluteIndex]; Column.BandIndex := Bands.GetAbsoluteIndex(BandIndex); Column.Visible := True; Column.RowIndex := RowIndex; Column.ColIndex := ColIndex; finally EndUpdate; end; if Assigned(FOnShowHeader) then FOnShowHeader(Self, Column, BandIndex, RowIndex, ColIndex); end; procedure TCustomdxTreeListControl.StartDragHeader(AbsoluteIndex: Integer); begin inherited StartDragHeader(AbsoluteIndex); if Assigned(FOnStartHeaderDragging) then FOnStartHeaderDragging(Self, Columns[AbsoluteIndex]); end; function TCustomdxTreeListControl.CreateEditor(AColumn: Integer): TdxInplaceEdit; begin Result := Columns[GetFocusedAbsoluteIndex(AColumn)].GetdxInplaceEditClass.Create(Self); FEditors.Add(Result); end; procedure TCustomdxTreeListControl.DoBeforeEditing(Node : TdxTreeListNode; var AllowEditing: Boolean); begin inherited DoBeforeEditing(Node, AllowEditing); if AllowEditing and (0 <= FocusedColumn) and (FocusedColumn < GetVisibleHeaderCount) then AllowEditing := Columns[FocusedAbsoluteIndex].GetEnableEditor; end; procedure TCustomdxTreeListControl.DoHotTrackNode(AHotTrackInfo: TdxTreeListHotTrackInfo; var ACursor: TCursor); begin with AHotTrackInfo do if (Column <> -1) and (Node <> nil) then Columns[Column].GetHotTrackCursor(Node, ACursor); inherited DoHotTrackNode(AHotTrackInfo, ACursor); end; function TCustomdxTreeListControl.FindInplaceEdit(AColumn: Integer): TdxInplaceEdit; var I: Integer; EditClass: TdxInplaceEditClass; begin Result := nil; EditClass := Columns[GetFocusedAbsoluteIndex(AColumn)].GetdxInplaceEditClass; for I := 0 to FEditors.Count - 1 do if TdxInplaceEdit(FEditors[I]).ClassType = EditClass then begin Result := FEditors[i]; Exit; end; end; procedure TCustomdxTreeListControl.InitEditProperties(AInplaceEdit: TdxInplaceEdit); begin inherited InitEditProperties(AInplaceEdit); if FocusedAbsoluteIndex <> -1 then Columns[FocusedAbsoluteIndex].InitEditProperties(AInplaceEdit); end; function TCustomdxTreeListControl.InitEditValue(ANode: TdxTreeListNode; AInplaceEdit: TdxInplaceEdit): Variant; begin if FocusedAbsoluteIndex <> -1 then Result := Columns[FocusedAbsoluteIndex].InitEditValue(ANode, AInplaceEdit) else Result := inherited InitEditValue(ANode, AInplaceEdit); end; procedure TCustomdxTreeListControl.ClearListNodes; var I, J: Integer; List: TList; begin inherited ClearListNodes; if FBandList <> nil then FBandList.Clear; if FBandVisibleList <> nil then FBandVisibleList.Clear; if FHeaderAbsoluteList <> nil then begin for I := 0 to FHeaderAbsoluteList.Count - 1 do begin List := FHeaderAbsoluteList[I]; // get row list for J := 0 to List.Count - 1 do // free col list TList(List[J]).Free; List.Free; // free row list end; FHeaderAbsoluteList.Clear; end; ClearBoundsInfo; end; procedure TCustomdxTreeListControl.ClearNodeRowHeight; begin inherited ClearNodeRowHeight; ClearBoundsInfo; end; type PdxHeaderCalculateInfo =^TdxHeaderCalculateInfo; TdxHeaderCalculateInfo = record Column: TdxTreeListColumn; BandIndex: Integer; RowIndex: Integer; Index: Integer; // calculate in cycle for I := 0 end; function CompareHeaders(Item1, Item2: Pointer): Integer; begin Result := PdxHeaderCalculateInfo(Item1)^.BandIndex - PdxHeaderCalculateInfo(Item2)^.BandIndex; if Result = 0 then begin Result := PdxHeaderCalculateInfo(Item1)^.RowIndex - PdxHeaderCalculateInfo(Item2)^.RowIndex; if Result = 0 then Result := PdxHeaderCalculateInfo(Item1)^.Index - PdxHeaderCalculateInfo(Item2)^.Index; end; end; function TCustomdxTreeListControl.IsColumnHotTrack(X, Y: Integer; Node: TdxTreeListNode; ColumnAbsoluteIndex: Integer; var ActiveIndex: Integer): Boolean; begin Result := inherited IsColumnHotTrack(X, Y, Node, ColumnAbsoluteIndex, ActiveIndex); if not Result and (ColumnAbsoluteIndex <> -1) then Result := Columns[ColumnAbsoluteIndex].IsColumnHotTrack(X, Y, Node, ActiveIndex); end; function TCustomdxTreeListControl.IsHeaderHotTrack(X, Y: Integer; ColumnAbsoluteIndex: Integer; var HeaderHotTrack: TdxTreeListHeaderHotTrack): Boolean; begin Result := inherited IsHeaderHotTrack(X, Y, ColumnAbsoluteIndex, HeaderHotTrack); if ColumnAbsoluteIndex <> -1 then Result := Result and Columns[ColumnAbsoluteIndex].IsHeaderHotTrack(X, Y, HeaderHotTrack); end; procedure TCustomdxTreeListControl.MakeBandHeaderList(CalcBounds: Boolean); var I, J, B, R, C: Integer; RowList, ColList, List: TList; AHeaderList: TList; PHeaderInfo: PdxHeaderCalculateInfo; AColumn: TdxTreeListColumn; begin if (FBandList <> nil) and (FBandVisibleList <> nil) and (FHeaderAbsoluteList <> nil) and (FHeaderBounds <> nil) then begin // bands FBandListLoading := True; try // get absolute index from visible index C := Bands.GetVisibleCount; FBandList.Clear; FBandList.Capacity := C; for I := 0 to C - 1 do FBandList.Add(Pointer(Bands.GetAbsoluteIndex(I))); // get visible index from absolute index C := Bands.Count; FBandVisibleList.Clear; FBandVisibleList.Capacity := C; for I := 0 to C - 1 do FBandVisibleList.Add(Pointer(Bands.GetVisibleIndex(I))); finally FBandListLoading := False; end; // headers FHeaderListLoading := True; try // get absolute index from band, row, col index for I := 0 to FHeaderAbsoluteList.Count - 1 do begin List := FHeaderAbsoluteList[I]; // get row list for J := 0 to List.Count - 1 do // free col list TList(List[J]).Free; List.Free; // free row list end; FHeaderAbsoluteList.Clear; B := FBandList.Count; // Visible Band Count FHeaderAbsoluteList.Capacity := B; // create temp list AHeaderList := TList.Create; try if Bands.Count > 0 then for I := 0 to ColumnCount - 1 do begin AColumn := Columns[I]; if AColumn.Visible and (AColumn.BandIndex <> -1) and Bands.Items[AColumn.BandIndex].Visible then begin New(PHeaderInfo); PHeaderInfo^.Column := AColumn; PHeaderInfo^.BandIndex := AColumn.BandIndex; PHeaderInfo^.RowIndex := AColumn.RowIndex; PHeaderInfo^.Index := I; AHeaderList.Add(PHeaderInfo); end; end; AHeaderList.Sort(CompareHeaders); // Save to FHeaderAbsoluteList if AHeaderList.Count > 0 then begin FHeaderAbsoluteList.Capacity := FBandList.Count; I := 0; PHeaderInfo := AHeaderList[I]; repeat RowList := TList.Create; B := PHeaderInfo^.BandIndex; repeat ColList := TList.Create; R := PHeaderInfo^.RowIndex; repeat ColList.Add(Pointer(PHeaderInfo^.Index)); Inc(I); if I >= AHeaderList.Count then Break; PHeaderInfo := AHeaderList[I]; until (PHeaderInfo^.BandIndex <> B) or (PHeaderInfo^.RowIndex <> R); RowList.Add(ColList); if I >= AHeaderList.Count then Break; until (PHeaderInfo^.BandIndex <> B); // check band empty while FHeaderAbsoluteList.Count < Bands.GetVisibleIndex(B) do FHeaderAbsoluteList.Add(TList.Create); FHeaderAbsoluteList.Add(Pointer(RowList)); until (I >= AHeaderList.Count); end; finally for I := 0 to AHeaderList.Count - 1 do begin PHeaderInfo := AHeaderList[I]; Dispose(PHeaderInfo); end; AHeaderList.Free; end; finally FHeaderListLoading := False; end; ClearBoundsInfo; // if CalcBounds then MakeBoundsInfo; end; end; procedure TCustomdxTreeListControl.ClearBoundsInfo; begin inherited ClearBoundsInfo; if FHeaderBounds <> nil then FHeaderBounds.Clear; end; procedure TCustomdxTreeListControl.MakeBoundsInfo; var I, J: Integer; begin inherited MakeBoundsInfo; if FHeaderBounds = nil then Exit; FHeaderBoundsLoading := True; try FHeaderBounds.Clear; FHeaderBounds.Capacity := GetVisibleHeaderCount; for I := 0 to ColumnCount - 1 do begin if IsHeaderVisible(I) then J := GetHeaderBoundsWidth(I) else J := 0; FHeaderBounds.Add(Pointer(J)); end; finally FHeaderBoundsLoading := False; end; end; procedure TCustomdxTreeListControl.MakeListNodes; begin inherited MakeListNodes; MakeBandHeaderList(True); end; procedure TCustomdxTreeListControl.MoveNodeValues(FromIndex, ToIndex: Integer); procedure MoveValue(Item: TdxTreeListNode); begin with Item as TdxTreeListTextNode do begin if ToIndex >= FStrings.Count then while FStrings.Add('') < ToIndex do; if FromIndex >= FStrings.Count then while FStrings.Add('') < FromIndex do; if (FromIndex < ToIndex) then begin if (ToIndex + 1) = FStrings.Count then begin FStrings.Add(FStrings[FromIndex]); FStrings.Objects[FStrings.Count-1] := FStrings.Objects[FromIndex]; end else begin FStrings.Insert(ToIndex + 1, FStrings[FromIndex]); FStrings.Objects[ToIndex + 1] := FStrings.Objects[FromIndex]; end; FStrings.Delete(FromIndex); end else begin FStrings.Insert(ToIndex, FStrings[FromIndex]); FStrings.Objects[ToIndex] := FStrings.Objects[FromIndex + 1]; FStrings.Delete(FromIndex + 1); end; end; end; procedure MoveValues(Node: TdxTreeListNode); var I: Integer; begin MoveValue(Node); for I := 0 to Node.Count - 1 do MoveValues(Node[I]); end; var I: Integer; begin for I := 0 to Count - 1 do MoveValues(Items[i]); // Hidden for I := 0 to FHiddenList.Count - 1 do MoveValues(TdxTreeListNode(FHiddenList[I])); end; procedure TCustomdxTreeListControl.ResetAutoHeaderPanelRowCountOption; begin FOptionsEx := FOptionsEx - [aoAutoHeaderPanelHeight]; end; function TCustomdxTreeListControl.NeedShowButtonEdit(X, Y: Integer; IsCurrentNode: Boolean; ColumnAbsoluteIndex: Integer): Boolean; begin Result := inherited NeedShowButtonEdit(X, Y, IsCurrentNode, ColumnAbsoluteIndex); if Result and (ColumnAbsoluteIndex <> -1) then Result := Columns[ColumnAbsoluteIndex].NeedShowButtonEdit(X, Y, IsCurrentNode); end; procedure TCustomdxTreeListControl.UpdateBands; begin // calc best panel size if IsAutoHeaderPanelRowCount then begin BeginUpdate; try HeaderPanelBestFit; finally EndUpdate; end; end else LayoutChanged; end; procedure TCustomdxTreeListControl.UpdateColumn(Column: TdxTreeListColumn); begin if csLoading in ComponentState then Exit; if Column <> nil then Column.RefreshDefaultWidth; // RefreshRowIndexes; if FLockRefreshRowIndexes = 0 then RefreshRowIndexes; LayoutChanged; end; procedure TCustomdxTreeListControl.UpdateHeaders; begin LayoutChanged; end; procedure TCustomdxTreeListControl.AddSortedColumn(Column: TdxTreeListColumn); begin if (Column <> nil) and (FSortedColumns.IndexOf(Column) = -1) and (Column.Sorted <> csNone) then FSortedColumns.Add(Column); end; function TCustomdxTreeListControl.CanColumnSorting(Column: TdxTreeListColumn): Boolean; begin Result := True; if Assigned(FOnColumnSorting) then FOnColumnSorting(Self, Column, Result); end; procedure TCustomdxTreeListControl.DoColumnSort(Column: TdxTreeListColumn); begin if CanColumnSorting(Column) then begin if FlagClearSort then Column.Sorted := csNone else if Column.Sorted in [csDown, csNone] then Column.Sorted := csUp else Column.Sorted := csDown; end; end; procedure TCustomdxTreeListControl.PrepareColumnSorted(Column: TdxTreeListColumn); begin end; procedure TCustomdxTreeListControl.RefreshSortedList; var I: Integer; begin for I := 0 to ColumnCount - 1 do if Columns[I].Sorted <> csNone then AddSortedColumn(Columns[I]); FSortedColumns.Sort(CompareSortedOrderColumns); end; procedure TCustomdxTreeListControl.RemoveSortedColumn(Column: TdxTreeListColumn); begin FSortedColumns.Remove(Column); end; procedure TCustomdxTreeListControl.SetColumnSorted(Column: TdxTreeListColumn); begin if (Column.Sorted <> csNone) {and (FlagMultiSort or LockSorting)} then AddSortedColumn(Column); end; procedure TCustomdxTreeListControl.BeginCustomLayout; begin inherited BeginCustomLayout; MakeBandHeaderList(True); end; function TCustomdxTreeListControl.CanEditModify: Boolean; var I: Integer; begin I := FocusedAbsoluteIndex; if (I <> -1) and not Columns[I].ReadOnly then Result := True else Result := False; end; function TCustomdxTreeListControl.CreateNode: TdxTreeListNode; begin Result := TdxTreeListTextNode.Create(Self); end; function TCustomdxTreeListControl.GetSortedColumnCount: Integer; begin Result := FSortedColumns.Count; end; function TCustomdxTreeListControl.GetSortedColumnDesc(Index: Integer): Boolean; begin Result := SortedColumns[Index].Sorted = csDown; end; function TCustomdxTreeListControl.GetSortedColumnIndex(Index: Integer): Integer; begin Result := SortedColumns[Index].Index; end; function TCustomdxTreeListControl.GetNodeImageIndex(Node : TdxTreeListNode) : Integer; begin Result := (Node as TdxTreeListTextNode).FImageIndex; if Assigned(FOnGetImageIndex) then FOnGetImageIndex(Self, Node, Result); end; function TCustomdxTreeListControl.GetNodeSelectedIndex(Node : TdxTreeListNode) : Integer; begin Result := (Node as TdxTreeListTextNode).FSelectedIndex; if Assigned(FOnGetSelectedIndex) then FOnGetSelectedIndex(Self, Node, Result); end; function TCustomdxTreeListControl.GetNodeStateIndex(Node : TdxTreeListNode) : Integer; begin Result := (Node as TdxTreeListTextNode).FStateIndex; if Assigned(FOnGetStateIndex) then FOnGetStateIndex(Self, Node, Result); end; function TCustomdxTreeListControl.GetNodeValue(Node: TdxTreeListNode; Column: Integer) : Variant; begin Result := (Node as TdxTreeListTextNode).Strings[Column]; end; function TCustomdxTreeListControl.GetNodeString(Node: TdxTreeListNode; Column: Integer): string; begin with Node as TdxTreeListTextNode do if Column < FStrings.Count then Result := FStrings[Column] else Result := ''; end; function TCustomdxTreeListControl.LockSorting: Boolean; begin Result := FLockSorting <> 0; end; procedure TCustomdxTreeListControl.RemoveColumn(Column: TdxTreeListColumn); begin Column.FTreeList := nil; // TODO remove strings FColumns.Remove(Column); // FSortedColumns.Remove(Column); RemoveSortedColumn(Column); if not (csDestroying in ComponentState) then UpdateColumn(nil); end; procedure TCustomdxTreeListControl.SetNodeImageIndex(Node : TdxTreeListNode; Value : Integer); begin if Node.ImageIndex <> Value then (Node as TdxTreeListTextNode).FImageIndex := Value; UpdateNode(Node, False {no Below}); end; procedure TCustomdxTreeListControl.SetNodeSelectedIndex(Node : TdxTreeListNode; Value : Integer); begin if Node.SelectedIndex <> Value then (Node as TdxTreeListTextNode).FSelectedIndex := Value; UpdateNode(Node, False {no Below}); end; procedure TCustomdxTreeListControl.SetNodeStateIndex(Node : TdxTreeListNode; Value : Integer); begin if Node.StateIndex <> Value then (Node as TdxTreeListTextNode).FStateIndex := Value; UpdateNode(Node, False {no Below}); end; procedure TCustomdxTreeListControl.SetNodeString(Node: TdxTreeListNode; Column: Integer; const Value: string); begin with Node as TdxTreeListTextNode do begin if Column >= FStrings.Count then while FStrings.Add('') < Column do; FStrings[Column] := Value; end; end; procedure TCustomdxTreeListControl.SetNodeValue(Node: TdxTreeListNode; Column: Integer; const Value: Variant); begin Node.Strings[Column] := VarToStr(Value); if FLockUpdate = 0 then InvalidateRect(GetRectNode(Node)); end; procedure TCustomdxTreeListControl.BeginReadSettings(ARegIniWrapper: TdxRegIniWrapper); begin BeginUpdate; if IsMultiSort then BeginSorting; end; procedure TCustomdxTreeListControl.EndReadSettings(ARegIniWrapper: TdxRegIniWrapper); begin if IsMultiSort then EndSorting; EndUpdate; end; procedure TCustomdxTreeListControl.LoadFromRegIni(ARegIniObject: TObject; APath: string); var RegIniWrapper: TdxRegIniWrapper; APathCol, S: string; I, ID, J: Integer; ABand: TdxTreeListBand; AColumn: TdxTreeListColumn; FList: TStringList; 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); RegIniWrapper := TdxRegIniWrapper.Create; try RegIniWrapper.RegIniObject := ARegIniObject; with RegIniWrapper do begin FList := TStringList.Create; BeginReadSettings(RegIniWrapper); try ReadSettings(RegIniWrapper, APath); // bands for I := 0 to Bands.Count - 1 do begin APathCol := APath + '\Band\Band' + IntToStr(I); ID := ReadInteger(APathCol, 'ID', -1); ABand := nil; if ID <> -1 then // find band by ID for J := 0 to Bands.Count - 1 do if Bands[J].ID = ID then begin ABand := Bands[J]; Break; end; if ABand <> nil then begin ABand.Visible := ReadBool(APathCol, 'Visible', ABand.Visible); ABand.Width := ReadInteger(APathCol, 'Width', ABand.Width); // add in sort list Str(ReadInteger(APathCol, 'Index', ABand.Index): 11, S); FList.AddObject(S, ABand); end; end; FList.Sorted := True; for I := 0 to FList.Count - 1 do TdxTreeListBand(FList.Objects[I]).Index := I; // columns FList.Clear; FList.Sorted := False; for I := 0 to ColumnCount - 1 do begin AColumn := Columns[I]; APathCol := APath + '\Columns\' + AColumn.Name; ReadColumn(RegIniWrapper, APathCol, AColumn); Str(ReadInteger(APathCol, 'Index', AColumn.Index): 11, S); FList.AddObject(S, AColumn); end; // columns order FList.Sorted := True; for I := 0 to FList.Count - 1 do TdxTreeListColumn(FList.Objects[I]).Index := I; Inc(FLockRefreshRowIndexes); try for I := 0 to ColumnCount - 1 do begin AColumn := Columns[I]; APathCol := APath + '\Columns\' + AColumn.Name; AColumn.BandIndex := ReadInteger(APathCol, 'BandIndex', AColumn.BandIndex); AColumn.RowIndex := ReadInteger(APathCol, 'RowIndex', AColumn.RowIndex); AColumn.StoredRowIndex := ReadInteger(APathCol, 'StoredRowIndex', Integer(AColumn.StoredRowIndex)); end; finally Dec(FLockRefreshRowIndexes); UpdateColumn(nil); end; // Resync Sorted if IsMultiSort then RefreshSortedList; finally EndReadSettings(RegIniWrapper); FList.Free; end; end; finally RegIniWrapper.Free; end; end; procedure TCustomdxTreeListControl.ReadColumn(ARegIniWrapper: TdxRegIniWrapper; const APathCol: string; AColumn: TdxTreeListColumn); begin with ARegIniWrapper do begin AColumn.Visible := ReadBool(APathCol, 'Visible', AColumn.Visible); AColumn.Width := ReadInteger(APathCol,'Width', AColumn.Width); AColumn.Sorted := TdxTreeListColumnSort(ReadInteger(APathCol, 'Sorted', Integer(AColumn.Sorted))); AColumn.SortedOrder := ReadInteger(APathCol, 'SortedOrder', Integer(-1)); end; end; procedure TCustomdxTreeListControl.ReadSettings(ARegIniWrapper: TdxRegIniWrapper; const APath: string); var H: Integer; begin with ARegIniWrapper do begin ShowGrid := ReadBool(APath, 'ShowGrid', ShowGrid); ShowPreviewGrid := ReadBool(APath, 'ShowPreviewGrid', ShowPreviewGrid); BandRowCount := ReadInteger(APath, 'BandRowCount', BandRowCount); DefaultRowHeight := ReadInteger(APath, 'DefaultRowHeight', DefaultRowHeight); H := ReadInteger(APath, 'HeaderPanelRowCount', HeaderPanelRowCount); if H <> -1 then begin ResetAutoHeaderPanelRowCountOption; HeaderPanelRowCount := H; end; end; end; procedure TCustomdxTreeListControl.SaveToRegIni(ARegIniObject: TObject; APath: string); var RegIniWrapper: TdxRegIniWrapper; I: Integer; AColumn: TdxTreeListColumn; 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); RegIniWrapper := TdxRegIniWrapper.Create; try RegIniWrapper.RegIniObject := ARegIniObject; with RegIniWrapper do begin // erase prev settings Erase(APath); // write settings WriteSettings(RegIniWrapper, APath); // columns for I := 0 to ColumnCount - 1 do begin AColumn := TdxTreeListColumn(Columns[I]); WriteColumn(RegIniWrapper, APath + '\Columns\' + AColumn.Name, AColumn); end; end; finally RegIniWrapper.Free; end; end; procedure TCustomdxTreeListControl.WriteColumn(ARegIniWrapper: TdxRegIniWrapper; const APathCol: string; AColumn: TdxTreeListColumn); begin with ARegIniWrapper do begin WriteInteger(APathCol, 'BandIndex', Integer(AColumn.BandIndex)); WriteInteger(APathCol, 'RowIndex', Integer(AColumn.RowIndex)); WriteInteger(APathCol, 'ColIndex', Integer(AColumn.ColIndex)); WriteBool(APathCol, 'Visible', AColumn.Visible); WriteInteger(APathCol, 'Index', AColumn.Index); WriteInteger(APathCol, 'Width', AColumn.Width); WriteInteger(APathCol, 'Sorted', Integer(AColumn.Sorted)); WriteInteger(APathCol, 'SortedOrder', Integer(AColumn.SortedOrder)); WriteInteger(APathCol, 'StoredRowIndex', Integer(AColumn.StoredRowIndex)); end; end; procedure TCustomdxTreeListControl.WriteSettings(ARegIniWrapper: TdxRegIniWrapper; const APath: string); var APathCol: string; I: Integer; ABand: TdxTreeListBand; begin with ARegIniWrapper do begin WriteBool(APath, 'ShowGrid', ShowGrid); WriteBool(APath, 'ShowPreviewGrid', ShowPreviewGrid); WriteInteger(APath, 'BandRowCount', BandRowCount); WriteInteger(APath, 'DefaultRowHeight', DefaultRowHeight); if IsAutoHeaderPanelRowCount then WriteInteger(APath, 'HeaderPanelRowCount', -1) else WriteInteger(APath, 'HeaderPanelRowCount', HeaderPanelRowCount); // bands for I := 0 to Bands.Count - 1 do begin ABand := Bands[I]; APathCol := APath + '\Band\Band' + IntToStr(I); WriteInteger(APathCol, 'ID', ABand.ID); // Collection Item ID WriteBool(APathCol, 'Visible', ABand.Visible); WriteInteger(APathCol, 'Index', ABand.Index); WriteInteger(APathCol, 'Width', ABand.Width); end; end; end; procedure TCustomdxTreeListControl.GetChildren(Proc: TGetChildProc; Root: TComponent); var I: Integer; Column: TdxTreeListColumn; begin for I := 0 to FColumns.Count - 1 do begin Column := FColumns[I]; if (Column.Owner = Root) or IsCustomStoring then Proc(Column); end; end; procedure TCustomdxTreeListControl.SetChildOrder(Component: TComponent; Order: Integer); begin if FColumns.IndexOf(Component) >= 0 then (Component as TdxTreeListColumn).Index := Order; end; procedure TCustomdxTreeListControl.Loaded; begin inherited Loaded; RefreshRowIndexes; RefreshSortedList; // Load From Ini/Regsirty DoRestoreLayout; end; procedure TCustomdxTreeListControl.SetParent(AParent: TWinControl); begin inherited SetParent(AParent); if (AParent <> nil) and (GetParentForm(Self) <> nil) then FParentFormName := GetParentForm(Self).Name; end; function TCustomdxTreeListControl.AssignedDrawBandEvent(VisibleIndex: Integer): Boolean; begin Result := Assigned(FOnCustomDrawBand); end; function TCustomdxTreeListControl.AssignedDrawCellEvent(ANode: TdxTreeListNode; AbsoluteIndex: Integer): Boolean; begin Result := Assigned(FOnCustomDrawCell) or Assigned(FOnCustomDraw){obsolete} or Columns[AbsoluteIndex].AssignedDrawCellEvent; end; function TCustomdxTreeListControl.AssignedDrawFooterCellEvent(ANode: TdxTreeListNode; AbsoluteIndex, FooterIndex: Integer): Boolean; begin if FooterIndex <> -1 then Result := Assigned(FOnCustomDrawFooterNode) else Result := Assigned(FOnCustomDrawFooter); end; function TCustomdxTreeListControl.AssignedDrawHeaderEvent(AbsoluteIndex: Integer): Boolean; begin Result := Assigned(FOnCustomDrawColumnHeader) or Assigned(Columns[AbsoluteIndex].FOnCustomDrawColumnHeader); end; function TCustomdxTreeListControl.AssignedDrawPreviewEvent: Boolean; begin Result := Assigned(FOnCustomDrawPreviewCell) or Assigned(FOnCustomDrawPreview); end; function TCustomdxTreeListControl.AssignedLevelColorEvent: Boolean; begin Result := Assigned(OnGetLevelColor); end; procedure TCustomdxTreeListControl.DoDrawBand(VisibleIndex: Integer; ACanvas: TCanvas; ARect, AClipRect: TRect; var AText: string; var AColor: TColor; AFont: TFont; var AAlignment: TAlignment; var ADone: Boolean); begin if Assigned(FOnCustomDrawBand) then FOnCustomDrawBand(Self, Bands.VisibleItems[VisibleIndex], ACanvas, ARect, AText, AColor, AFont, AAlignment, ADone); end; procedure TCustomdxTreeListControl.DoDrawCell(ACanvas: TCanvas; var ARect: TRect; ANode: TdxTreeListNode; AIndex: Integer; ASelected, AFocused: Boolean; ANewItemRow: Boolean; ALeftEdge, ARightEdge: Boolean; ABrush: HBRUSH; var AText: string; var AColor: TColor; AFont: TFont; var AAlignment: TAlignment; var ADone: Boolean); var Column: TdxTreeListColumn; begin Column := Columns[AIndex]; // obsolete if Assigned(FOnCustomDraw) then FOnCustomDraw(Self, ACanvas, ARect, ANode, Column, AText, AFont, AColor, ASelected, AFocused, ADone); if not ADone then begin if Assigned(FOnCustomDrawCell) then FOnCustomDrawCell(Self, ACanvas, ARect, ANode, Column, ASelected, AFocused, ANewItemRow, AText, AColor, AFont, AAlignment, ADone); if not ADone and ((ANewItemRow and IsNewItemRowEditing) or (not ANewItemRow and not IsRowGroup(ANode))) then Column.DoDrawCell(ACanvas, ARect, ANode, ASelected, AFocused, ANewItemRow, ALeftEdge, ARightEdge, ABrush, AText, AColor, AFont, AAlignment, ADone); end; end; procedure TCustomdxTreeListControl.DoDrawFooterCell(ACanvas: TCanvas; ARect: TRect; ANode: TdxTreeListNode; AIndex, AFooterIndex: Integer; var AText: string; var AColor: TColor; AFont: TFont; var AAlignment: TAlignment; var ADone: Boolean); begin if AFooterIndex <> -1 then if Assigned(FOnCustomDrawFooterNode) then FOnCustomDrawFooterNode(Self, ACanvas, ARect, ANode, Columns[AIndex], AFooterIndex, AText, AColor, AFont, AAlignment, ADone) else else if Assigned(FOnCustomDrawFooter) then FOnCustomDrawFooter(Self, ACanvas, ARect, ANode, Columns[AIndex], AText, AColor, AFont, AAlignment, ADone); end; procedure TCustomdxTreeListControl.DoDrawHeader(AbsoluteIndex: Integer; ACanvas: TCanvas; ARect, AClipRect: TRect; var AText: string; var AColor: TColor; AFont: TFont; var AAlignment: TAlignment; var ASorted: TdxTreeListColumnSort; var ADone: Boolean); var Column: TdxTreeListColumn; begin Column := Columns[AbsoluteIndex]; if Assigned(FOnCustomDrawColumnHeader) then FOnCustomDrawColumnHeader(Self, Column, ACanvas, ARect, AText, AColor, AFont, AAlignment, ASorted, ADone); if not ADone and Assigned(Column.FOnCustomDrawColumnHeader) then Column.FOnCustomDrawColumnHeader(Self, Column, ACanvas, ARect, AText, AColor, AFont, AAlignment, ASorted, ADone); end; procedure TCustomdxTreeListControl.DoDrawPreview(ACanvas: TCanvas; ARect: TRect; ANode: TdxTreeListNode; ASelected: Boolean; var AText: string; var AColor, ATextColor: TColor; AFont: TFont; var ADone: Boolean); begin if Assigned(FOnCustomDrawPreview) then FOnCustomDrawPreview(Self, ACanvas, ARect, ANode, ASelected, AText, ADone); if not ADone and Assigned(FOnCustomDrawPreviewCell) then FOnCustomDrawPreviewCell(Self, ACanvas, ARect, ANode, ASelected, AText, AColor, ATextColor, AFont, ADone); end; procedure TCustomdxTreeListControl.DoGetLevelColor(ALevel: Integer; var AColor: TColor); begin if Assigned(FOnGetLevelColor) then FOnGetLevelColor(Self, ALevel, AColor); end; function TCustomdxTreeListControl.IsExistFooterCell(AbsoluteIndex: Integer): Boolean; begin Result := False; if Assigned(FOnIsExistFooterCell) then FOnIsExistFooterCell(Self, AbsoluteIndex, Result); end; // private TCustomdxTreeListControl procedure TCustomdxTreeListControl.AddColumn(Column: TdxTreeListColumn); begin FColumns.Add(Column); Column.FTreeList := Self; UpdateColumn(nil); end; function TCustomdxTreeListControl.GetColumn(Index: Integer): TdxTreeListColumn; begin Result := FColumns[Index]; end; function TCustomdxTreeListControl.GetColumnCount: Integer; begin Result := FColumns.Count; end; function TCustomdxTreeListControl.GetDefaultLayout: Boolean; begin Result := FDefaultLayout; end; function TCustomdxTreeListControl.GetSortedColumns(Index: Integer): TdxTreeListColumn; begin Result := FSortedColumns[Index]; end; function TCustomdxTreeListControl.GetVisibleColumn(Index: Integer): TdxTreeListColumn; var i: Integer; begin Result := nil; i := GetAbsoluteColumnIndex(Index); if i <> -1 then Result := Columns[i]; end; function TCustomdxTreeListControl.GetVisibleColumnCount: Integer; var i: Integer; begin Result := 0; for i := 0 to FColumns.Count - 1 do if TdxTreeListColumn(FColumns[i]).Visible then Inc(Result); end; function TCustomdxTreeListControl.IsHeaderPanelRowCountStored: Boolean; begin Result := not (aoAutoHeaderPanelHeight in OptionsEx); end; procedure TCustomdxTreeListControl.MakeDefaultLayout; var I: Integer; begin //if csLoading in ComponentState then Exit; BeginUpdate; try ShowBands := False; HeaderPanelRowCount := 1; while Bands.Count > 1 do Bands[Bands.Count - 1].Free; if Bands.Count = 0 then Bands.Add; Bands[0].Visible := True; for I := 0 to ColumnCount - 1 do Columns[I].BandIndex := 0; finally EndUpdate; end; end; procedure TCustomdxTreeListControl.SetBands(Value: TdxTreeListBands); begin Bands.Assign(Value); end; procedure TCustomdxTreeListControl.SetBandMaxRowCount(Value: Integer); begin if Value < 1 then Value := 1; FBandMaxRowCount := Value; SetBandRowCount(FBandRowCount); end; procedure TCustomdxTreeListControl.SetBandRowCount(Value: Integer); begin if Value < 1 then Value := 1; if Value > FBandMaxRowCount then Value := FBandMaxRowCount; if FBandRowCount <> Value then begin FBandRowCount := Value; UpdateBands; end; end; procedure TCustomdxTreeListControl.SetColumn(Index: Integer; Value: TdxTreeListColumn); begin TdxTreeListColumn(FColumns[Index]).Assign(Value); end; procedure TCustomdxTreeListControl.SetHeaderPanelMaxRowCount(Value: Integer); begin if Value < 1 then Value := 1; FHeaderPanelMaxRowCount := Value; SetHeaderPanelRowCount(FHeaderPanelRowCount); end; procedure TCustomdxTreeListControl.SetHeaderPanelRowCount(Value: Integer); begin if Value < 1 then Value := 1; if Value > FHeaderPanelMaxRowCount then Value := FHeaderPanelMaxRowCount; if FHeaderPanelRowCount <> Value then begin if not FSetAutoHeaderPanelRowCount then ResetAutoHeaderPanelRowCountOption; FHeaderPanelRowCount := Value; if FHeaderPanelRowCount > 1 then FDefaultLayout := False; RefreshRowIndexes; UpdateHeaders; end; end; procedure TCustomdxTreeListControl.SetHeaderRowCount(Value: Integer); begin if Value < 1 then Value := 1; if FHeaderMinRowCount <> Value then begin FHeaderMinRowCount := Value; UpdateHeaders; end; end; procedure TCustomdxTreeListControl.RefreshRowIndexes; procedure MakeBandRowList(AList: TList); var PIndexes: PIntArray; I, J, RCount, R: Integer; Column: TdxTreeListColumn; begin AList.Clear; RCount := HeaderPanelRowCount + 1; GetMem(PIndexes, RCount * SizeOf(Integer)); try for J := 0 to Bands.Count - 1 do begin FillChar(PIndexes^, RCount * SizeOf(Integer), 0); for I := 0 to ColumnCount - 1 do begin Column := Columns[I]; if Column.Visible and (Column.BandIndex = J) and (0 <= Column.RowIndex) and (Column.RowIndex < RCount) then PIndexes^[Column.RowIndex] := 1; end; R := 0; for I := 0 to RCount - 1 do if PIndexes^[I] = 1 then Inc(R); AList.Add(Pointer(R)); end; finally FreeMem(PIndexes); end; end; var I, J, K, RCount, BIndex: Integer; Found: Boolean; Column: TdxTreeListColumn; ABandRowList: TList; begin ClearListNodes; for I := 0 to ColumnCount - 1 do begin Column := Columns[I]; if Column.FRowIndex >= FHeaderPanelRowCount then Column.FRowIndex := FHeaderPanelRowCount - 1; if Column.FRowIndex < 0 then Column.FRowIndex := 0; end; // check empty row for K := 0 to Bands.VisibleCount - 1 do begin BIndex := Bands.VisibleItems[K].Index; RCount := GetHeaderRowCount(K); for J := RCount - 1 downto 0 do begin Found := False; for I := 0 to ColumnCount - 1 do begin Column := Columns[I]; if Column.Visible and (Column.BandIndex = BIndex) and (Column.RowIndex = J) then begin Found := True; Break; end; end; // if exist empty row -> move up if not Found then begin for I := 0 to ColumnCount - 1 do begin Column := Columns[I]; if Column.Visible and (Column.BandIndex = BIndex) and (Column.RowIndex > J) then begin Dec(Column.FRowIndex); Dec(Column.FStoredRowIndex); end; end; end; end; end; // check ranges ABandRowList := TList.Create; try // make Band Row List MakeBandRowList(ABandRowList); // check if ABandRowList.Count > 0 then for I := 0 to ColumnCount - 1 do begin Column := Columns[I]; BIndex := Column.BandIndex; if BIndex <> -1 then begin RCount := Integer(ABandRowList[BIndex]); if Column.FRowIndex >= RCount then begin Column.FRowIndex := RCount - 1; if Column.FRowIndex = -1 then Column.FRowIndex := 0; Column.FStoredRowIndex := Column.FRowIndex; //-2 TODO end; end; end; finally ABandRowList.Free; end; // calc best panel size if IsAutoHeaderPanelRowCount and not FSetAutoHeaderPanelRowCount then HeaderPanelBestFit; if LockUpdate = 0 then MakeListNodes; end; procedure TCustomdxTreeListControl.SetDefaultLayout(Value: Boolean); begin if FDefaultLayout <> Value then begin FDefaultLayout := Value; if FDefaultLayout then MakeDefaultLayout; end; end; procedure TCustomdxTreeListControl.SetVisibleColumn(Index: Integer; Value: TdxTreeListColumn); var i :Integer; begin i := GetAbsoluteColumnIndex(Index); if i <> -1 then Columns[i] := Value; end; procedure TCustomdxTreeListControl.CMCursorChanged(var Message: TMessage); begin inherited; if not FCursorChange then FDefaultCursor := Cursor; end; procedure TCustomdxTreeListControl.CMFontChanged(var Message: TMessage); var I: Integer; begin BeginUpdate; try for I := 0 to ColumnCount - 1 do Columns[I].RefreshDefaultFont; finally EndUpdate; end; end; {TdxTreeListDesigner} constructor TdxTreeListDesigner.Create(ATreeList: TCustomdxTreeListControl); begin FTreeList := ATreeList; FTreeList.FDesigner := Self; end; destructor TdxTreeListDesigner.Destroy; begin FTreeList.FDesigner := nil; inherited Destroy; end; procedure TdxTreeListDesigner.LayoutChanged; begin end; {TdxTreeList} constructor TdxTreeList.Create(AOwner : TComponent); begin inherited Create(AOwner); FSelectedNodes := TList.Create; end; destructor TdxTreeList.Destroy; begin ClearSelection; inherited Destroy; FSelectedNodes.Free; FSelectedNodes := nil; end; procedure TdxTreeList.AssignNodes(Source: TPersistent); var MemStream: TMemoryStream; ATreeList: TdxTreeList; begin if Source is TdxTreeList then begin ATreeList := TdxTreeList(Source); BeginUpdate; try ClearNodes; MemStream := TMemoryStream.Create; try ATreeList.WriteData(MemStream); MemStream.Position := 0; ReadData(MemStream); finally MemStream.Free; end; finally EndUpdate; end; end else inherited Assign(Source); end; procedure TdxTreeList.ClearColumnsSorted; var I: Integer; begin inherited ClearColumnsSorted; for I := 0 to ColumnCount - 1 do Columns[I].FSorted := csNone; end; procedure TdxTreeList.ClearSelection; begin if GetSelectedCount = 0 then Exit; if not (csDestroying in ComponentState) and not FClearNodes then InvalidateSelection; if FSelectedNodes <> nil then FSelectedNodes.Clear; inherited ClearSelection; end; procedure TdxTreeList.DeleteSelection; begin inherited DeleteSelection; BeginUpdate; try while SelectedCount > 0 do SelectedNodes[0].Free; FSelectedNodes.Clear; finally EndUpdate; end; end; procedure TdxTreeList.LoadFromFile(const FileName: string); var Stream: TStream; begin Stream := TFileStream.Create(FileName, fmOpenRead); try LoadFromStream(Stream); finally Stream.Free; end; end; procedure TdxTreeList.LoadFromStream(Stream: TStream); begin BeginUpdate; try ClearNodes; Self.ReadData(Stream); finally EndUpdate; end; end; procedure TdxTreeList.RefreshSorting; var Column: TdxTreeListColumn; begin if IsAutoSort then begin BeginUpdate; try Column := SortedColumn; if (Column <> nil) and (Column.Sorted <> csNone) then DoSortColumn(-1{all levels}, Column.Index, Column.Sorted = csDown); // if IsAutoSort and (SortedColumnCount > 0) then // DoSortColumn(-1{all levels}, SortedColumns[0].Index, SortedColumns[0].Sorted = csDown); finally EndUpdate; end; end; end; procedure TdxTreeList.SaveToFile(const FileName: string); var Stream: TStream; begin Stream := TFileStream.Create(FileName, fmCreate); try SaveToStream(Stream); finally Stream.Free; end; end; procedure TdxTreeList.SaveToStream(Stream: TStream); begin Self.WriteData(Stream); end; procedure TdxTreeList.SelectAll; var N1, N2: TdxTreeListNode; begin if not IsMultiSelect or (Count = 0) then Exit; BeginSelection; try BeginUpdate; try ClearSelection; if IsExtMultiSelect then begin FullExpand; {calc start Node} N1 := Items[0]; {calc end Node} N2 := Items[Count - 1]; while N2.Count > 0 do N2 := N2[N2.Count - 1]; end else begin if FocusedNode.Parent = nil then begin N1 := Items[0]; N2 := Items[Count - 1]; end else begin N1 := FocusedNode.Parent[0]; N2 := FocusedNode.Parent[FocusedNode.Parent.Count - 1]; end; end; SelectNodes(N1, N2); finally EndUpdate; end; finally EndSelection; end; end; //protected TdxTreeList procedure TdxTreeList.DefineProperties(Filer: TFiler); begin inherited DefineProperties(Filer); Filer.DefineBinaryProperty('Data', ReadData, WriteData, Count > 0); end; function TdxTreeList.GetRowIndicatorKind(Node: TdxTreeListNode; ASelected: Boolean): TdxGridIndicatorKind; begin Result := ikNone; if Node.Focused then begin if ASelected and IsMultiSelect then Result := ikMultiArrow else Result := ikArrow; end else if ASelected then Result := ikMultiDot; end; function TdxTreeList.GetPreviewText(Node: TdxTreeListNode): string; begin Result := inherited GetPreviewText(Node); if Assigned(FOnGetPreviewText) then FOnGetPreviewText(Self, Node, Result); end; function TdxTreeList.GetRowLineCount(Node: TdxTreeListNode; var LineHeight: Integer): Integer; begin Result := inherited GetRowLineCount(Node, LineHeight); if Assigned(FOnGetRowLineCount) then FOnGetRowLineCount(Self, Node, Result); end; function TdxTreeList.GetRowPreviewLineCount(Node: TdxTreeListNode): Integer; begin Result := inherited GetRowPreviewLineCount(Node); if Assigned(FOnGetPreviewLineCount) then FOnGetPreviewLineCount(Self, Node, Result); end; function TdxTreeList.GetFooterCellText(Node: TdxTreeListNode; AbsoluteIndex, FooterIndex: Integer): string; begin Result := ''; if Assigned(FOnGetFooterCellText) then FOnGetFooterCellText(Self, Node, AbsoluteIndex, FooterIndex, Result); end; function TdxTreeList.IsExistRowFooterCell(Node: TdxTreeListNode; AbsoluteIndex, FooterIndex: Integer): Boolean; begin Result := False; if Assigned(FOnIsExistRowFooterCell) then FOnIsExistRowFooterCell(Self, Node, AbsoluteIndex, FooterIndex, Result); end; function TdxTreeList.IsLevelFooter(Level: Integer): Boolean; begin Result := False; if Assigned(FOnIsLevelFooter) then FOnIsLevelFooter(Self, Level, Result); end; procedure TdxTreeList.AddNode(Node: TdxTreeListNode); begin inherited AddNode(Node); CheckRefreshSorting; end; procedure TdxTreeList.BeginCustomLayout; begin inherited BeginCustomLayout; HideEditor; if IsAutoSortRefresh and FNeededSortRefresh and not (csDestroying in ComponentState) then RefreshSorting; FNeededSortRefresh := False; end; procedure TdxTreeList.DeleteNode(Node, Prior, Next: TdxTreeListNode; IsLast, Redraw: Boolean); begin inherited DeleteNode(Node, Prior, Next, IsLast, Redraw); CheckRefreshSorting; end; function TdxTreeList.GetNodeVariant(Node: TdxTreeListNode; Column: Integer) : Variant; begin if not IsCaseInsensitive then Result := Node.Strings[Column] else Result := AnsiUpperCase(Node.Strings[Column]); end; procedure TdxTreeList.PrepareColumnSorted(Column: TdxTreeListColumn); begin if IsAutoSort and not (FlagMultiSort or LockSorting) then ClearColumnsSorted; end; procedure TdxTreeList.SetColumnSorted(Column: TdxTreeListColumn); begin if IsMultiSort and (SortedColumn <> nil) then; // check SortedColumns[] inherited SetColumnSorted(Column); if IsAutoSort and not LockSorting then DoSortColumn(-1{all levels}, Column.Index, Column.Sorted = csDown); end; procedure TdxTreeList.SetNodeString(Node : TdxTreeListNode; Column : Integer; const Value: string); begin inherited SetNodeString(Node, Column, Value); CheckRefreshSorting; end; function TdxTreeList.AssignEditValue(ANode: TdxTreeListNode; AColumn: Integer; AInplaceEdit: TdxInplaceEdit): Variant; var I: Integer; begin I := GetFocusedAbsoluteIndex(AColumn); if I <> -1 then begin with Columns[I] do begin Result := AssignEditValue(ANode, AInplaceEdit); ANode.Strings[Index] := GetDisplayText(ANode); end; if IsRowAutoHeight or (IsShowPreview and IsAutoCalcPreviewLines) then begin BeginUpdate; try UpdateNode(ANode, False{Below}); finally EndUpdate; end; end; if IsAutoSortRefresh and not (csDestroying in ComponentState) and (FLockUpdate = 0) then begin RefreshSorting; ANode.MakeVisible; end; end else Result := ''; inherited AssignEditValue(ANode, AColumn, AInplaceEdit); end; function TdxTreeList.GetSelectedCount : Integer; begin Result := FSelectedNodes.Count; end; function TdxTreeList.GetSelectedItem(AIndex : Integer) : TdxTreeListNode; begin if (AIndex >=0) and (AIndex < GetSelectedCount) then Result := FSelectedNodes[AIndex] else Result := nil; end; function TdxTreeList.IsNodeSelected(ANode: TdxTreeListNode): Boolean; var TempIndex: Integer; begin Result := FindSelectedNode(ANode, TempIndex); {Sorted List} end; procedure TdxTreeList.NodeSelected(ANode: TdxTreeListNode; ASelected: Boolean); var Index: Integer; begin if not IsMultiSelect then Exit; if ASelected then begin if not CanNodeSelected(ANode) then Exit; if not FindSelectedNode(ANode, Index) then FSelectedNodes.Insert(Index, ANode); end else if FindSelectedNode(ANode, Index) then FSelectedNodes.Delete(Index); UpdateNode(ANode, False {no Below}); inherited NodeSelected(ANode, ASelected); end; procedure TdxTreeList.SelectNodes(N1, N2: TdxTreeListNode); var I, J, C: Integer; FList: TList; Node: TdxTreeListNode; begin BeginSelection; try I := CompareByAbsoluteIndex(N1, N2); if I > 0 then begin Node := N1; N1 := N2; N2 := Node; end; BeginUpdate; try MakeListNodes; J := GetAbsoluteIndex(N1); C := GetAbsoluteIndex(N2); FList := TList.Create; try FList.Capacity := C - J + 1; for I := J to C do begin Node := GetAbsoluteNode(I); if FFirstSelectedNode = nil then FFirstSelectedNode := Node; if CanNodeSelected(Node) then FList.Add(Node); end; if FList.Count > 0 then begin FList.Sort(CompareNodes); // [FList] or [FSelectedNodes] J := 0; for I := 0 to FSelectedNodes.Count - 1 do begin if J = -1 then FList.Add(FSelectedNodes[I]) else repeat C := CompareNodes(FSelectedNodes[I], FList[J]); if C <= 0 then begin if C < 0 then begin FList.Insert(J, FSelectedNodes[I]); Inc(J); end; Break; end; {else C > 0} Inc(J); if J >= FList.Count then begin FList.Add(FSelectedNodes[I]); J := -1; Break; end; until False; end; end; // copy from temp list FSelectedNodes.Count := FList.Count; System.Move(FList.List^, FSelectedNodes.List^, FList.Count * SizeOf(Pointer)); finally FFirstSelectedNode := nil; FList.Free; end; finally EndUpdate; end; finally EndSelection; end; end; //private TdxTreeList procedure TdxTreeList.CheckRefreshSorting; begin if not FClearNodes and not (csDestroying in ComponentState) and IsAutoSortRefresh then if FLockUpdate = 0 then RefreshSorting else FNeededSortRefresh := True; end; function TdxTreeList.FindSelectedNode(Node: TdxTreeListNode; var Index: Integer): Boolean; var L, H, I, C: Integer; begin Result := False; L := 0; H := FSelectedNodes.Count - 1; while L <= H do begin I := (L + H) shr 1; // C := CompareNodes(FSelectedNodes[I], Node); C := Integer(FSelectedNodes[I]) - Integer(Node); if C < 0 then L := I + 1 else begin H := I - 1; if C = 0 then begin Result := True; L := I; end; end; end; Index := L; end; function TdxTreeList.GetSortedColumn: TdxTreeListColumn; var I: Integer; begin Result := nil; for I := 0 to ColumnCount - 1 do if Columns[I].Sorted <> csNone then begin Result := Columns[I]; Break; end; if IsMultiSort then begin if SortedColumnCount = 0 then AddSortedColumn(Result) else Result := SortedColumns[0]; end; end; procedure TdxTreeList.ReadData(Stream: TStream); var I, ItemCount: Integer; begin ClearNodes; Stream.ReadBuffer(ItemCount, SizeOf(ItemCount)); if ItemCount < 0 then // new format (version) begin FStreamVersion := ItemCount; Stream.ReadBuffer(ItemCount, SizeOf(ItemCount)); end else FStreamVersion := 0; for I := 0 to ItemCount - 1 do TdxTreeListTextNode(Add).ReadData(Stream); end; procedure TdxTreeList.WriteData(Stream: TStream); var I: Integer; begin // new format (version) I := -1; Stream.WriteBuffer(I, SizeOf(I)); // count I := Count; Stream.WriteBuffer(I, SizeOf(I)); for I := 0 to Count - 1 do TdxTreeListTextNode(Items[i]).WriteData(Stream); end; { TdxTreeListEditStyle } constructor TdxTreeListEditStyle.Create(AEdit: TdxInplaceEdit; ATreeList: TCustomdxTreeList); begin inherited Create(AEdit); FTreeList := ATreeList; end; function TdxTreeListEditStyle.DefaultBorderColor: TColor; begin Result := TreeList.EditStyleBorderColor; end; function TdxTreeListEditStyle.DefaultBorderStyle: TdxEditBorderStyle; begin Result := TreeList.EditStyleBorderStyle; end; function TdxTreeListEditStyle.DefaultButtonStyle: TdxEditButtonViewStyle; begin Result := TreeList.EditStyleButtonStyle; end; function TdxTreeListEditStyle.DefaultButtonTransparence: TdxEditButtonTransparence; begin Result := TreeList.EditStyleButtonTransparence; end; function TdxTreeListEditStyle.DefaultEdges: TdxEditEdges; begin Result := TreeList.EditStyleEdges; end; function TdxTreeListEditStyle.DefaultHotTrack: Boolean; begin Result := TreeList.EditStyleHotTrack; end; function TdxTreeListEditStyle.DefaultShadow: Boolean; begin Result := TreeList.EditStyleShadow; end; { TdxTreeListMaskColumn } procedure TdxTreeListMaskColumn.Assign(Source: TPersistent); begin if Source is TdxTreeListMaskColumn then begin if Assigned(TreeList) then TreeList.BeginUpdate; try inherited Assign(Source); EditMask := TdxTreeListMaskColumn(Source).EditMask; finally if Assigned(TreeList) then TreeList.EndUpdate; end; end else inherited Assign(Source); end; procedure TdxTreeListMaskColumn.RestoreDefaults; begin inherited RestoreDefaults; EditMask := ''; end; function TdxTreeListMaskColumn.GetdxInplaceEditClass: TdxInplaceEditClass; begin Result := TdxInplaceTreeListMaskEdit; end; procedure TdxTreeListMaskColumn.InitEditProperties(AInplaceEdit: TdxInplaceEdit); begin inherited InitEditProperties(AInplaceEdit); if AInplaceEdit is TdxInplaceMaskEdit then with TdxInplaceTreeListMaskEdit(AInplaceEdit) do begin EditMask := Self.EditMask; IgnoreMaskBlank := Self.IgnoreMaskBlank; end; end; var FAntiBugImageList: HImageList; initialization Classes.RegisterClasses([TdxTreeListColumn, TdxTreeListMaskColumn]); Screen.Cursors[crdxTreeListDeleteCursor] := LoadCursor(HInstance, dxTreeListDeleteCursor); Screen.Cursors[crdxTreeListFullScroll] := LoadCursor(HInstance, 'DXTL_FULLSCROLLCURSOR'); Screen.Cursors[crdxTreeListHorScroll] := LoadCursor(HInstance, 'DXTL_HORSCROLLCURSOR'); Screen.Cursors[crdxTreeListVerScroll] := LoadCursor(HInstance, 'DXTL_VERSCROLLCURSOR'); Screen.Cursors[crdxTreeListUpScroll] := LoadCursor(HInstance, 'DXTL_UPSCROLLCURSOR'); Screen.Cursors[crdxTreeListRightScroll] := LoadCursor(HInstance, 'DXTL_RIGHTSCROLLCURSOR'); Screen.Cursors[crdxTreeListDownScroll] := LoadCursor(HInstance, 'DXTL_DOWNSCROLLCURSOR'); Screen.Cursors[crdxTreeListLeftScroll] := LoadCursor(HInstance, 'DXTL_LEFTSCROLLCURSOR'); Screen.Cursors[crdxTreeListDragCopy] := LoadCursor(HInstance, 'DXTL_DRAGCOPY'); Screen.Cursors[crdxTreeListMultiDragCopy] := LoadCursor(HInstance, 'DXTL_MULTIDRAGCOPY'); ScrollTimerID := -1; ScrollNodeTimerID := -1; ClickTimerID := -1; CreateBitmaps; sdxGrColumns := LoadStr(dxSColumnsCaption); sdxGrBandsCaption := LoadStr(dxSBandsCaption); sdxGrHeadersCaption := LoadStr(dxSHeadersCaption); FAntiBugImageList := ImageList_Create(1, 1, ILC_COLOR, 1, 1); TempDC := GetDC(0); finalization ReleaseDC(0, TempDC); if FAntiBugImageList <> 0 then begin ImageList_Destroy(FAntiBugImageList); FAntiBugImageList := 0; end; DestroyBitmaps; {$IFDEF DELPHI4} DestroyCursor(Screen.Cursors[crdxTreeListDeleteCursor]); DestroyCursor(Screen.Cursors[crdxTreeListFullScroll]); DestroyCursor(Screen.Cursors[crdxTreeListHorScroll]); DestroyCursor(Screen.Cursors[crdxTreeListVerScroll]); DestroyCursor(Screen.Cursors[crdxTreeListUpScroll]); DestroyCursor(Screen.Cursors[crdxTreeListRightScroll]); DestroyCursor(Screen.Cursors[crdxTreeListDownScroll]); DestroyCursor(Screen.Cursors[crdxTreeListLeftScroll]); DestroyCursor(Screen.Cursors[crdxTreeListDragCopy]); DestroyCursor(Screen.Cursors[crdxTreeListMultiDragCopy]); {$ENDIF} end.