home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 1997 April
/
Chip_1997-04_cd.bin
/
prezent
/
cb
/
data.z
/
COMCTRLS.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1997-01-16
|
239KB
|
8,454 lines
{*******************************************************}
{ }
{ Delphi Visual Component Library }
{ }
{ Copyright (c) 1996-1997 Borland International }
{ }
{*******************************************************}
unit ComCtrls; // $Revision: 1.12 $
{$R-}
interface
uses Messages, Windows, SysUtils, CommCtrl, Classes, Controls, Forms,
Menus, Graphics, StdCtrls, RichEdit;
type
TTabChangingEvent = procedure(Sender: TObject;
var AllowChange: Boolean) of object;
TCustomTabControl = class(TWinControl)
private
FTabs: TStrings;
FSaveTabs: TStringList;
FSaveTabIndex: Integer;
FTabSize: TSmallPoint;
FMultiLine: Boolean;
FUpdating: Boolean;
FOnChange: TNotifyEvent;
FOnChanging: TTabChangingEvent;
function GetDisplayRect: TRect;
function GetTabIndex: Integer;
procedure SetMultiLine(Value: Boolean);
procedure SetTabHeight(Value: Smallint);
procedure SetTabIndex(Value: Integer);
procedure SetTabs(Value: TStrings);
procedure SetTabWidth(Value: Smallint);
procedure TabsChanged;
procedure UpdateTabSize;
procedure WMDestroy(var Message: TWMDestroy); message WM_DESTROY;
procedure CMTabStopChanged(var Message: TMessage); message CM_TABSTOPCHANGED;
procedure CNNotify(var Message: TWMNotify); message CN_NOTIFY;
protected
procedure AlignControls(AControl: TControl; var Rect: TRect); override;
function CanChange: Boolean; dynamic;
procedure Change; dynamic;
procedure CreateParams(var Params: TCreateParams); override;
procedure CreateWnd; override;
procedure DestroyWnd; override;
property DisplayRect: TRect read GetDisplayRect;
property MultiLine: Boolean read FMultiLine write SetMultiLine default False;
property TabHeight: Smallint read FTabSize.Y write SetTabHeight default 0;
property TabIndex: Integer read GetTabIndex write SetTabIndex default -1;
property Tabs: TStrings read FTabs write SetTabs;
property TabWidth: Smallint read FTabSize.X write SetTabWidth default 0;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
property OnChanging: TTabChangingEvent read FOnChanging write FOnChanging;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property TabStop default True;
end;
TTabControl = class(TCustomTabControl)
public
property DisplayRect;
published
property Align;
property DragCursor;
property DragMode;
property Enabled;
property Font;
property MultiLine;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property TabHeight;
property TabIndex;
property TabOrder;
property Tabs;
property TabStop;
property TabWidth;
property Visible;
property OnChange;
property OnChanging;
property OnDragDrop;
property OnDragOver;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnStartDrag;
end;
TPageControl = class;
TTabSheet = class(TWinControl)
private
FPageControl: TPageControl;
FTabVisible: Boolean;
FTabShowing: Boolean;
function GetPageIndex: Integer;
function GetTabIndex: Integer;
procedure SetPageControl(APageControl: TPageControl);
procedure SetPageIndex(Value: Integer);
procedure SetTabShowing(Value: Boolean);
procedure SetTabVisible(Value: Boolean);
procedure UpdateTabShowing;
procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
protected
procedure ReadState(Reader: TReader); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property PageControl: TPageControl read FPageControl write SetPageControl;
property TabIndex: Integer read GetTabIndex;
published
property Caption;
property Enabled;
property Font;
property Height stored False;
property Left stored False;
property PageIndex: Integer read GetPageIndex write SetPageIndex stored False;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property TabVisible: Boolean read FTabVisible write SetTabVisible default True;
property Top stored False;
property Visible stored False;
property Width stored False;
property OnDragDrop;
property OnDragOver;
property OnEnter;
property OnExit;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
end;
TPageControl = class(TCustomTabControl)
private
FPages: TList;
FActivePage: TTabSheet;
procedure ChangeActivePage(Page: TTabSheet);
procedure DeleteTab(Page: TTabSheet);
function GetPage(Index: Integer): TTabSheet;
function GetPageCount: Integer;
procedure InsertPage(Page: TTabSheet);
procedure InsertTab(Page: TTabSheet);
procedure MoveTab(CurIndex, NewIndex: Integer);
procedure RemovePage(Page: TTabSheet);
procedure SetActivePage(Page: TTabSheet);
procedure UpdateTab(Page: TTabSheet);
procedure UpdateActivePage;
procedure CMDesignHitTest(var Message: TCMDesignHitTest); message CM_DESIGNHITTEST;
procedure CMDialogKey(var Message: TCMDialogKey); message CM_DIALOGKEY;
protected
procedure Change; override;
procedure GetChildren(Proc: TGetChildProc); override;
procedure SetChildOrder(Child: TComponent; Order: Integer); override;
procedure ShowControl(AControl: TControl); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function FindNextPage(CurPage: TTabSheet;
GoForward, CheckTabVisible: Boolean): TTabSheet;
procedure SelectNextPage(GoForward: Boolean);
property PageCount: Integer read GetPageCount;
property Pages[Index: Integer]: TTabSheet read GetPage;
published
property ActivePage: TTabSheet read FActivePage write SetActivePage;
property Align;
property DragCursor;
property DragMode;
property Enabled;
property Font;
property MultiLine;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property TabHeight;
property TabOrder;
property TabStop;
property TabWidth;
property Visible;
property OnChange;
property OnChanging;
property OnDragDrop;
property OnDragOver;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnStartDrag;
end;
TStatusBar = class;
TStatusPanelStyle = (psText, psOwnerDraw);
TStatusPanelBevel = (pbNone, pbLowered, pbRaised);
TStatusPanel = class(TCollectionItem)
private
FText: string;
FWidth: Integer;
FAlignment: TAlignment;
FBevel: TStatusPanelBevel;
FStyle: TStatusPanelStyle;
procedure SetAlignment(Value: TAlignment);
procedure SetBevel(Value: TStatusPanelBevel);
procedure SetStyle(Value: TStatusPanelStyle);
procedure SetText(const Value: string);
procedure SetWidth(Value: Integer);
public
constructor Create(Collection: TCollection); override;
procedure Assign(Source: TPersistent); override;
published
property Alignment: TAlignment read FAlignment write SetAlignment default taLeftJustify;
property Bevel: TStatusPanelBevel read FBevel write SetBevel default pbLowered;
property Style: TStatusPanelStyle read FStyle write SetStyle default psText;
property Text: string read FText write SetText;
property Width: Integer read FWidth write SetWidth;
end;
TStatusPanels = class(TCollection)
private
FStatusBar: TStatusBar;
function GetItem(Index: Integer): TStatusPanel;
procedure SetItem(Index: Integer; Value: TStatusPanel);
protected
procedure Update(Item: TCollectionItem); override;
public
constructor Create(StatusBar: TStatusBar);
function Add: TStatusPanel;
property Items[Index: Integer]: TStatusPanel read GetItem write SetItem; default;
end;
TDrawPanelEvent = procedure(StatusBar: TStatusBar; Panel: TStatusPanel;
const Rect: TRect) of object;
TStatusBar = class(TWinControl)
private
FPanels: TStatusPanels;
FCanvas: TCanvas;
FSimpleText: string;
FSimplePanel: Boolean;
FSizeGrip: Boolean;
FOnDrawPanel: TDrawPanelEvent;
FOnResize: TNotifyEvent;
procedure SetPanels(Value: TStatusPanels);
procedure SetSimplePanel(Value: Boolean);
procedure SetSimpleText(const Value: string);
procedure SetSizeGrip(Value: Boolean);
procedure UpdatePanel(Index: Integer);
procedure UpdatePanels;
procedure CNDrawItem(var Message: TWMDrawItem); message CN_DRAWITEM;
procedure WMSize(var Message: TWMSize); message WM_SIZE;
protected
procedure CreateParams(var Params: TCreateParams); override;
procedure CreateWnd; override;
procedure DrawPanel(Panel: TStatusPanel; const Rect: TRect); dynamic;
procedure Resize; dynamic;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property Canvas: TCanvas read FCanvas;
published
property Align default alBottom;
property DragCursor;
property DragMode;
property Enabled;
property Font;
property Panels: TStatusPanels read FPanels write SetPanels;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property SimplePanel: Boolean read FSimplePanel write SetSimplePanel;
property SimpleText: string read FSimpleText write SetSimpleText;
property SizeGrip: Boolean read FSizeGrip write SetSizeGrip default True;
property Visible;
property OnClick;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnEndDrag;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnDrawPanel: TDrawPanelEvent read FOnDrawPanel write FOnDrawPanel;
property OnResize: TNotifyEvent read FOnResize write FOnResize;
property OnStartDrag;
end;
THeaderControl = class;
THeaderSectionStyle = (hsText, hsOwnerDraw);
THeaderSection = class(TCollectionItem)
private
FText: string;
FWidth: Integer;
FMinWidth: Integer;
FMaxWidth: Integer;
FAlignment: TAlignment;
FStyle: THeaderSectionStyle;
FAllowClick: Boolean;
function GetLeft: Integer;
function GetRight: Integer;
procedure SetAlignment(Value: TAlignment);
procedure SetMaxWidth(Value: Integer);
procedure SetMinWidth(Value: Integer);
procedure SetStyle(Value: THeaderSectionStyle);
procedure SetText(const Value: string);
procedure SetWidth(Value: Integer);
public
constructor Create(Collection: TCollection); override;
procedure Assign(Source: TPersistent); override;
property Left: Integer read GetLeft;
property Right: Integer read GetRight;
published
property Alignment: TAlignment read FAlignment write SetAlignment default taLeftJustify;
property AllowClick: Boolean read FAllowClick write FAllowClick default True;
property MaxWidth: Integer read FMaxWidth write SetMaxWidth default 10000;
property MinWidth: Integer read FMinWidth write SetMinWidth default 0;
property Style: THeaderSectionStyle read FStyle write SetStyle default hsText;
property Text: string read FText write SetText;
property Width: Integer read FWidth write SetWidth;
end;
THeaderSections = class(TCollection)
private
FHeaderControl: THeaderControl;
function GetItem(Index: Integer): THeaderSection;
procedure SetItem(Index: Integer; Value: THeaderSection);
protected
procedure Update(Item: TCollectionItem); override;
public
constructor Create(HeaderControl: THeaderControl);
function Add: THeaderSection;
property Items[Index: Integer]: THeaderSection read GetItem write SetItem; default;
end;
TSectionTrackState = (tsTrackBegin, tsTrackMove, tsTrackEnd);
TDrawSectionEvent = procedure(HeaderControl: THeaderControl;
Section: THeaderSection; const Rect: TRect; Pressed: Boolean) of object;
TSectionNotifyEvent = procedure(HeaderControl: THeaderControl;
Section: THeaderSection) of object;
TSectionTrackEvent = procedure(HeaderControl: THeaderControl;
Section: THeaderSection; Width: Integer;
State: TSectionTrackState) of object;
THeaderControl = class(TWinControl)
private
FSections: THeaderSections;
FCanvas: TCanvas;
FOnDrawSection: TDrawSectionEvent;
FOnResize: TNotifyEvent;
FOnSectionClick: TSectionNotifyEvent;
FOnSectionResize: TSectionNotifyEvent;
FOnSectionTrack: TSectionTrackEvent;
procedure SetSections(Value: THeaderSections);
procedure UpdateItem(Message, Index: Integer);
procedure UpdateSection(Index: Integer);
procedure UpdateSections;
procedure CNDrawItem(var Message: TWMDrawItem); message CN_DRAWITEM;
procedure CNNotify(var Message: TWMNotify); message CN_NOTIFY;
procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
procedure WMSize(var Message: TWMSize); message WM_SIZE;
protected
procedure CreateParams(var Params: TCreateParams); override;
procedure CreateWnd; override;
procedure DrawSection(Section: THeaderSection; const Rect: TRect;
Pressed: Boolean); dynamic;
procedure Resize; dynamic;
procedure SectionClick(Section: THeaderSection); dynamic;
procedure SectionResize(Section: THeaderSection); dynamic;
procedure SectionTrack(Section: THeaderSection; Width: Integer;
State: TSectionTrackState); dynamic;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property Canvas: TCanvas read FCanvas;
published
property Align default alTop;
property DragCursor;
property DragMode;
property Enabled;
property Font;
property Sections: THeaderSections read FSections write SetSections;
property ShowHint;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property Visible;
property OnDragDrop;
property OnDragOver;
property OnEndDrag;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnDrawSection: TDrawSectionEvent read FOnDrawSection write FOnDrawSection;
property OnResize: TNotifyEvent read FOnResize write FOnResize;
property OnSectionClick: TSectionNotifyEvent read FOnSectionClick write FOnSectionClick;
property OnSectionResize: TSectionNotifyEvent read FOnSectionResize write FOnSectionResize;
property OnSectionTrack: TSectionTrackEvent read FOnSectionTrack write FOnSectionTrack;
property OnStartDrag;
end;
{ TTreeNode }
TCustomTreeView = class;
TTreeNodes = class;
TNodeState = (nsCut, nsDropHilited, nsFocused, nsSelected, nsExpanded);
TNodeAttachMode = (naAdd, naAddFirst, naAddChild, naAddChildFirst, naInsert);
TAddMode = (taAddFirst, taAdd, taInsert);
PNodeInfo = ^TNodeInfo;
TNodeInfo = packed record
ImageIndex: Integer;
SelectedIndex: Integer;
StateIndex: Integer;
OverlayIndex: Integer;
Data: Pointer;
Count: Integer;
Text: string[255];
end;
TTreeNode = class(TPersistent)
private
FOwner: TTreeNodes;
FText: string;
FData: Pointer;
FItemId: HTreeItem;
FImageIndex: Integer;
FSelectedIndex: Integer;
FOverlayIndex: Integer;
FStateIndex: Integer;
FDeleting: Boolean;
procedure ExpandItem(Expand: Boolean; Recurse: Boolean);
function GetAbsoluteIndex: Integer;
function GetExpanded: Boolean;
function GetLevel: Integer;
function GetParent: TTreeNode;
function GetChildren: Boolean;
function GetCut: Boolean;
function GetDropTarget: Boolean;
function GetFocused: Boolean;
function GetIndex: Integer;
function GetItem(Index: Integer): TTreeNode;
function GetSelected: Boolean;
function GetState(NodeState: TNodeState): Boolean;
function GetCount: Integer;
function GetTreeView: TCustomTreeView;
function HasVisibleParent: Boolean;
procedure InternalMove(ParentNode, Node: TTreeNode; HItem: HTreeItem;
AddMode: TAddMode);
function IsEqual(Node: TTreeNode): Boolean;
function IsNodeVisible: Boolean;
procedure ReadData(Stream: TStream; Info: PNodeInfo);
procedure SetChildren(Value: Boolean);
procedure SetCut(Value: Boolean);
procedure SetData(Value: Pointer);
procedure SetDropTarget(Value: Boolean);
procedure SetItem(Index: Integer; Value: TTreeNode);
procedure SetExpanded(Value: Boolean);
procedure SetFocused(Value: Boolean);
procedure SetImageIndex(Value: Integer);
procedure SetOverlayIndex(Value: Integer);
procedure SetSelectedIndex(Value: Integer);
procedure SetSelected(Value: Boolean);
procedure SetStateIndex(Value: Integer);
procedure SetText(const S: string);
procedure WriteData(Stream: TStream; Info: PNodeInfo);
public
constructor Create(AOwner: TTreeNodes);
destructor Destroy; override;
function AlphaSort: Boolean;
procedure Assign(Source: TPersistent); override;
procedure Collapse(Recurse: Boolean);
function CustomSort(SortProc: TTVCompare; Data: Longint): Boolean;
procedure Delete;
procedure DeleteChildren;
function DisplayRect(TextOnly: Boolean): TRect;
function EditText: Boolean;
procedure EndEdit(Cancel: Boolean);
procedure Expand(Recurse: Boolean);
function getFirstChild: TTreeNode;
function GetHandle: HWND;
function GetLastChild: TTreeNode;
function GetNext: TTreeNode;
function GetNextChild(Value: TTreeNode): TTreeNode;
function getNextSibling: TTreeNode;
function GetNextVisible: TTreeNode;
function GetPrev: TTreeNode;
function GetPrevChild(Value: TTreeNode): TTreeNode;
function getPrevSibling: TTreeNode;
function GetPrevVisible: TTreeNode;
function HasAsParent(Value: TTreeNode): Boolean;
function IndexOf(Value: TTreeNode): Integer;
procedure MakeVisible;
procedure MoveTo(Destination: TTreeNode; Mode: TNodeAttachMode);
property AbsoluteIndex: Integer read GetAbsoluteIndex;
property Count: Integer read GetCount;
property Cut: Boolean read GetCut write SetCut;
property Data: Pointer read FData write SetData;
property Deleting: Boolean read FDeleting;
property Focused: Boolean read GetFocused write SetFocused;
property DropTarget: Boolean read GetDropTarget write SetDropTarget;
property Selected: Boolean read GetSelected write SetSelected;
property Expanded: Boolean read GetExpanded write SetExpanded;
property Handle: HWND read GetHandle;
property HasChildren: Boolean read GetChildren write SetChildren;
property ImageIndex: Integer read FImageIndex write SetImageIndex;
property Index: Integer read GetIndex;
property IsVisible: Boolean read IsNodeVisible;
property Item[Index: Integer]: TTreeNode read GetItem write SetItem; default;
property ItemId: HTreeItem read FItemId;
property Level: Integer read GetLevel;
property OverlayIndex: Integer read FOverlayIndex write SetOverlayIndex;
property Owner: TTreeNodes read FOwner;
property Parent: TTreeNode read GetParent;
property SelectedIndex: Integer read FSelectedIndex write SetSelectedIndex;
property StateIndex: Integer read FStateIndex write SetStateIndex;
property Text: string read FText write SetText;
property TreeView: TCustomTreeView read GetTreeView;
end;
{ TTreeNodes }
TTreeNodes = class(TPersistent)
private
FOwner: TCustomTreeView;
FUpdateCount: Integer;
procedure AddedNode(Value: TTreeNode);
function GetHandle: HWND;
function GetNodeFromIndex(Index: Integer): TTreeNode;
procedure ReadData(Stream: TStream);
procedure Repaint(Node: TTreeNode);
procedure WriteData(Stream: TStream);
protected
function AddItem(Parent, Target: HTreeItem; const Item: TTVItem;
AddMode: TAddMode): HTreeItem;
function InternalAddObject(Node: TTreeNode; const S: string;
Ptr: Pointer; AddMode: TAddMode): TTreeNode;
procedure DefineProperties(Filer: TFiler); override;
function CreateItem(Node: TTreeNode): TTVItem;
function GetCount: Integer;
procedure SetItem(Index: Integer; Value: TTreeNode);
procedure SetUpdateState(Updating: Boolean);
public
constructor Create(AOwner: TCustomTreeView);
destructor Destroy; override;
function AddChildFirst(Node: TTreeNode; const S: string): TTreeNode;
function AddChild(Node: TTreeNode; const S: string): TTreeNode;
function AddChildObjectFirst(Node: TTreeNode; const S: string;
Ptr: Pointer): TTreeNode;
function AddChildObject(Node: TTreeNode; const S: string;
Ptr: Pointer): TTreeNode;
function AddFirst(Node: TTreeNode; const S: string): TTreeNode;
function Add(Node: TTreeNode; const S: string): TTreeNode;
function AddObjectFirst(Node: TTreeNode; const S: string;
Ptr: Pointer): TTreeNode;
function AddObject(Node: TTreeNode; const S: string;
Ptr: Pointer): TTreeNode;
procedure Assign(Source: TPersistent); override;
procedure BeginUpdate;
procedure Clear;
procedure Delete(Node: TTreeNode);
procedure EndUpdate;
function GetFirstNode: TTreeNode;
function GetNode(ItemId: HTreeItem): TTreeNode;
function Insert(Node: TTreeNode; const S: string): TTreeNode;
function InsertObject(Node: TTreeNode; const S: string;
Ptr: Pointer): TTreeNode;
property Count: Integer read GetCount;
property Handle: HWND read GetHandle;
property Item[Index: Integer]: TTreeNode read GetNodeFromIndex; default;
property Owner: TCustomTreeView read FOwner;
end;
{ TCustomTreeView }
THitTest = (htAbove, htBelow, htNowhere, htOnItem, htOnButton,
htOnIcon, htOnIndent, htOnLabel, htOnRight,
htOnStateIcon, htToLeft, htToRight);
THitTests = set of THitTest;
ETreeViewError = class(Exception);
TTVChangingEvent = procedure(Sender: TObject; Node: TTreeNode;
var AllowChange: Boolean) of object;
TTVChangedEvent = procedure(Sender: TObject; Node: TTreeNode) of object;
TTVEditingEvent = procedure(Sender: TObject; Node: TTreeNode;
var AllowEdit: Boolean) of object;
TTVEditedEvent = procedure(Sender: TObject; Node: TTreeNode; var S: string) of object;
TTVExpandingEvent = procedure(Sender: TObject; Node: TTreeNode;
var AllowExpansion: Boolean) of object;
TTVCollapsingEvent = procedure(Sender: TObject; Node: TTreeNode;
var AllowCollapse: Boolean) of object;
TTVExpandedEvent = procedure(Sender: TObject; Node: TTreeNode) of object;
TTVCompareEvent = procedure(Sender: TObject; Node1, Node2: TTreeNode;
Data: Integer; var Compare: Integer) of object;
TSortType = (stNone, stData, stText, stBoth);
TCustomTreeView = class(TWinControl)
private
FShowLines: Boolean;
FShowRoot: Boolean;
FShowButtons: Boolean;
FBorderStyle: TBorderStyle;
FReadOnly: Boolean;
FImages: TImageList;
FStateImages: TImageList;
FImageChangeLink: TChangeLink;
FStateChangeLink: TChangeLink;
FDragImage: TImageList;
FTreeNodes: TTreeNodes;
FSortType: TSortType;
FSaveItems: TStringList;
FSaveTopIndex: Integer;
FSaveIndex: Integer;
FSaveIndent: Integer;
FHideSelection: Boolean;
FMemStream: TMemoryStream;
FEditInstance: Pointer;
FDefEditProc: Pointer;
FEditHandle: HWND;
FDragged: Boolean;
FRClicked: Boolean;
FLastDropTarget: TTreeNode;
FDragNode: TTreeNode;
FOnEditing: TTVEditingEvent;
FOnEdited: TTVEditedEvent;
FOnExpanded: TTVExpandedEvent;
FOnExpanding: TTVExpandingEvent;
FOnCollapsed: TTVExpandedEvent;
FOnCollapsing: TTVCollapsingEvent;
FOnChanging: TTVChangingEvent;
FOnChange: TTVChangedEvent;
FOnCompare: TTVCompareEvent;
FOnDeletion: TTVExpandedEvent;
FOnGetImageIndex: TTVExpandedEvent;
FOnGetSelectedIndex: TTVExpandedEvent;
procedure CMColorChanged(var Message: TMessage); message CM_COLORCHANGED;
procedure CMCtl3DChanged(var Message: TMessage); message CM_CTL3DCHANGED;
procedure CMDrag(var Message: TCMDrag); message CM_DRAG;
procedure CNNotify(var Message: TWMNotify); message CN_NOTIFY;
procedure EditWndProc(var Message: TMessage);
procedure DoDragOver(Source: TDragObject; X, Y: Integer);
procedure GetImageIndex(Node: TTreeNode);
procedure GetSelectedIndex(Node: TTreeNode);
function GetDropTarget: TTreeNode;
function GetIndent: Integer;
function GetNodeFromItem(const Item: TTVItem): TTreeNode;
function GetSelection: TTreeNode;
function GetTopItem: TTreeNode;
procedure ImageListChange(Sender: TObject);
procedure SetBorderStyle(Value: TBorderStyle);
procedure SetButtonStyle(Value: Boolean);
procedure SetDropTarget(Value: TTreeNode);
procedure SetHideSelection(Value: Boolean);
procedure SetImageList(Value: HImageList; Flags: Integer);
procedure SetIndent(Value: Integer);
procedure SetImages(Value: TImageList);
procedure SetLineStyle(Value: Boolean);
procedure SetReadOnly(Value: Boolean);
procedure SetRootStyle(Value: Boolean);
procedure SetSelection(Value: TTreeNode);
procedure SetSortType(Value: TSortType);
procedure SetStateImages(Value: TImageList);
procedure SetStyle(Value: Integer; UseStyle: Boolean);
procedure SetTreeNodes(Value: TTreeNodes);
procedure SetTopItem(Value: TTreeNode);
procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
procedure WMRButtonDown(var Message: TWMRButtonDown); message WM_RBUTTONDOWN;
protected
function CanEdit(Node: TTreeNode): Boolean; dynamic;
function CanChange(Node: TTreeNode): Boolean; dynamic;
function CanCollapse(Node: TTreeNode): Boolean; dynamic;
function CanExpand(Node: TTreeNode): Boolean; dynamic;
procedure Change(Node: TTreeNode); dynamic;
procedure Collapse(Node: TTreeNode); dynamic;
function CreateNode: TTreeNode; virtual;
procedure CreateParams(var Params: TCreateParams); override;
procedure CreateWnd; override;
procedure DestroyWnd; override;
procedure DoEndDrag(Target: TObject; X, Y: Integer); dynamic;
procedure DoStartDrag(var DragObject: TDragObject); override;
procedure Edit(const Item: TTVItem); dynamic;
procedure Expand(Node: TTreeNode); dynamic;
function GetDragImages: TCustomImageList; override;
procedure Loaded; override;
procedure Notification(AComponent: TComponent;
Operation: TOperation); override;
procedure SetDragMode(Value: TDragMode); override;
procedure WndProc(var Message: TMessage); override;
property OnEditing: TTVEditingEvent read FOnEditing write FOnEditing;
property OnEdited: TTVEditedEvent read FOnEdited write FOnEdited;
property OnExpanding: TTVExpandingEvent read FOnExpanding write FOnExpanding;
property OnExpanded: TTVExpandedEvent read FOnExpanded write FOnExpanded;
property OnCollapsing: TTVCollapsingEvent read FOnCollapsing write FOnCollapsing;
property OnCollapsed: TTVExpandedEvent read FOnCollapsed write FOnCollapsed;
property OnChanging: TTVChangingEvent read FOnChanging write FOnChanging;
property OnChange: TTVChangedEvent read FOnChange write FOnChange;
property OnCompare: TTVCompareEvent read FOnCompare write FOnCompare;
property OnDeletion: TTVExpandedEvent read FOnDeletion write FOnDeletion;
property OnGetImageIndex: TTVExpandedEvent read FOnGetImageIndex write FOnGetImageIndex;
property OnGetSelectedIndex: TTVExpandedEvent read FOnGetSelectedIndex write FOnGetSelectedIndex;
property ShowButtons: Boolean read FShowButtons write SetButtonStyle default True;
property BorderStyle: TBorderStyle read FBorderStyle write SetBorderStyle default bsSingle;
property ShowLines: Boolean read FShowLines write SetLineStyle default True;
property ShowRoot: Boolean read FShowRoot write SetRootStyle default True;
property ReadOnly: Boolean read FReadOnly write SetReadOnly default False;
property Indent: Integer read GetIndent write SetIndent;
property Items: TTreeNodes read FTreeNodes write SetTreeNodes;
property SortType: TSortType read FSortType write SetSortType default stNone;
property HideSelection: Boolean read FHideSelection write SetHideSelection default True;
property Images: TImageList read FImages write SetImages;
property StateImages: TImageList read FStateImages write SetStateImages;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function AlphaSort: Boolean;
function CustomSort(SortProc: TTVCompare; Data: Longint): Boolean;
procedure FullCollapse;
procedure FullExpand;
function GetHitTestInfoAt(X, Y: Integer): THitTests;
function GetNodeAt(X, Y: Integer): TTreeNode;
function IsEditing: Boolean;
procedure LoadFromFile(const FileName: string);
procedure LoadFromStream(Stream: TStream);
procedure SaveToFile(const FileName: string);
procedure SaveToStream(Stream: TStream);
property DropTarget: TTreeNode read GetDropTarget write SetDropTarget;
property Selected: TTreeNode read GetSelection write SetSelection;
property TopItem: TTreeNode read GetTopItem write SetTopItem;
end;
TTreeView = class(TCustomTreeView)
published
property ShowButtons;
property BorderStyle;
property DragCursor;
property ShowLines;
property ShowRoot;
property ReadOnly;
property DragMode;
property HideSelection;
property Indent;
property Items;
property OnEditing;
property OnEdited;
property OnExpanding;
property OnExpanded;
property OnCollapsing;
property OnCompare;
property OnCollapsed;
property OnChanging;
property OnChange;
property OnDeletion;
property OnGetImageIndex;
property OnGetSelectedIndex;
property Align;
property Enabled;
property Font;
property Color;
property ParentColor;
property ParentCtl3D;
property Ctl3D;
property SortType;
property TabOrder;
property TabStop default True;
property Visible;
property OnClick;
property OnEnter;
property OnExit;
property OnDragDrop;
property OnDragOver;
property OnStartDrag;
property OnEndDrag;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnDblClick;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property PopupMenu;
property ParentFont;
property ParentShowHint;
property ShowHint;
property Images;
property StateImages;
end;
{ TTrackBar }
TTrackBarOrientation = (trHorizontal, trVertical);
TTickMark = (tmBottomRight, tmTopLeft, tmBoth);
TTickStyle = (tsNone, tsAuto, tsManual);
TTrackBar = class(TWinControl)
private
FOrientation: TTrackBarOrientation;
FTickMarks: TTickMark;
FTickStyle: TTickStyle;
FLineSize: Integer;
FPageSize: Integer;
FMin: Integer;
FMax: Integer;
FFrequency: Integer;
FPosition: Integer;
FSelStart: Integer;
FSelEnd: Integer;
FOnChange: TNotifyEvent;
procedure SetOrientation(Value: TTrackBarOrientation);
procedure SetParams(APosition, AMin, AMax: Integer);
procedure SetPosition(Value: Integer);
procedure SetMin(Value: Integer);
procedure SetMax(Value: Integer);
procedure SetFrequency(Value: Integer);
procedure SetTickStyle(Value: TTickStyle);
procedure SetTickMarks(Value: TTickMark);
procedure SetLineSize(Value: Integer);
procedure SetPageSize(Value: Integer);
procedure SetSelStart(Value: Integer);
procedure SetSelEnd(Value: Integer);
procedure UpdateSelection;
procedure CNHScroll(var Message: TWMHScroll); message CN_HSCROLL;
procedure CNVScroll(var Message: TWMVScroll); message CN_VSCROLL;
protected
procedure CreateParams(var Params: TCreateParams); override;
procedure CreateWnd; override;
procedure DestroyWnd; override;
public
constructor Create(AOwner: TComponent); override;
procedure SetTick(Value: Integer);
published
property Ctl3D;
property DragCursor;
property DragMode;
property Enabled;
property LineSize: Integer read FLineSize write SetLineSize default 1;
property Max: Integer read FMax write SetMax default 10;
property Min: Integer read FMin write SetMin default 0;
property Orientation: TTrackBarOrientation read FOrientation write SetOrientation;
property ParentCtl3D;
property ParentShowHint;
property PageSize: Integer read FPageSize write SetPageSize default 2;
property PopupMenu;
property Frequency: Integer read FFrequency write SetFrequency;
property Position: Integer read FPosition write SetPosition;
property SelEnd: Integer read FSelEnd write SetSelEnd;
property SelStart: Integer read FSelStart write SetSelStart;
property ShowHint;
property TabOrder;
property TabStop default True;
property TickMarks: TTickMark read FTickMarks write SetTickMarks;
property TickStyle: TTickStyle read FTickStyle write SetTickStyle;
property Visible;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
property OnDragDrop;
property OnDragOver;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnStartDrag;
end;
{ TProgressBar }
TProgressRange = 0..65535; // max & position limitation of Progess Bar
TProgressBar = class(TWinControl)
private
FMin: TProgressRange;
FMax: TProgressRange;
FStep: TProgressRange;
FPosition: TProgressRange;
function GetPosition: TProgressRange;
procedure SetParams(AMin, AMax: TProgressRange);
procedure SetMin(Value: TProgressRange);
procedure SetMax(Value: TProgressRange);
procedure SetPosition(Value: TProgressRange);
procedure SetStep(Value: TProgressRange);
protected
procedure CreateParams(var Params: TCreateParams); override;
procedure CreateWnd; override;
public
constructor Create(AOwner: TComponent); override;
procedure StepIt;
procedure StepBy(Delta: TProgressRange);
published
property Align;
property Enabled;
property Hint;
property Min: TProgressRange read FMin write SetMin;
property Max: TProgressRange read FMax write SetMax;
property ParentShowHint;
property PopupMenu;
property Position: TProgressRange read GetPosition write SetPosition default 0;
property Step: TProgressRange read FStep write SetStep default 10;
property ShowHint;
property TabOrder;
property TabStop;
property Visible;
property OnDragDrop;
property OnDragOver;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnStartDrag;
end;
{ TTextAttributes }
TCustomRichEdit = class;
TAttributeType = (atSelected, atDefaultText);
TConsistentAttribute = (caBold, caColor, caFace, caItalic,
caSize, caStrikeOut, caUnderline, caProtected);
TConsistentAttributes = set of TConsistentAttribute;
TTextAttributes = class(TPersistent)
private
RichEdit: TCustomRichEdit;
FType: TAttributeType;
procedure GetAttributes(var Format: TCharFormat);
function GetColor: TColor;
function GetConsistentAttributes: TConsistentAttributes;
function GetHeight: Integer;
function GetName: TFontName;
function GetPitch: TFontPitch;
function GetProtected: Boolean;
function GetSize: Integer;
function GetStyle: TFontStyles;
procedure SetAttributes(var Format: TCharFormat);
procedure SetColor(Value: TColor);
procedure SetHeight(Value: Integer);
procedure SetName(Value: TFontName);
procedure SetPitch(Value: TFontPitch);
procedure SetProtected(Value: Boolean);
procedure SetSize(Value: Integer);
procedure SetStyle(Value: TFontStyles);
protected
procedure InitFormat(var Format: TCharFormat);
procedure AssignTo(Dest: TPersistent); override;
public
constructor Create(AOwner: TCustomRichEdit; AttributeType: TAttributeType);
procedure Assign(Source: TPersistent); override;
property Color: TColor read GetColor write SetColor;
property ConsistentAttributes: TConsistentAttributes read GetConsistentAttributes;
property Name: TFontName read GetName write SetName;
property Pitch: TFontPitch read GetPitch write SetPitch;
property Protected: Boolean read GetProtected write SetProtected;
property Size: Integer read GetSize write SetSize;
property Style: TFontStyles read GetStyle write SetStyle;
property Height: Integer read GetHeight write SetHeight;
end;
{ TParaAttributes }
TNumberingStyle = (nsNone, nsBullet);
TParaAttributes = class(TPersistent)
private
RichEdit: TCustomRichEdit;
procedure GetAttributes(var Paragraph: TParaFormat);
function GetAlignment: TAlignment;
function GetFirstIndent: Longint;
function GetLeftIndent: Longint;
function GetRightIndent: Longint;
function GetNumbering: TNumberingStyle;
function GetTab(Index: Byte): Longint;
function GetTabCount: Integer;
procedure InitPara(var Paragraph: TParaFormat);
procedure SetAlignment(Value: TAlignment);
procedure SetAttributes(var Paragraph: TParaFormat);
procedure SetFirstIndent(Value: Longint);
procedure SetLeftIndent(Value: Longint);
procedure SetRightIndent(Value: Longint);
procedure SetNumbering(Value: TNumberingStyle);
procedure SetTab(Index: Byte; Value: Longint);
procedure SetTabCount(Value: Integer);
public
constructor Create(AOwner: TCustomRichEdit);
procedure Assign(Source: TPersistent); override;
property Alignment: TAlignment read GetAlignment write SetAlignment;
property FirstIndent: Longint read GetFirstIndent write SetFirstIndent;
property LeftIndent: Longint read GetLeftIndent write SetLeftIndent;
property Numbering: TNumberingStyle read GetNumbering write SetNumbering;
property RightIndent: Longint read GetRightIndent write SetRightIndent;
property Tab[Index: Byte]: Longint read GetTab write SetTab;
property TabCount: Integer read GetTabCount write SetTabCount;
end;
{ TCustomRichEdit }
TRichEditResizeEvent = procedure(Sender: TObject; Rect: TRect) of object;
TRichEditProtectChange = procedure(Sender: TObject;
StartPos, EndPos: Integer; var AllowChange: Boolean) of object;
TRichEditSaveClipboard = procedure(Sender: TObject;
NumObjects, NumChars: Integer; var SaveClipboard: Boolean) of object;
TSearchType = (stWholeWord, stMatchCase);
TSearchTypes = set of TSearchType;
TConversion = class(TObject)
public
function ConvertReadStream(Stream: TStream; Buffer: PChar; BufSize: Integer): Integer; virtual;
function ConvertWriteStream(Stream: TStream; Buffer: PChar; BufSize: Integer): Integer; virtual;
end;
TConversionClass = class of TConversion;
PConversionFormat = ^TConversionFormat;
TConversionFormat = record
ConversionClass: TConversionClass;
Extension: string;
Next: PConversionFormat;
end;
PRichEditStreamInfo = ^TRichEditStreamInfo;
TRichEditStreamInfo = record
Converter: TConversion;
Stream: TStream;
end;
TCustomRichEdit = class(TCustomMemo)
private
FLibHandle: THandle;
FHideScrollBars: Boolean;
FSelAttributes: TTextAttributes;
FDefAttributes: TTextAttributes;
FParagraph: TParaAttributes;
FScreenLogPixels: Integer;
FRichEditStrings: TStrings;
FMemStream: TMemoryStream;
FOnSelChange: TNotifyEvent;
FHideSelection: Boolean;
FModified: Boolean;
FDefaultConverter: TConversionClass;
FOnResizeRequest: TRichEditResizeEvent;
FOnProtectChange: TRichEditProtectChange;
FOnSaveClipboard: TRichEditSaveClipboard;
FPageRect: TRect;
procedure CMColorChanged(var Message: TMessage); message CM_COLORCHANGED;
procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
procedure CNNotify(var Message: TWMNotify); message CN_NOTIFY;
function GetPlainText: Boolean;
function ProtectChange(StartPos, EndPos: Integer): Boolean;
function SaveClipboard(NumObj, NumChars: Integer): Boolean;
procedure SetHideScrollBars(Value: Boolean);
procedure SetHideSelection(Value: Boolean);
procedure SetPlainText(Value: Boolean);
procedure SetRichEditStrings(Value: TStrings);
procedure SetDefAttributes(Value: TTextAttributes);
procedure SetSelAttributes(Value: TTextAttributes);
procedure WMNCDestroy(var Message: TWMNCDestroy); message WM_NCDESTROY;
procedure WMSetCursor(var Message: TWMSetCursor); message WM_SETCURSOR;
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
procedure WMSetFont(var Message: TWMSetFont); message WM_SETFONT;
protected
procedure CreateParams(var Params: TCreateParams); override;
procedure CreateWnd; override;
procedure DestroyWnd; override;
procedure RequestSize(const Rect: TRect); virtual;
procedure SelectionChange; dynamic;
property HideSelection: Boolean read FHideSelection write SetHideSelection default True;
property HideScrollBars: Boolean read FHideScrollBars
write SetHideScrollBars default True;
property Lines: TStrings read FRichEditStrings write SetRichEditStrings;
property OnSaveClipboard: TRichEditSaveClipboard read FOnSaveClipboard
write FOnSaveClipboard;
property OnSelectionChange: TNotifyEvent read FOnSelChange write FOnSelChange;
property OnProtectChange: TRichEditProtectChange read FOnProtectChange
write FOnProtectChange;
property OnResizeRequest: TRichEditResizeEvent read FOnResizeRequest
write FOnResizeRequest;
property PlainText: Boolean read GetPlainText write SetPlainText default False;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function FindText(const SearchStr: string;
StartPos, Length: Integer; Options: TSearchTypes): Integer;
procedure Print(const Caption: string);
class procedure RegisterConversionFormat(const AExtension: string;
AConversionClass: TConversionClass);
property DefaultConverter: TConversionClass
read FDefaultConverter write FDefaultConverter;
property DefAttributes: TTextAttributes read FDefAttributes write SetDefAttributes;
property SelAttributes: TTextAttributes read FSelAttributes write SetSelAttributes;
property PageRect: TRect read FPageRect write FPageRect;
property Paragraph: TParaAttributes read FParagraph;
end;
TRichEdit = class(TCustomRichEdit)
published
property Align;
property Alignment;
property BorderStyle;
property Color;
property Ctl3D;
property DragMode;
property Enabled;
property Font;
property HideSelection;
property HideScrollBars;
property ImeMode;
property ImeName;
property Lines;
property MaxLength;
property ParentColor;
property ParentCtl3D;
property ParentFont;
property PlainText;
property PopupMenu;
property ReadOnly;
property ScrollBars;
property ShowHint;
property TabOrder;
property TabStop default True;
property Visible;
property WantTabs;
property WantReturns;
property WordWrap;
property OnChange;
property OnDragDrop;
property OnDragOver;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnResizeRequest;
property OnSelectionChange;
property OnStartDrag;
property OnProtectChange;
property OnSaveClipboard;
end;
{ TUpDown }
TUDAlignButton = (udLeft, udRight);
TUDOrientation = (udHorizontal, udVertical);
TUDBtnType = (btNext, btPrev);
TUDClickEvent = procedure (Sender: TObject; Button: TUDBtnType) of object;
TUDChangingEvent = procedure (Sender: TObject; var AllowChange: Boolean) of object;
TCustomUpDown = class(TWinControl)
private
FArrowKeys: Boolean;
FAssociate: TWinControl;
FMin: SmallInt;
FMax: SmallInt;
FIncrement: Integer;
FPosition: SmallInt;
FThousands: Boolean;
FWrap: Boolean;
FOnClick: TUDClickEvent;
FAlignButton: TUDAlignButton;
FOrientation: TUDOrientation;
FOnChanging: TUDChangingEvent;
procedure UndoAutoResizing(Value: TWinControl);
procedure SetAssociate(Value: TWinControl);
function GetPosition: SmallInt;
procedure SetMin(Value: SmallInt);
procedure SetMax(Value: SmallInt);
procedure SetIncrement(Value: Integer);
procedure SetPosition(Value: SmallInt);
procedure SetAlignButton(Value: TUDAlignButton);
procedure SetOrientation(Value: TUDOrientation);
procedure SetArrowKeys(Value: Boolean);
procedure SetThousands(Value: Boolean);
procedure SetWrap(Value: Boolean);
procedure CNNotify(var Message: TWMNotify); message CN_NOTIFY;
procedure WMHScroll(var Message: TWMHScroll); message CN_HSCROLL;
procedure WMVScroll(var Message: TWMVScroll); message CN_VSCROLL;
protected
function CanChange: Boolean;
procedure CreateParams(var Params: TCreateParams); override;
procedure CreateWnd; override;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
procedure Click(Button: TUDBtnType); dynamic;
property AlignButton: TUDAlignButton read FAlignButton write SetAlignButton default udRight;
property ArrowKeys: Boolean read FArrowKeys write SetArrowKeys default True;
property Associate: TWinControl read FAssociate write SetAssociate;
property Min: SmallInt read FMin write SetMin;
property Max: SmallInt read FMax write SetMax default 100;
property Increment: Integer read FIncrement write SetIncrement default 1;
property Orientation: TUDOrientation read FOrientation write SetOrientation default udVertical;
property Position: SmallInt read GetPosition write SetPosition;
property Thousands: Boolean read FThousands write SetThousands default True;
property Wrap: Boolean read FWrap write SetWrap;
property OnChanging: TUDChangingEvent read FOnChanging write FOnChanging;
property OnClick: TUDClickEvent read FOnClick write FOnClick;
public
constructor Create(AOwner: TComponent); override;
end;
TUpDown = class(TCustomUpDown)
published
property AlignButton;
property Associate;
property ArrowKeys;
property Enabled;
property Hint;
property Min;
property Max;
property Increment;
property Orientation;
property ParentShowHint;
property PopupMenu;
property Position;
property ShowHint;
property TabOrder;
property TabStop;
property Thousands;
property Visible;
property Wrap;
property OnChanging;
property OnClick;
property OnEnter;
property OnExit;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
end;
{ THotKey }
THKModifier = (hkShift, hkCtrl, hkAlt, hkExt);
THKModifiers = set of THKModifier;
THKInvalidKey = (hcNone, hcShift, hcCtrl, hcAlt, hcShiftCtrl,
hcShiftAlt, hcCtrlAlt, hcShiftCtrlAlt);
THKInvalidKeys = set of THKInvalidKey;
TCustomHotKey = class(TWinControl)
private
FAutoSize: Boolean;
FModifiers: THKModifiers;
FInvalidKeys: THKInvalidKeys;
FHotKey: Word;
FShiftState: TShiftState;
procedure AdjustHeight;
procedure SetAutoSize(Value: Boolean);
procedure SetInvalidKeys(Value: THKInvalidKeys);
procedure SetModifiers(Value: THKModifiers);
procedure UpdateHeight;
function GetHotKey: TShortCut;
procedure SetHotKey(Value: TShortCut);
procedure ShortCutToHotKey(Value: TShortCut);
function HotKeyToShortCut(Value: Longint): TShortCut;
protected
procedure CreateParams(var Params: TCreateParams); override;
procedure CreateWnd; override;
property AutoSize: Boolean read FAutoSize write SetAutoSize default True;
property InvalidKeys: THKInvalidKeys read FInvalidKeys write SetInvalidKeys;
property Modifiers: THKModifiers read FModifiers write SetModifiers;
property HotKey: TShortCut read GetHotKey write SetHotKey;
property TabStop default True;
public
constructor Create(AOwner: TComponent); override;
end;
THotKey = class(TCustomHotKey)
published
property AutoSize;
property Enabled;
property Hint;
property HotKey;
property InvalidKeys;
property Modifiers;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property TabOrder;
property TabStop;
property Visible;
property OnEnter;
property OnExit;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
end;
const
ColumnHeaderWidth = LVSCW_AUTOSIZE_USEHEADER;
ColumnTextWidth = LVSCW_AUTOSIZE;
type
TListColumns = class;
TListItems = class;
TCustomListView = class;
TWidth = ColumnHeaderWidth..MaxInt;
TListColumn = class(TCollectionItem)
private
FCaption: string;
FAlignment: TAlignment;
FWidth: TWidth;
procedure DoChange;
function GetWidth: TWidth;
procedure ReadData(Reader: TReader);
procedure SetAlignment(Value: TAlignment);
procedure SetCaption(const Value: string);
procedure SetWidth(Value: TWidth);
procedure WriteData(Writer: TWriter);
protected
procedure DefineProperties(Filer: TFiler); override;
public
constructor Create(Collection: TCollection); override;
destructor Destroy; override;
procedure Assign(Source: TPersistent); override;
property WidthType: TWidth read FWidth;
published
property Alignment: TAlignment read FAlignment write SetAlignment default taLeftJustify;
property Caption: string read FCaption write SetCaption;
property Width: TWidth read GetWidth write SetWidth default 50;
end;
TListColumns = class(TCollection)
private
FOwner: TCustomListView;
function GetItem(Index: Integer): TListColumn;
procedure SetItem(Index: Integer; Value: TListColumn);
protected
procedure Update(Item: TCollectionItem); override;
public
constructor Create(AOwner: TCustomListView);
function Add: TListColumn;
property Owner: TCustomListView read FOwner;
property Items[Index: Integer]: TListColumn read GetItem write SetItem; default;
end;
TDisplayCode = (drBounds, drIcon, drLabel, drSelectBounds);
{ TListItem }
TListItem = class(TPersistent)
private
FOwner: TListItems;
FSubItems: TStrings;
FData: Pointer;
FImageIndex: Integer;
FOverlayIndex: Integer;
FStateIndex: Integer;
FCaption: string;
FDeleting: Boolean;
FProcessedDeleting: Boolean;
function GetHandle: HWND;
function GetIndex: Integer;
function GetListView: TCustomListView;
function GetLeft: Integer;
function GetState(Index: Integer): Boolean;
function GetTop: Integer;
function IsEqual(Item: TListItem): Boolean;
procedure SetCaption(const Value: string);
procedure SetData(Value: Pointer);
procedure SetImage(Index: Integer; Value: Integer);
procedure SetLeft(Value: Integer);
procedure SetState(Index: Integer; State: Boolean);
procedure SetSubItems(Value: TStrings);
procedure SetTop(Value: Integer);
protected
procedure Assign(Source: TPersistent); override;
public
constructor Create(AOwner: TListItems);
destructor Destroy; override;
procedure CancelEdit;
procedure Delete;
function DisplayRect(Code: TDisplayCode): TRect;
function EditCaption: Boolean;
function GetPosition: TPoint;
procedure MakeVisible(PartialOK: Boolean);
procedure Update;
procedure SetPosition(const Value: TPoint);
property Caption: string read FCaption write SetCaption;
property Cut: Boolean index 0 read GetState write SetState;
property Data: Pointer read FData write SetData;
property DropTarget: Boolean index 1 read GetState write SetState;
property Focused: Boolean index 2 read GetState write SetState;
property Handle: HWND read GetHandle;
property ImageIndex: Integer index 0 read FImageIndex write SetImage;
property Index: Integer read GetIndex;
property Left: Integer read GetLeft write SetLeft;
property ListView: TCustomListView read GetListView;
property Owner: TListItems read FOwner;
property OverlayIndex: Integer index 1 read FOverlayIndex write SetImage;
property Selected: Boolean index 3 read GetState write SetState;
property StateIndex: Integer index 2 read FStateIndex write SetImage;
property SubItems: TStrings read FSubItems write SetSubItems;
property Top: Integer read GetTop write SetTop;
end;
{ TListItems }
TListItems = class(TPersistent)
private
FOwner: TCustomListView;
FUpdateCount: Integer;
FNoRedraw: Boolean;
procedure ReadData(Stream: TStream);
procedure WriteData(Stream: TStream);
protected
procedure DefineProperties(Filer: TFiler); override;
function CreateItem(Index: Integer; ListItem: TListItem): TLVItem;
function GetCount: Integer;
function GetHandle: HWND;
function GetItem(Index: Integer): TListItem;
procedure SetItem(Index: Integer; Value: TListItem);
procedure SetUpdateState(Updating: Boolean);
public
constructor Create(AOwner: TCustomListView);
destructor Destroy; override;
function Add: TListItem;
procedure Assign(Source: TPersistent); override;
procedure BeginUpdate;
procedure Clear;
procedure Delete(Index: Integer);
procedure EndUpdate;
function IndexOf(Value: TListItem): Integer;
function Insert(Index: Integer): TListItem;
property Count: Integer read GetCount;
property Handle: HWND read GetHandle;
property Item[Index: Integer]: TListItem read GetItem write SetItem; default;
property Owner: TCustomListView read FOwner;
end;
{ TIconOptions }
TIconArrangement = (iaTop, iaLeft);
TIconOptions = class(TPersistent)
private
FListView: TCustomListView;
FArrangement: TIconArrangement;
FAutoArrange: Boolean;
FWrapText: Boolean;
procedure SetArrangement(Value: TIconArrangement);
procedure SetAutoArrange(Value: Boolean);
procedure SetWrapText(Value: Boolean);
public
constructor Create(AOwner: TCustomListView);
published
property Arrangement: TIconArrangement read FArrangement write SetArrangement default iaTop;
property AutoArrange: Boolean read FAutoArrange write SetAutoArrange default False;
property WrapText: Boolean read FWrapText write SetWrapText default True;
end;
TListArrangement = (arAlignBottom, arAlignLeft, arAlignRight,
arAlignTop, arDefault, arSnapToGrid);
TViewStyle = (vsIcon, vsSmallIcon, vsList, vsReport);
TItemState = (isNone, isCut, isDropHilited, isFocused, isSelected);
TItemStates = set of TItemState;
TItemChange = (ctText, ctImage, ctState);
TLVDeletedEvent = procedure(Sender: TObject; Item: TListItem) of object;
TLVEditingEvent = procedure(Sender: TObject; Item: TListItem;
var AllowEdit: Boolean) of object;
TLVEditedEvent = procedure(Sender: TObject; Item: TListItem; var S: string) of object;
TLVChangeEvent = procedure(Sender: TObject; Item: TListItem;
Change: TItemChange) of object;
TLVChangingEvent = procedure(Sender: TObject; Item: TListItem;
Change: TItemChange; var AllowChange: Boolean) of object;
TLVColumnClickEvent = procedure(Sender: TObject; Column: TListColumn) of object;
TLVCompareEvent = procedure(Sender: TObject; Item1, Item2: TListItem;
Data: Integer; var Compare: Integer) of object;
TSearchDirection = (sdLeft, sdRight, sdAbove, sdBelow, sdAll);
{ TCustomListView }
TCustomListView = class(TWinControl)
private
FBorderStyle: TBorderStyle;
FViewStyle: TViewStyle;
FReadOnly: Boolean;
FLargeImages: TImageList;
FSmallImages: TImageList;
FStateImages: TImageList;
FDragImage: TImageList;
FShareImages: Boolean;
FMultiSelect: Boolean;
FSortType: TSortType;
FColumnClick: Boolean;
FShowColumnHeaders: Boolean;
FListItems: TListItems;
FClicked: Boolean;
FRClicked: Boolean;
FIconOptions: TIconOptions;
FHideSelection: Boolean;
FListColumns: TListColumns;
FMemStream: TMemoryStream;
FEditInstance: Pointer;
FDefEditProc: Pointer;
FEditHandle: HWND;
FHeaderInstance: Pointer;
FDefHeaderProc: Pointer;
FHeaderHandle: HWND;
FAllocBy: Integer;
FDragIndex: Integer;
FLastDropTarget: TListItem;
FLargeChangeLink: TChangeLink;
FSmallChangeLink: TChangeLink;
FStateChangeLink: TChangeLink;
FOnChange: TLVChangeEvent;
FOnChanging: TLVChangingEvent;
FOnColumnClick: TLVColumnClickEvent;
FOnDeletion: TLVDeletedEvent;
FOnEditing: TLVEditingEvent;
FOnEdited: TLVEditedEvent;
FOnInsert: TLVDeletedEvent;
FOnCompare: TLVCompareEvent;
procedure CMColorChanged(var Message: TMessage); message CM_COLORCHANGED;
procedure CMCtl3DChanged(var Message: TMessage); message CM_CTL3DCHANGED;
procedure CMDrag(var Message: TCMDrag); message CM_DRAG;
procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
procedure CNNotify(var Message: TWMNotify); message CN_NOTIFY;
procedure DoDragOver(Source: TDragObject; X, Y: Integer);
procedure EditWndProc(var Message: TMessage);
function GetBoundingRect: TRect;
function GetColumnFromIndex(Index: Integer): TListColumn;
function GetDropTarget: TListItem;
function GetFocused: TListItem;
function GetItem(Value: TLVItem): TListItem;
function GetSelCount: Integer;
function GetSelection: TListItem;
function GetTopItem: TListItem;
function GetViewOrigin: TPoint;
function GetVisibleRowCount: Integer;
procedure HeaderWndProc(var Message: TMessage);
procedure ImageListChange(Sender: TObject);
procedure InsertItem(Item: TListItem); dynamic;
procedure SetBorderStyle(Value: TBorderStyle);
procedure SetColumnClick(Value: Boolean);
procedure SetColumnHeaders(Value: Boolean);
procedure SetDropTarget(Value: TListItem);
procedure SetFocused(Value: TListItem);
procedure SetHideSelection(Value: Boolean);
procedure SetIconArrangement(Value: TIconArrangement);
procedure SetIconOptions(Value: TIconOptions);
procedure SetImageList(Value: HImageList; Flags: Integer);
procedure SetLargeImages(Value: TImageList);
procedure SetAllocBy(Value: Integer);
procedure SetItems(Value: TListItems);
procedure SetListColumns(Value: TListColumns);
procedure SetMultiSelect(Value: Boolean);
procedure SetReadOnly(Value: Boolean);
procedure SetSmallImages(Value: TImageList);
procedure SetSortType(Value: TSortType);
procedure SetSelection(Value: TListItem);
procedure SetStateImages(Value: TImageList);
procedure SetTextBkColor(Value: TColor);
procedure SetTextColor(Value: TColor);
procedure SetViewStyle(Value: TViewStyle);
function ValidHeaderHandle: Boolean;
procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
procedure WMNotify(var Message: TWMNotify); message WM_NOTIFY;
procedure WMParentNotify(var Message: TWMParentNotify); message WM_PARENTNOTIFY;
procedure WMRButtonDown(var Message: TWMRButtonDown); message WM_RBUTTONDOWN;
protected
function CanChange(Item: TListItem; Change: Integer): Boolean; dynamic;
function CanEdit(Item: TListItem): Boolean; dynamic;
procedure Change(Item: TListItem; Change: Integer); dynamic;
procedure ColClick(Column: TListColumn); dynamic;
function ColumnsShowing: Boolean;
function CreateListItem: TListItem; virtual;
procedure CreateParams(var Params: TCreateParams); override;
procedure CreateWnd; override;
procedure Delete(Item: TListItem); dynamic;
procedure DestroyWnd; override;
procedure DoEndDrag(Target: TObject; X, Y: Integer); dynamic;
procedure DoStartDrag(var DragObject: TDragObject); override;
procedure Edit(const Item: TLVItem); dynamic;
function GetDragImages: TCustomImageList; override;
function GetItemIndex(Value: TListItem): Integer;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
procedure UpdateColumn(Index: Integer);
procedure UpdateColumns;
procedure WndProc(var Message: TMessage); override;
property BorderStyle: TBorderStyle read FBorderStyle write SetBorderStyle default bsSingle;
property Columns: TListColumns read FListColumns write SetListColumns;
property ColumnClick: Boolean read FColumnClick write SetColumnClick default True;
property ReadOnly: Boolean read FReadOnly write SetReadOnly;
property HideSelection: Boolean read FHideSelection write SetHideSelection default True;
property IconOptions: TIconOptions read FIconOptions write SetIconOptions;
property Items: TListItems read FListItems write SetItems;
property AllocBy: Integer read FAllocBy write SetAllocBy default 0;
property LargeImages: TImageList read FLargeImages write SetLargeImages;
property MultiSelect: Boolean read FMultiSelect write SetMultiSelect default False;
property OnChange: TLVChangeEvent read FOnChange write FOnChange;
property OnChanging: TLVChangingEvent read FOnChanging write FOnChanging;
property OnColumnClick: TLVColumnClickEvent read FOnColumnClick
write FOnColumnClick;
property OnCompare: TLVCompareEvent read FOnCompare write FOnCompare;
property OnDeletion: TLVDeletedEvent read FOnDeletion write FOnDeletion;
property OnEdited: TLVEditedEvent read FOnEdited write FOnEdited;
property OnEditing: TLVEditingEvent read FOnEditing write FOnEditing;
property OnInsert: TLVDeletedEvent read FOnInsert write FOnInsert;
property ShowColumnHeaders: Boolean read FShowColumnHeaders write
SetColumnHeaders default True;
property SmallImages: TImageList read FSmallImages write SetSmallImages;
property SortType: TSortType read FSortType write SetSortType default stNone;
property StateImages: TImageList read FStateImages write SetStateImages;
property ViewStyle: TViewStyle read FViewStyle write SetViewStyle default vsIcon;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function AlphaSort: Boolean;
procedure Arrange(Code: TListArrangement);
function FindCaption(StartIndex: Integer; Value: string;
Partial, Inclusive, Wrap: Boolean): TListItem;
function FindData(StartIndex: Integer; Value: Pointer;
Inclusive, Wrap: Boolean): TListItem;
function GetItemAt(X, Y: Integer): TListItem;
function GetNearestItem(Point: TPoint;
Direction: TSearchDirection): TListItem;
function GetNextItem(StartItem: TListItem;
Direction: TSearchDirection; States: TItemStates): TListItem;
function GetSearchString: string;
function IsEditing: Boolean;
procedure Scroll(DX, DY: Integer);
property Column[Index: Integer]: TListColumn read GetColumnFromIndex;
property DropTarget: TListItem read GetDropTarget write SetDropTarget;
property ItemFocused: TListItem read GetFocused write SetFocused;
property SelCount: Integer read GetSelCount;
property Selected: TListItem read GetSelection write SetSelection;
function CustomSort(SortProc: TLVCompare; lParam: Longint): Boolean;
function StringWidth(S: string): Integer;
procedure UpdateItems(FirstIndex, LastIndex: Integer);
property TopItem: TListItem read GetTopItem;
property ViewOrigin: TPoint read GetViewOrigin;
property VisibleRowCount: Integer read GetVisibleRowCount;
property BoundingRect: TRect read GetBoundingRect;
end;
{ TListView }
TListView = class(TCustomListView)
published
property Align;
property BorderStyle;
property Color;
property ColumnClick;
property OnClick;
property OnDblClick;
property Columns;
property Ctl3D;
property DragMode;
property ReadOnly;
property Font;
property HideSelection;
property IconOptions;
property Items;
property AllocBy;
property MultiSelect;
property OnChange;
property OnChanging;
property OnColumnClick;
property OnCompare;
property OnDeletion;
property OnEdited;
property OnEditing;
property OnEnter;
property OnExit;
property OnInsert;
property OnDragDrop;
property OnDragOver;
property DragCursor;
property OnStartDrag;
property OnEndDrag;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property ParentShowHint;
property ShowHint;
property PopupMenu;
property ShowColumnHeaders;
property SortType;
property TabOrder;
property TabStop default True;
property ViewStyle;
property Visible;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property LargeImages;
property SmallImages;
property StateImages;
end;
implementation
uses Printers, Consts, ComStrs;
const
SectionSizeArea = 8;
RTFConversionFormat: TConversionFormat = (
ConversionClass: TConversion;
Extension: 'rtf';
Next: nil);
TextConversionFormat: TConversionFormat = (
ConversionClass: TConversion;
Extension: 'txt';
Next: @RTFConversionFormat);
var
ConversionFormatList: PConversionFormat = @TextConversionFormat;
{ TTabStrings }
type
TTabStrings = class(TStrings)
private
FTabControl: TCustomTabControl;
protected
function Get(Index: Integer): string; override;
function GetCount: Integer; override;
function GetObject(Index: Integer): TObject; override;
procedure Put(Index: Integer; const S: string); override;
procedure PutObject(Index: Integer; AObject: TObject); override;
procedure SetUpdateState(Updating: Boolean); override;
public
procedure Clear; override;
procedure Delete(Index: Integer); override;
procedure Insert(Index: Integer; const S: string); override;
end;
procedure TabControlError;
begin
raise EListError.CreateRes(sTabAccessError);
end;
procedure TTabStrings.Clear;
begin
if SendMessage(FTabControl.Handle, TCM_DELETEALLITEMS, 0, 0) = 0 then
TabControlError;
FTabControl.TabsChanged;
end;
procedure TTabStrings.Delete(Index: Integer);
begin
if SendMessage(FTabControl.Handle, TCM_DELETEITEM, Index, 0) = 0 then
TabControlError;
FTabControl.TabsChanged;
end;
function TTabStrings.Get(Index: Integer): string;
var
TCItem: TTCItem;
Buffer: array[0..4095] of Char;
begin
TCItem.mask := TCIF_TEXT;
TCItem.pszText := Buffer;
TCItem.cchTextMax := SizeOf(Buffer);
if SendMessage(FTabControl.Handle, TCM_GETITEM, Index,
Longint(@TCItem)) = 0 then TabControlError;
Result := Buffer;
end;
function TTabStrings.GetCount: Integer;
begin
Result := SendMessage(FTabControl.Handle, TCM_GETITEMCOUNT, 0, 0);
end;
function TTabStrings.GetObject(Index: Integer): TObject;
var
TCItem: TTCItem;
begin
TCItem.mask := TCIF_PARAM;
if SendMessage(FTabControl.Handle, TCM_GETITEM, Index,
Longint(@TCItem)) = 0 then TabControlError;
Result := TObject(TCItem.lParam);
end;
procedure TTabStrings.Put(Index: Integer; const S: string);
var
TCItem: TTCItem;
begin
TCItem.mask := TCIF_TEXT;
TCItem.pszText := PChar(S);
if SendMessage(FTabControl.Handle, TCM_SETITEM, Index,
Longint(@TCItem)) = 0 then TabControlError;
FTabControl.TabsChanged;
end;
procedure TTabStrings.PutObject(Index: Integer; AObject: TObject);
var
TCItem: TTCItem;
begin
TCItem.mask := TCIF_PARAM;
TCItem.lParam := Longint(AObject);
if SendMessage(FTabControl.Handle, TCM_SETITEM, Index,
Longint(@TCItem)) = 0 then TabControlError;
end;
procedure TTabStrings.Insert(Index: Integer; const S: string);
var
TCItem: TTCItem;
begin
TCItem.mask := TCIF_TEXT;
TCItem.pszText := PChar(S);
if SendMessage(FTabControl.Handle, TCM_INSERTITEM, Index,
Longint(@TCItem)) < 0 then TabControlError;
FTabControl.TabsChanged;
end;
procedure TTabStrings.SetUpdateState(Updating: Boolean);
begin
FTabControl.FUpdating := Updating;
SendMessage(FTabControl.Handle, WM_SETREDRAW, Ord(not Updating), 0);
if not Updating then
begin
FTabControl.Invalidate;
FTabControl.TabsChanged;
end;
end;
{ TCustomTabControl }
constructor TCustomTabControl.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Width := 289;
Height := 193;
TabStop := True;
ControlStyle := [csAcceptsControls, csDoubleClicks];
FTabs := TTabStrings.Create;
TTabStrings(FTabs).FTabControl := Self;
end;
destructor TCustomTabControl.Destroy;
begin
FTabs.Free;
FSaveTabs.Free;
inherited Destroy;
end;
function TCustomTabControl.CanChange: Boolean;
begin
Result := True;
if Assigned(FOnChanging) then FOnChanging(Self, Result);
end;
procedure TCustomTabControl.Change;
begin
if Assigned(FOnChange) then FOnChange(Self);
end;
procedure TCustomTabControl.CreateParams(var Params: TCreateParams);
begin
InitCommonControls;
inherited CreateParams(Params);
CreateSubClass(Params, WC_TABCONTROL);
with Params do
begin
Style := Style or WS_CLIPCHILDREN;
if not TabStop then Style := Style or TCS_FOCUSNEVER;
if FMultiLine then Style := Style or TCS_MULTILINE;
if FTabSize.X <> 0 then Style := Style or TCS_FIXEDWIDTH;
WindowClass.style := WindowClass.style or CS_DBLCLKS;
end;
end;
procedure TCustomTabControl.CreateWnd;
begin
inherited CreateWnd;
if Integer(FTabSize) <> 0 then UpdateTabSize;
if FSaveTabs <> nil then
begin
FTabs.Assign(FSaveTabs);
SetTabIndex(FSaveTabIndex);
FSaveTabs.Free;
FSaveTabs := nil;
end;
end;
procedure TCustomTabControl.DestroyWnd;
begin
if FTabs.Count > 0 then
begin
FSaveTabs := TStringList.Create;
FSaveTabs.Assign(FTabs);
FSaveTabIndex := GetTabIndex;
end;
inherited DestroyWnd;
end;
procedure TCustomTabControl.AlignControls(AControl: TControl;
var Rect: TRect);
begin
Rect := DisplayRect;
inherited AlignControls(AControl, Rect);
end;
function TCustomTabControl.GetDisplayRect: TRect;
begin
Result := ClientRect;
SendMessage(Handle, TCM_ADJUSTRECT, 0, Integer(@Result));
Inc(Result.Top, 2);
end;
function TCustomTabControl.GetTabIndex: Integer;
begin
Result := SendMessage(Handle, TCM_GETCURSEL, 0, 0);
end;
procedure TCustomTabControl.SetMultiLine(Value: Boolean);
begin
if FMultiLine <> Value then
begin
FMultiLine := Value;
RecreateWnd;
end;
end;
procedure TCustomTabControl.SetTabHeight(Value: Smallint);
begin
if FTabSize.Y <> Value then
begin
if Value < 0 then
raise EInvalidOperation.CreateResFmt(SPropertyOutOfRange, [Self.Classname]);
FTabSize.Y := Value;
UpdateTabSize;
end;
end;
procedure TCustomTabControl.SetTabIndex(Value: Integer);
begin
SendMessage(Handle, TCM_SETCURSEL, Value, 0);
end;
procedure TCustomTabControl.SetTabs(Value: TStrings);
begin
FTabs.Assign(Value);
end;
procedure TCustomTabControl.SetTabWidth(Value: Smallint);
var
OldValue: Smallint;
begin
if FTabSize.X <> Value then
begin
if Value < 0 then
raise EInvalidOperation.CreateResFmt(SPropertyOutOfRange, [Self.Classname]);
OldValue := FTabSize.X;
FTabSize.X := Value;
if (OldValue = 0) or (Value = 0) then
RecreateWnd else
UpdateTabSize;
end;
end;
procedure TCustomTabControl.TabsChanged;
begin
if not FUpdating then
begin
if HandleAllocated then
SendMessage(Handle, WM_SIZE, SIZE_RESTORED,
Word(Width) or Word(Height) shl 16);
Realign;
end;
end;
procedure TCustomTabControl.UpdateTabSize;
begin
SendMessage(Handle, TCM_SETITEMSIZE, 0, Integer(FTabSize));
TabsChanged;
end;
procedure TCustomTabControl.WMDestroy(var Message: TWMDestroy);
var
FocusHandle: HWnd;
begin
FocusHandle := GetFocus;
if (FocusHandle <> 0) and ((FocusHandle = Handle) or
IsChild(Handle, FocusHandle)) then
Windows.SetFocus(0);
inherited;
end;
procedure TCustomTabControl.CMTabStopChanged(var Message: TMessage);
begin
if not (csDesigning in ComponentState) then RecreateWnd;
end;
procedure TCustomTabControl.CNNotify(var Message: TWMNotify);
begin
with Message.NMHdr^ do
case code of
TCN_SELCHANGE:
Change;
TCN_SELCHANGING:
begin
Message.Result := 1;
if CanChange then Message.Result := 0;
end;
end;
end;
{ TTabSheet }
constructor TTabSheet.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Align := alClient;
ControlStyle := ControlStyle + [csAcceptsControls, csNoDesignVisible];
Visible := False;
FTabVisible := True;
end;
destructor TTabSheet.Destroy;
begin
if FPageControl <> nil then FPageControl.RemovePage(Self);
inherited Destroy;
end;
function TTabSheet.GetPageIndex: Integer;
begin
if FPageControl <> nil then
Result := FPageControl.FPages.IndexOf(Self) else
Result := -1;
end;
function TTabSheet.GetTabIndex: Integer;
var
I: Integer;
begin
Result := 0;
if not FTabShowing then Dec(Result) else
for I := 0 to PageIndex - 1 do
if TTabSheet(FPageControl.FPages[I]).FTabShowing then
Inc(Result);
end;
procedure TTabSheet.ReadState(Reader: TReader);
begin
inherited ReadState(Reader);
if Reader.Parent is TPageControl then
PageControl := TPageControl(Reader.Parent);
end;
procedure TTabSheet.SetPageControl(APageControl: TPageControl);
begin
if FPageControl <> APageControl then
begin
if FPageControl <> nil then FPageControl.RemovePage(Self);
Parent := APageControl;
if APageControl <> nil then APageControl.InsertPage(Self);
end;
end;
procedure TTabSheet.SetPageIndex(Value: Integer);
var
I: Integer;
begin
if FPageControl <> nil then
begin
I := TabIndex;
FPageControl.FPages.Move(PageIndex, Value);
if I >= 0 then FPageControl.MoveTab(I, TabIndex);
end;
end;
procedure TTabSheet.SetTabShowing(Value: Boolean);
begin
if FTabShowing <> Value then
if Value then
begin
FTabShowing := True;
FPageControl.InsertTab(Self);
end else
begin
FPageControl.DeleteTab(Self);
FTabShowing := False;
end;
end;
procedure TTabSheet.SetTabVisible(Value: Boolean);
begin
if FTabVisible <> Value then
begin
FTabVisible := Value;
UpdateTabShowing;
end;
end;
procedure TTabSheet.UpdateTabShowing;
begin
SetTabShowing((FPageControl <> nil) and FTabVisible);
end;
procedure TTabSheet.CMTextChanged(var Message: TMessage);
begin
if FTabShowing then FPageControl.UpdateTab(Self);
end;
{ TPageControl }
constructor TPageControl.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
ControlStyle := [csDoubleClicks];
FPages := TList.Create;
end;
destructor TPageControl.Destroy;
var
I: Integer;
begin
for I := 0 to FPages.Count - 1 do TTabSheet(FPages[I]).FPageControl := nil;
FPages.Free;
inherited Destroy;
end;
procedure TPageControl.Change;
var
Form: TForm;
begin
UpdateActivePage;
if csDesigning in ComponentState then
begin
Form := GetParentForm(Self);
if (Form <> nil) and (Form.Designer <> nil) then Form.Designer.Modified;
end;
inherited Change;
end;
procedure TPageControl.ChangeActivePage(Page: TTabSheet);
var
ParentForm: TForm;
begin
if FActivePage <> Page then
begin
ParentForm := GetParentForm(Self);
if (ParentForm <> nil) and (FActivePage <> nil) and
FActivePage.ContainsControl(ParentForm.ActiveControl) then
ParentForm.ActiveControl := FActivePage;
if Page <> nil then
begin
Page.BringToFront;
Page.Visible := True;
if (ParentForm <> nil) and (FActivePage <> nil) and
(ParentForm.ActiveControl = FActivePage) then
if Page.CanFocus then
ParentForm.ActiveControl := Page else
ParentForm.ActiveControl := Self;
end;
if FActivePage <> nil then FActivePage.Visible := False;
FActivePage := Page;
if (ParentForm <> nil) and (FActivePage <> nil) and
(ParentForm.ActiveControl = FActivePage) then
FActivePage.SelectFirst;
end;
end;
procedure TPageControl.DeleteTab(Page: TTabSheet);
begin
Tabs.Delete(Page.TabIndex);
UpdateActivePage;
end;
function TPageControl.FindNextPage(CurPage: TTabSheet;
GoForward, CheckTabVisible: Boolean): TTabSheet;
var
I, StartIndex: Integer;
begin
if FPages.Count <> 0 then
begin
StartIndex := FPages.IndexOf(CurPage);
if StartIndex = -1 then
if GoForward then StartIndex := FPages.Count - 1 else StartIndex := 0;
I := StartIndex;
repeat
if GoForward then
begin
Inc(I);
if I = FPages.Count then I := 0;
end else
begin
if I = 0 then I := FPages.Count;
Dec(I);
end;
Result := FPages[I];
if not CheckTabVisible or Result.TabVisible then Exit;
until I = StartIndex;
end;
Result := nil;
end;
procedure TPageControl.GetChildren(Proc: TGetChildProc);
var
I: Integer;
begin
for I := 0 to FPages.Count - 1 do Proc(TComponent(FPages[I]));
end;
function TPageControl.GetPage(Index: Integer): TTabSheet;
begin
Result := FPages[Index];
end;
function TPageControl.GetPageCount: Integer;
begin
Result := FPages.Count;
end;
procedure TPageControl.InsertPage(Page: TTabSheet);
begin
FPages.Add(Page);
Page.FPageControl := Self;
Page.UpdateTabShowing;
end;
procedure TPageControl.InsertTab(Page: TTabSheet);
begin
Tabs.InsertObject(Page.TabIndex, Page.Caption, Page);
UpdateActivePage;
end;
procedure TPageControl.MoveTab(CurIndex, NewIndex: Integer);
begin
Tabs.Move(CurIndex, NewIndex);
end;
procedure TPageControl.RemovePage(Page: TTabSheet);
begin
if FActivePage = Page then SetActivePage(nil);
Page.SetTabShowing(False);
Page.FPageControl := nil;
FPages.Remove(Page);
end;
procedure TPageControl.SelectNextPage(GoForward: Boolean);
var
Page: TTabSheet;
begin
Page := FindNextPage(ActivePage, GoForward, True);
if (Page <> nil) and (Page <> ActivePage) and CanChange then
begin
TabIndex := Page.TabIndex;
Change;
end;
end;
procedure TPageControl.SetActivePage(Page: TTabSheet);
begin
if (Page <> nil) and (Page.PageControl <> Self) then Exit;
ChangeActivePage(Page);
if Page <> nil then TabIndex := Page.TabIndex else TabIndex := -1;
end;
procedure TPageControl.SetChildOrder(Child: TComponent; Order: Integer);
begin
TTabSheet(Child).PageIndex := Order;
end;
procedure TPageControl.ShowControl(AControl: TControl);
begin
if (AControl is TTabSheet) and (TTabSheet(AControl).PageControl = Self) then
SetActivePage(TTabSheet(AControl));
inherited ShowControl(AControl);
end;
procedure TPageControl.UpdateTab(Page: TTabSheet);
begin
Tabs[Page.TabIndex] := Page.Caption;
end;
procedure TPageControl.UpdateActivePage;
begin
if TabIndex >= 0 then SetActivePage(TTabSheet(Tabs.Objects[TabIndex]));
end;
procedure TPageControl.CMDesignHitTest(var Message: TCMDesignHitTest);
var
HitIndex: Integer;
HitTestInfo: TTCHitTestInfo;
begin
HitTestInfo.pt := SmallPointToPoint(Message.Pos);
HitIndex := SendMessage(Handle, TCM_HITTEST, 0, Longint(@HitTestInfo));
if (HitIndex >= 0) and (HitIndex <> TabIndex) then Message.Result := 1;
end;
procedure TPageControl.CMDialogKey(var Message: TCMDialogKey);
begin
if (Message.CharCode = VK_TAB) and (GetKeyState(VK_CONTROL) < 0) then
begin
SelectNextPage(GetKeyState(VK_SHIFT) >= 0);
Message.Result := 1;
end else
inherited;
end;
{ TStatusPanel }
constructor TStatusPanel.Create(Collection: TCollection);
begin
FWidth := 50;
FBevel := pbLowered;
inherited Create(Collection);
end;
procedure TStatusPanel.Assign(Source: TPersistent);
begin
if Source is TStatusPanel then
begin
Text := TStatusPanel(Source).Text;
Width := TStatusPanel(Source).Width;
Alignment := TStatusPanel(Source).Alignment;
Bevel := TStatusPanel(Source).Bevel;
Style := TStatusPanel(Source).Style;
Exit;
end;
inherited Assign(Source);
end;
procedure TStatusPanel.SetAlignment(Value: TAlignment);
begin
if FAlignment <> Value then
begin
FAlignment := Value;
Changed(False);
end;
end;
procedure TStatusPanel.SetBevel(Value: TStatusPanelBevel);
begin
if FBevel <> Value then
begin
FBevel := Value;
Changed(True);
end;
end;
procedure TStatusPanel.SetStyle(Value: TStatusPanelStyle);
begin
if FStyle <> Value then
begin
FStyle := Value;
Changed(False);
end;
end;
procedure TStatusPanel.SetText(const Value: string);
begin
if FText <> Value then
begin
FText := Value;
Changed(False);
end;
end;
procedure TStatusPanel.SetWidth(Value: Integer);
begin
if FWidth <> Value then
begin
FWidth := Value;
Changed(True);
end;
end;
{ TStatusPanels }
constructor TStatusPanels.Create(StatusBar: TStatusBar);
begin
inherited Create(TStatusPanel);
FStatusBar := StatusBar;
end;
function TStatusPanels.Add: TStatusPanel;
begin
Result := TStatusPanel(inherited Add);
end;
function TStatusPanels.GetItem(Index: Integer): TStatusPanel;
begin
Result := TStatusPanel(inherited GetItem(Index));
end;
procedure TStatusPanels.SetItem(Index: Integer; Value: TStatusPanel);
begin
inherited SetItem(Index, Value);
end;
procedure TStatusPanels.Update(Item: TCollectionItem);
begin
if Item <> nil then
FStatusBar.UpdatePanel(Item.Index) else
FStatusBar.UpdatePanels;
end;
{ TStatusBar }
constructor TStatusBar.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
ControlStyle := [csCaptureMouse, csClickEvents, csDoubleClicks];
Color := clBtnFace;
Height := 19;
Align := alBottom;
FPanels := TStatusPanels.Create(Self);
FCanvas := TControlCanvas.Create;
TControlCanvas(FCanvas).Control := Self;
FSizeGrip := True;
end;
destructor TStatusBar.Destroy;
begin
FCanvas.Free;
FPanels.Free;
inherited Destroy;
end;
procedure TStatusBar.CreateParams(var Params: TCreateParams);
begin
InitCommonControls;
inherited CreateParams(Params);
CreateSubClass(Params, STATUSCLASSNAME);
if FSizeGrip then
Params.Style := Params.Style or SBARS_SIZEGRIP else
Params.Style := Params.Style or CCS_TOP;
end;
procedure TStatusBar.CreateWnd;
begin
inherited CreateWnd;
UpdatePanels;
if FSimpleText <> '' then
SendMessage(Handle, SB_SETTEXT, 255, Integer(PChar(FSimpleText)));
if FSimplePanel then
SendMessage(Handle, SB_SIMPLE, 1, 0);
end;
procedure TStatusBar.DrawPanel(Panel: TStatusPanel; const Rect: TRect);
begin
if Assigned(FOnDrawPanel) then
FOnDrawPanel(Self, Panel, Rect) else
FCanvas.FillRect(Rect);
end;
procedure TStatusBar.Resize;
begin
if Assigned(FOnResize) then FOnResize(Self);
end;
procedure TStatusBar.SetPanels(Value: TStatusPanels);
begin
FPanels.Assign(Value);
end;
procedure TStatusBar.SetSimplePanel(Value: Boolean);
begin
if FSimplePanel <> Value then
begin
FSimplePanel := Value;
if HandleAllocated then
SendMessage(Handle, SB_SIMPLE, Ord(FSimplePanel), 0);
end;
end;
procedure TStatusBar.SetSimpleText(const Value: string);
begin
if FSimpleText <> Value then
begin
FSimpleText := Value;
if HandleAllocated then
SendMessage(Handle, SB_SETTEXT, 255, Integer(PChar(FSimpleText)));
end;
end;
procedure TStatusBar.SetSizeGrip(Value: Boolean);
begin
if FSizeGrip <> Value then
begin
FSizeGrip := Value;
RecreateWnd;
end;
end;
procedure TStatusBar.UpdatePanel(Index: Integer);
var
Flags: Integer;
S: string;
begin
if HandleAllocated then
with Panels[Index] do
begin
Flags := 0;
case Bevel of
pbNone: Flags := SBT_NOBORDERS;
pbRaised: Flags := SBT_POPOUT;
end;
if Style = psOwnerDraw then Flags := Flags or SBT_OWNERDRAW;
S := Text;
case Alignment of
taCenter: S := #9 + S;
taRightJustify: S := #9#9 + S;
end;
SendMessage(Handle, SB_SETTEXT, Index or Flags, Integer(PChar(S)));
end;
end;
procedure TStatusBar.UpdatePanels;
const
MaxPanelCount = 128;
var
I, Count, PanelPos: Integer;
PanelEdges: array[0..MaxPanelCount - 1] of Integer;
begin
if HandleAllocated then
begin
Count := Panels.Count;
if Count > MaxPanelCount then Count := MaxPanelCount;
if Count = 0 then
begin
PanelEdges[0] := -1;
SendMessage(Handle, SB_SETPARTS, 1, Integer(@PanelEdges));
SendMessage(Handle, SB_SETTEXT, 0, Integer(PChar('')));
end else
begin
PanelPos := 0;
for I := 0 to Count - 2 do
begin
Inc(PanelPos, Panels[I].Width);
PanelEdges[I] := PanelPos;
end;
PanelEdges[Count - 1] := -1;
SendMessage(Handle, SB_SETPARTS, Count, Integer(@PanelEdges));
for I := 0 to Count - 1 do UpdatePanel(I);
end;
end;
end;
procedure TStatusBar.CNDrawItem(var Message: TWMDrawItem);
var
SaveIndex: Integer;
begin
with Message.DrawItemStruct^ do
begin
SaveIndex := SaveDC(hDC);
FCanvas.Handle := hDC;
FCanvas.Font := Font;
FCanvas.Brush.Color := clBtnFace;
FCanvas.Brush.Style := bsSolid;
DrawPanel(Panels[itemID], rcItem);
FCanvas.Handle := 0;
RestoreDC(hDC, SaveIndex);
end;
Message.Result := 1;
end;
procedure TStatusBar.WMSize(var Message: TWMSize);
begin
{ Eat WM_SIZE message to prevent control from doing alignment }
if not (csLoading in ComponentState) then Resize;
end;
{ THeaderSection }
constructor THeaderSection.Create(Collection: TCollection);
begin
FWidth := 50;
FMaxWidth := 10000;
FAllowClick := True;
inherited Create(Collection);
end;
procedure THeaderSection.Assign(Source: TPersistent);
begin
if Source is THeaderSection then
begin
Text := THeaderSection(Source).Text;
Width := THeaderSection(Source).Width;
MinWidth := THeaderSection(Source).MinWidth;
MaxWidth := THeaderSection(Source).MaxWidth;
Alignment := THeaderSection(Source).Alignment;
Style := THeaderSection(Source).Style;
AllowClick := THeaderSection(Source).AllowClick;
Exit;
end;
inherited Assign(Source);
end;
function THeaderSection.GetLeft: Integer;
var
I: Integer;
begin
Result := 0;
for I := 0 to Index - 1 do
Inc(Result, THeaderSections(Collection)[I].Width);
end;
function THeaderSection.GetRight: Integer;
begin
Result := Left + Width;
end;
procedure THeaderSection.SetAlignment(Value: TAlignment);
begin
if FAlignment <> Value then
begin
FAlignment := Value;
Changed(False);
end;
end;
procedure THeaderSection.SetMaxWidth(Value: Integer);
begin
if Value < FMinWidth then Value := FMinWidth;
if Value > 10000 then Value := 10000;
FMaxWidth := Value;
SetWidth(FWidth);
end;
procedure THeaderSection.SetMinWidth(Value: Integer);
begin
if Value < 0 then Value := 0;
if Value > FMaxWidth then Value := FMaxWidth;
FMinWidth := Value;
SetWidth(FWidth);
end;
procedure THeaderSection.SetStyle(Value: THeaderSectionStyle);
begin
if FStyle <> Value then
begin
FStyle := Value;
Changed(False);
end;
end;
procedure THeaderSection.SetText(const Value: string);
begin
if FText <> Value then
begin
FText := Value;
Changed(False);
end;
end;
procedure THeaderSection.SetWidth(Value: Integer);
begin
if Value < FMinWidth then Value := FMinWidth;
if Value > FMaxWidth then Value := FMaxWidth;
if FWidth <> Value then
begin
FWidth := Value;
Changed(True);
end;
end;
{ THeaderSections }
constructor THeaderSections.Create(HeaderControl: THeaderControl);
begin
inherited Create(THeaderSection);
FHeaderControl := HeaderControl;
end;
function THeaderSections.Add: THeaderSection;
begin
Result := THeaderSection(inherited Add);
end;
function THeaderSections.GetItem(Index: Integer): THeaderSection;
begin
Result := THeaderSection(inherited GetItem(Index));
end;
procedure THeaderSections.SetItem(Index: Integer; Value: THeaderSection);
begin
inherited SetItem(Index, Value);
end;
procedure THeaderSections.Update(Item: TCollectionItem);
begin
if Item <> nil then
FHeaderControl.UpdateSection(Item.Index) else
FHeaderControl.UpdateSections;
end;
{ THeaderControl }
constructor THeaderControl.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
ControlStyle := [];
Align := alTop;
Height := 17;
FSections := THeaderSections.Create(Self);
FCanvas := TControlCanvas.Create;
TControlCanvas(FCanvas).Control := Self;
end;
destructor THeaderControl.Destroy;
begin
FCanvas.Free;
FSections.Free;
inherited Destroy;
end;
procedure THeaderControl.CreateParams(var Params: TCreateParams);
begin
InitCommonControls;
inherited CreateParams(Params);
CreateSubClass(Params, 'SysHeader32');
Params.Style := Params.Style or HDS_BUTTONS;
end;
procedure THeaderControl.CreateWnd;
begin
inherited CreateWnd;
UpdateSections;
end;
procedure THeaderControl.DrawSection(Section: THeaderSection;
const Rect: TRect; Pressed: Boolean);
begin
if Assigned(FOnDrawSection) then
FOnDrawSection(Self, Section, Rect, Pressed) else
FCanvas.FillRect(Rect);
end;
procedure THeaderControl.Resize;
begin
if Assigned(FOnResize) then FOnResize(Self);
end;
procedure THeaderControl.SectionClick(Section: THeaderSection);
begin
if Assigned(FOnSectionClick) then FOnSectionClick(Self, Section);
end;
procedure THeaderControl.SectionResize(Section: THeaderSection);
begin
if Assigned(FOnSectionResize) then FOnSectionResize(Self, Section);
end;
procedure THeaderControl.SectionTrack(Section: THeaderSection;
Width: Integer; State: TSectionTrackState);
begin
if Assigned(FOnSectionTrack) then FOnSectionTrack(Self, Section, Width, State);
end;
procedure THeaderControl.SetSections(Value: THeaderSections);
begin
FSections.Assign(Value);
end;
procedure THeaderControl.UpdateItem(Message, Index: Integer);
var
Item: THDItem;
begin
with Sections[Index] do
begin
FillChar(Item, SizeOf(Item), 0);
Item.mask := HDI_WIDTH or HDI_TEXT or HDI_FORMAT;
Item.cxy := Width;
Item.pszText := PChar(Text);
Item.cchTextMax := Length(Text);
case Alignment of
taLeftJustify: Item.fmt := HDF_LEFT;
taRightJustify: Item.fmt := HDF_RIGHT;
else
Item.fmt := HDF_CENTER;
end;
if Style = hsOwnerDraw then
Item.fmt := Item.fmt or HDF_OWNERDRAW else
Item.fmt := Item.fmt or HDF_STRING;
SendMessage(Handle, Message, Index, Integer(@Item));
end;
end;
procedure THeaderControl.UpdateSection(Index: Integer);
begin
if HandleAllocated then UpdateItem(HDM_SETITEM, Index);
end;
procedure THeaderControl.UpdateSections;
var
I: Integer;
begin
if HandleAllocated then
begin
for I := 0 to SendMessage(Handle, HDM_GETITEMCOUNT, 0, 0) - 1 do
SendMessage(Handle, HDM_DELETEITEM, 0, 0);
for I := 0 to Sections.Count - 1 do UpdateItem(HDM_INSERTITEM, I);
end;
end;
procedure THeaderControl.CNDrawItem(var Message: TWMDrawItem);
var
SaveIndex: Integer;
begin
with Message.DrawItemStruct^ do
begin
SaveIndex := SaveDC(hDC);
FCanvas.Handle := hDC;
FCanvas.Font := Font;
FCanvas.Brush.Color := clBtnFace;
FCanvas.Brush.Style := bsSolid;
DrawSection(Sections[itemID], rcItem, itemState and ODS_SELECTED <> 0);
FCanvas.Handle := 0;
RestoreDC(hDC, SaveIndex);
end;
Message.Result := 1;
end;
procedure THeaderControl.CNNotify(var Message: TWMNotify);
var
Section: THeaderSection;
TrackState: TSectionTrackState;
begin
with PHDNotify(Message.NMHdr)^ do
case Hdr.code of
HDN_ITEMCLICK:
SectionClick(Sections[Item]);
HDN_ITEMCHANGED:
if PItem^.mask and HDI_WIDTH <> 0 then
begin
Section := Sections[Item];
if Section.FWidth <> PItem^.cxy then
begin
Section.FWidth := PItem^.cxy;
SectionResize(Section);
end;
end;
HDN_BEGINTRACK, HDN_TRACK, HDN_ENDTRACK:
begin
Section := Sections[Item];
case Hdr.code of
HDN_BEGINTRACK: TrackState := tsTrackBegin;
HDN_ENDTRACK: TrackState := tsTrackEnd;
else
TrackState := tsTrackMove;
end;
with PItem^ do
begin
if cxy < Section.FMinWidth then cxy := Section.FMinWidth;
if cxy > Section.FMaxWidth then cxy := Section.FMaxWidth;
SectionTrack(Sections[Item], cxy, TrackState);
end;
end;
end;
end;
procedure THeaderControl.WMLButtonDown(var Message: TWMLButtonDown);
var
Index: Integer;
Info: THDHitTestInfo;
begin
Info.Point.X := Message.Pos.X;
Info.Point.Y := Message.Pos.Y;
Index := SendMessage(Handle, HDM_HITTEST, 0, Integer(@Info));
if (Index < 0) or (Info.Flags and HHT_ONHEADER = 0) or
Sections[Index].AllowClick then inherited;
end;
procedure THeaderControl.WMSize(var Message: TWMSize);
begin
inherited;
if not (csLoading in ComponentState) then Resize;
end;
{ TTreeNode }
function DefaultTreeViewSort(Node1, Node2: TTreeNode; lParam: Integer): Integer; stdcall;
begin
with Node1 do
if Assigned(TreeView.OnCompare) then
TreeView.OnCompare(TreeView, Node1, Node2, lParam, Result)
else Result := lstrcmp(PChar(Node1.Text), PChar(Node2.Text));
end;
procedure TreeViewError(MsgID: Integer);
begin
raise ETreeViewError.CreateRes(MsgID);
end;
constructor TTreeNode.Create(AOwner: TTreeNodes);
begin
inherited Create;
FOverlayIndex := -1;
FStateIndex := -1;
FOwner := AOwner;
end;
destructor TTreeNode.Destroy;
var
Node: TTreeNode;
CheckValue: Integer;
begin
FDeleting := True;
Node := Parent;
if (Node <> nil) and (not Node.Deleting) then
begin
if Node.IndexOf(Self) <> -1 then CheckValue := 1
else CheckValue := 0;
if Node.Count = CheckValue then
begin
Node.Expanded := False;
Node.HasChildren := False;
end;
end;
if ItemId <> nil then TreeView_DeleteItem(Handle, ItemId);
Data := nil;
inherited Destroy;
end;
function TTreeNode.GetHandle: HWND;
begin
Result := TreeView.Handle;
end;
function TTreeNode.GetTreeView: TCustomTreeView;
begin
Result := Owner.Owner;
end;
function TTreeNode.HasAsParent(Value: TTreeNode): Boolean;
begin
if Self = Value then Result := True
else if Parent <> nil then Result := Parent.HasAsParent(Value)
else Result := False;
end;
procedure TTreeNode.SetText(const S: string);
var
Item: TTVItem;
begin
FText := S;
with Item do
begin
mask := TVIF_TEXT;
hItem := ItemId;
pszText := LPSTR_TEXTCALLBACK;
end;
TreeView_SetItem(Handle, Item);
if TreeView.SortType in [stText, stBoth] then
begin
if Parent <> nil then Parent.AlphaSort
else TreeView.AlphaSort;
end;
end;
procedure TTreeNode.SetData(Value: Pointer);
begin
FData := Value;
if (TreeView.SortType in [stData, stBoth]) and Assigned(TreeView.OnCompare) then
begin
if Parent <> nil then Parent.AlphaSort
else TreeView.AlphaSort;
end;
end;
function TTreeNode.GetState(NodeState: TNodeState): Boolean;
var
Item: TTVItem;
begin
Result := False;
with Item do
begin
mask := TVIF_STATE;
hItem := ItemId;
if TreeView_GetItem(Handle, Item) then
case NodeState of
nsCut: Result := (state and TVIS_CUT) <> 0;
nsFocused: Result := (state and TVIS_FOCUSED) <> 0;
nsSelected: Result := (state and TVIS_SELECTED) <> 0;
nsExpanded: Result := (state and TVIS_EXPANDED) <> 0;
nsDropHilited: Result := (state and TVIS_DROPHILITED) <> 0;
end;
end;
end;
procedure TTreeNode.SetImageIndex(Value: Integer);
var
Item: TTVItem;
begin
FImageIndex := Value;
with Item do
begin
mask := TVIF_IMAGE;
hItem := ItemId;
iImage := I_IMAGECALLBACK;
end;
TreeView_SetItem(Handle, Item);
end;
procedure TTreeNode.SetSelectedIndex(Value: Integer);
var
Item: TTVItem;
begin
FSelectedIndex := Value;
with Item do
begin
mask := TVIF_SELECTEDIMAGE;
hItem := ItemId;
iSelectedImage := I_IMAGECALLBACK;
end;
TreeView_SetItem(Handle, Item);
end;
procedure TTreeNode.SetOverlayIndex(Value: Integer);
var
Item: TTVItem;
begin
FOverlayIndex := Value;
with Item do
begin
mask := TVIF_STATE;
stateMask := TVIS_OVERLAYMASK;
hItem := ItemId;
state := IndexToOverlayMask(OverlayIndex + 1);
end;
TreeView_SetItem(Handle, Item);
end;
procedure TTreeNode.SetStateIndex(Value: Integer);
var
Item: TTVItem;
begin
FStateIndex := Value;
if Value >= 0 then Dec(Value);
with Item do
begin
mask := TVIF_STATE;
stateMask := TVIS_STATEIMAGEMASK;
hItem := ItemId;
state := IndexToStateImageMask(Value + 1);
end;
TreeView_SetItem(Handle, Item);
end;
procedure TTreeNode.ExpandItem(Expand: Boolean; Recurse: Boolean);
var
Flag: Integer;
Node: TTreeNode;
begin
if Recurse then
begin
Node := Self;
repeat
Node.ExpandItem(Expand, False);
Node := Node.GetNext;
until (Node = nil) or not Node.HasAsParent(Self);
end
else begin
if Expand then Flag := TVE_EXPAND
else Flag := TVE_COLLAPSE;
TreeView_Expand(Handle, ItemId, Flag);
end;
end;
procedure TTreeNode.Expand(Recurse: Boolean);
begin
ExpandItem(True, Recurse);
end;
procedure TTreeNode.Collapse(Recurse: Boolean);
begin
ExpandItem(False, Recurse);
end;
function TTreeNode.GetExpanded: Boolean;
begin
Result := GetState(nsExpanded);
end;
procedure TTreeNode.SetExpanded(Value: Boolean);
begin
if Value then Expand(False)
else Collapse(False);
end;
function TTreeNode.GetSelected: Boolean;
begin
Result := GetState(nsSelected);
end;
procedure TTreeNode.SetSelected(Value: Boolean);
begin
if Value then TreeView_SelectItem(Handle, ItemId)
else if Selected then TreeView_SelectItem(Handle, nil);
end;
function TTreeNode.GetCut: Boolean;
begin
Result := GetState(nsCut);
end;
procedure TTreeNode.SetCut(Value: Boolean);
var
Item: TTVItem;
Template: Integer;
begin
if Value then Template := -1
else Template := 0;
with Item do
begin
mask := TVIF_STATE;
hItem := ItemId;
stateMask := TVIS_CUT;
state := stateMask and Template;
end;
TreeView_SetItem(Handle, Item);
end;
function TTreeNode.GetDropTarget: Boolean;
begin
Result := GetState(nsDropHilited);
end;
procedure TTreeNode.SetDropTarget(Value: Boolean);
begin
if Value then TreeView_SelectDropTarget(Handle, ItemId)
else if DropTarget then TreeView_SelectDropTarget(Handle, nil);
end;
function TTreeNode.GetChildren: Boolean;
var
Item: TTVItem;
begin
Item.mask := TVIF_CHILDREN;
Item.hItem := ItemId;
if TreeView_GetItem(Handle, Item) then Result := Item.cChildren > 0
else Result := False;
end;
procedure TTreeNode.SetFocused(Value: Boolean);
var
Item: TTVItem;
Template: Integer;
begin
if Value then Template := -1
else Template := 0;
with Item do
begin
mask := TVIF_STATE;
hItem := ItemId;
stateMask := TVIS_FOCUSED;
state := stateMask and Template;
end;
TreeView_SetItem(Handle, Item);
end;
function TTreeNode.GetFocused: Boolean;
begin
Result := GetState(nsFocused);
end;
procedure TTreeNode.SetChildren(Value: Boolean);
var
Item: TTVItem;
begin
with Item do
begin
mask := TVIF_CHILDREN;
hItem := ItemId;
cChildren := Ord(Value);
end;
TreeView_SetItem(Handle, Item);
end;
function TTreeNode.GetParent: TTreeNode;
begin
with FOwner do
Result := GetNode(TreeView_GetParent(Handle, ItemId));
end;
function TTreeNode.getNextSibling: TTreeNode;
begin
with FOwner do
Result := GetNode(TreeView_GetNextSibling(Handle, ItemId));
end;
function TTreeNode.getPrevSibling: TTreeNode;
begin
with FOwner do
Result := GetNode(TreeView_GetPrevSibling(Handle, ItemId));
end;
function TTreeNode.GetNextVisible: TTreeNode;
begin
if IsVisible then
with FOwner do
Result := GetNode(TreeView_GetNextVisible(Handle, ItemId))
else Result := nil;
end;
function TTreeNode.GetPrevVisible: TTreeNode;
begin
with FOwner do
Result := GetNode(TreeView_GetPrevVisible(Handle, ItemId));
end;
function TTreeNode.GetNextChild(Value: TTreeNode): TTreeNode;
begin
if Value <> nil then Result := Value.getNextSibling
else Result := nil;
end;
function TTreeNode.GetPrevChild(Value: TTreeNode): TTreeNode;
begin
if Value <> nil then Result := Value.getPrevSibling
else Result := nil;
end;
function TTreeNode.getFirstChild: TTreeNode;
begin
with FOwner do
Result := GetNode(TreeView_GetChild(Handle, ItemId));
end;
function TTreeNode.GetLastChild: TTreeNode;
var
Node: TTreeNode;
begin
Result := getFirstChild;
if Result <> nil then
begin
Node := Result;
repeat
Result := Node;
Node := Result.getNextSibling;
until Node = nil;
end;
end;
function TTreeNode.GetNext: TTreeNode;
var
NodeID, ParentID: HTreeItem;
Handle: HWND;
begin
Handle := FOwner.Handle;
NodeID := TreeView_GetChild(Handle, ItemId);
if NodeID = nil then NodeID := TreeView_GetNextSibling(Handle, ItemId);
ParentID := ItemId;
while (NodeID = nil) and (ParentID <> nil) do
begin
ParentID := TreeView_GetParent(Handle, ParentID);
NodeID := TreeView_GetNextSibling(Handle, ParentID);
end;
Result := FOwner.GetNode(NodeID);
end;
function TTreeNode.GetPrev: TTreeNode;
var
Node: TTreeNode;
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 TTreeNode.GetAbsoluteIndex: Integer;
var
Node: TTreeNode;
begin
Result := -1;
Node := Self;
while Node <> nil do
begin
Inc(Result);
Node := Node.GetPrev;
end;
end;
function TTreeNode.GetIndex: Integer;
var
Node: TTreeNode;
begin
Result := -1;
Node := Self;
while Node <> nil do
begin
Inc(Result);
Node := Node.getPrevSibling;
end;
end;
function TTreeNode.GetItem(Index: Integer): TTreeNode;
begin
Result := getFirstChild;
while (Result <> nil) and (Index > 0) do
begin
Result := GetNextChild(Result);
Dec(Index);
end;
if Result = nil then TreeViewError(SListIndexError);
end;
procedure TTreeNode.SetItem(Index: Integer; Value: TTreeNode);
begin
item[Index].Assign(Value);
end;
function TTreeNode.IndexOf(Value: TTreeNode): Integer;
var
Node: TTreeNode;
begin
Result := -1;
Node := getFirstChild;
while (Node <> nil) do
begin
Inc(Result);
if Node = Value then Break;
Node := GetNextChild(Node);
end;
if Node = nil then Result := -1;
end;
function TTreeNode.GetCount: Integer;
var
Node: TTreeNode;
begin
Result := 0;
Node := getFirstChild;
while Node <> nil do
begin
Inc(Result);
Node := Node.GetNextChild(Node);
end;
end;
procedure TTreeNode.EndEdit(Cancel: Boolean);
begin
TreeView_EndEditLabelNow(Handle, Cancel);
end;
procedure TTreeNode.InternalMove(ParentNode, Node: TTreeNode;
HItem: HTreeItem; AddMode: TAddMode);
var
I: Integer;
NodeId: HTreeItem;
TreeViewItem: TTVItem;
Children: Boolean;
IsSelected: Boolean;
begin
if (AddMode = taInsert) and (Node <> nil) then
NodeId := Node.ItemId else
NodeId := nil;
Children := HasChildren;
IsSelected := Selected;
if (Parent <> nil) and (Parent.Count = 1) then
begin
Parent.Expanded := False;
Parent.HasChildren := False;
end;
with TreeViewItem do
begin
mask := TVIF_PARAM;
hItem := ItemId;
lParam := 0;
end;
TreeView_SetItem(Handle, TreeViewItem);
with Owner do
HItem := AddItem(HItem, NodeId, CreateItem(Self), AddMode);
if HItem = nil then
raise EOutOfResources.CreateRes(sInsertError);
for I := Count - 1 downto 0 do
Item[I].InternalMove(Self, nil, HItem, taAddFirst);
TreeView_DeleteItem(Handle, ItemId);
FItemId := HItem;
Assign(Self);
HasChildren := Children;
Selected := IsSelected;
end;
procedure TTreeNode.MoveTo(Destination: TTreeNode; Mode: TNodeAttachMode);
var
AddMode: TAddMode;
Node: TTreeNode;
HItem: HTreeItem;
OldOnChanging: TTVChangingEvent;
OldOnChange: TTVChangedEvent;
begin
OldOnChanging := TreeView.OnChanging;
OldOnChange := TreeView.OnChange;
TreeView.OnChanging := nil;
TreeView.OnChange := nil;
try
if (Destination = nil) or not Destination.HasAsParent(Self) then
begin
AddMode := taAdd;
if (Destination <> nil) and not (Mode in [naAddChild, naAddChildFirst]) then
Node := Destination.Parent else
Node := Destination;
case Mode of
naAdd,
naAddChild: AddMode := taAdd;
naAddFirst,
naAddChildFirst: AddMode := taAddFirst;
naInsert:
begin
Destination := Destination.getPrevSibling;
if Destination = nil then AddMode := taAddFirst
else AddMode := taInsert;
end;
end;
if Node <> nil then
HItem := Node.ItemId else
HItem := nil;
InternalMove(Node, Destination, HItem, AddMode);
Node := Parent;
if Node <> nil then
begin
Node.HasChildren := True;
Node.Expanded := True;
end;
end;
finally
TreeView.OnChanging := OldOnChanging;
TreeView.OnChange := OldOnChange;
end;
end;
procedure TTreeNode.MakeVisible;
begin
TreeView_EnsureVisible(Handle, ItemId);
end;
function TTreeNode.GetLevel: Integer;
var
Node: TTreeNode;
begin
Result := 0;
Node := Parent;
while Node <> nil do
begin
Inc(Result);
Node := Node.Parent;
end;
end;
function TTreeNode.IsNodeVisible: Boolean;
var
Rect: TRect;
begin
Result := TreeView_GetItemRect(Handle, ItemId, Rect, True);
end;
function TTreeNode.HasVisibleParent: Boolean;
begin
Result := (Parent <> nil) and (Parent.Expanded);
end;
function TTreeNode.EditText: Boolean;
begin
Result := TreeView_EditLabel(Handle, ItemId) <> 0;
end;
function TTreeNode.DisplayRect(TextOnly: Boolean): TRect;
begin
FillChar(Result, SizeOf(Result), 0);
TreeView_GetItemRect(Handle, ItemId, Result, TextOnly);
end;
function TTreeNode.AlphaSort: Boolean;
begin
Result := CustomSort(nil, 0);
end;
function TTreeNode.CustomSort(SortProc: TTVCompare; Data: Longint): Boolean;
var
SortCB: TTVSortCB;
begin
with SortCB do
begin
if not Assigned(SortProc) then lpfnCompare := @DefaultTreeViewSort
else lpfnCompare := SortProc;
hParent := ItemId;
lParam := Data;
end;
Result := TreeView_SortChildrenCB(Handle, SortCB, 0);
end;
procedure TTreeNode.Delete;
begin
if not Deleting then Free;
end;
procedure TTreeNode.DeleteChildren;
var
Node: TTreeNode;
begin
repeat
Node := getFirstChild;
if Node <> nil then Node.Delete;
until Node = nil;
end;
procedure TTreeNode.Assign(Source: TPersistent);
var
Node: TTreeNode;
begin
if Source is TTreeNode then
begin
Node := TTreeNode(Source);
Text := Node.Text;
Data := Node.Data;
ImageIndex := Node.ImageIndex;
SelectedIndex := Node.SelectedIndex;
StateIndex := Node.StateIndex;
OverlayIndex := Node.OverlayIndex;
Focused := Node.Focused;
DropTarget := Node.DropTarget;
Cut := Node.Cut;
HasChildren := Node.HasChildren;
end
else inherited Assign(Source);
end;
function TTreeNode.IsEqual(Node: TTreeNode): Boolean;
begin
Result := (Text = Node.Text) and (Data = Node.Data);
end;
procedure TTreeNode.ReadData(Stream: TStream; Info: PNodeInfo);
var
I, Size, ItemCount: Integer;
begin
Stream.ReadBuffer(Size, SizeOf(Size));
Stream.ReadBuffer(Info^, Size);
Text := Info^.Text;
ImageIndex := Info^.ImageIndex;
SelectedIndex := Info^.SelectedIndex;
StateIndex := Info^.StateIndex;
OverlayIndex := Info^.OverlayIndex;
Data := Info^.Data;
ItemCount := Info^.Count;
for I := 0 to ItemCount - 1 do
with Owner.AddChild(Self, '') do ReadData(Stream, Info);
end;
procedure TTreeNode.WriteData(Stream: TStream; Info: PNodeInfo);
var
I, Size, L, ItemCount: Integer;
begin
L := Length(Text);
if L > 255 then L := 255;
Size := SizeOf(TNodeInfo) + L - 255;
Info^.Text := Text;
Info^.ImageIndex := ImageIndex;
Info^.SelectedIndex := SelectedIndex;
Info^.OverlayIndex := OverlayIndex;
Info^.StateIndex := StateIndex;
Info^.Data := Data;
ItemCount := Count;
Info^.Count := ItemCount;
Stream.WriteBuffer(Size, SizeOf(Size));
Stream.WriteBuffer(Info^, Size);
for I := 0 to ItemCount - 1 do Item[I].WriteData(Stream, Info);
end;
{ TTreeNodes }
constructor TTreeNodes.Create(AOwner: TCustomTreeView);
begin
inherited Create;
FOwner := AOwner;
end;
destructor TTreeNodes.Destroy;
begin
Clear;
inherited Destroy;
end;
function TTreeNodes.GetCount: Integer;
begin
if Owner.HandleAllocated then Result := TreeView_GetCount(Handle)
else Result := 0;
end;
function TTreeNodes.GetHandle: HWND;
begin
Result := Owner.Handle;
end;
procedure TTreeNodes.Delete(Node: TTreeNode);
begin
if (Node.ItemId = nil) and Assigned(Owner.FOnDeletion) then
Owner.FOnDeletion(Self, Node);
Node.Delete;
end;
procedure TTreeNodes.Clear;
begin
if Owner.HandleAllocated then
TreeView_DeleteAllItems(Handle);
end;
function TTreeNodes.AddChildFirst(Node: TTreeNode; const S: string): TTreeNode;
begin
Result := AddChildObjectFirst(Node, S, nil);
end;
function TTreeNodes.AddChildObjectFirst(Node: TTreeNode; const S: string;
Ptr: Pointer): TTreeNode;
begin
Result := InternalAddObject(Node, S, Ptr, taAddFirst);
end;
function TTreeNodes.AddChild(Node: TTreeNode; const S: string): TTreeNode;
begin
Result := AddChildObject(Node, S, nil);
end;
function TTreeNodes.AddChildObject(Node: TTreeNode; const S: string;
Ptr: Pointer): TTreeNode;
begin
Result := InternalAddObject(Node, S, Ptr, taAdd);
end;
function TTreeNodes.AddFirst(Node: TTreeNode; const S: string): TTreeNode;
begin
Result := AddObjectFirst(Node, S, nil);
end;
function TTreeNodes.AddObjectFirst(Node: TTreeNode; const S: string;
Ptr: Pointer): TTreeNode;
begin
if Node <> nil then Node := Node.Parent;
Result := InternalAddObject(Node, S, Ptr, taAddFirst);
end;
function TTreeNodes.Add(Node: TTreeNode; const S: string): TTreeNode;
begin
Result := AddObject(Node, S, nil);
end;
procedure TTreeNodes.Repaint(Node: TTreeNode);
var
R: TRect;
begin
while (Node <> nil) and not Node.IsVisible do Node := Node.Parent;
if Node <> nil then
begin
R := Node.DisplayRect(False);
InvalidateRect(Owner.Handle, @R, True);
end;
end;
function TTreeNodes.AddObject(Node: TTreeNode; const S: string;
Ptr: Pointer): TTreeNode;
begin
if Node <> nil then Node := Node.Parent;
Result := InternalAddObject(Node, S, Ptr, taAdd);
end;
function TTreeNodes.Insert(Node: TTreeNode; const S: string): TTreeNode;
begin
Result := InsertObject(Node, S, nil);
end;
procedure TTreeNodes.AddedNode(Value: TTreeNode);
begin
Value := Value.Parent;
if Value <> nil then
begin
Value.HasChildren := True;
Repaint(Value);
end;
end;
function TTreeNodes.InsertObject(Node: TTreeNode; const S: string;
Ptr: Pointer): TTreeNode;
var
Item, ItemId: HTreeItem;
Parent: TTreeNode;
AddMode: TAddMode;
begin
Result := Owner.CreateNode;
try
Item := nil;
ItemId := nil;
AddMode := taInsert;
if Node <> nil then
begin
Parent := Node.Parent;
if Parent <> nil then Item := Parent.ItemId;
Node := Node.getPrevSibling;
if Node <> nil then ItemId := Node.ItemId
else AddMode := taAddFirst;
end;
Result.Data := Ptr;
Result.Text := S;
Item := AddItem(Item, ItemId, CreateItem(Result), AddMode);
if Item = nil then
raise EOutOfResources.CreateRes(sInsertError);
Result.FItemId := Item;
AddedNode(Result);
except
Result.Free;
raise;
end;
end;
function TTreeNodes.InternalAddObject(Node: TTreeNode; const S: string;
Ptr: Pointer; AddMode: TAddMode): TTreeNode;
var
Item: HTreeItem;
begin
Result := Owner.CreateNode;
try
if Node <> nil then Item := Node.ItemId
else Item := nil;
Result.Data := Ptr;
Result.Text := S;
Item := AddItem(Item, nil, CreateItem(Result), AddMode);
if Item = nil then
raise EOutOfResources.CreateRes(sInsertError);
Result.FItemId := Item;
AddedNode(Result);
except
Result.Free;
raise;
end;
end;
function TTreeNodes.CreateItem(Node: TTreeNode): TTVItem;
begin
with Result do
begin
mask := TVIF_TEXT or TVIF_PARAM or TVIF_IMAGE or TVIF_SELECTEDIMAGE;
lParam := Longint(Node);
pszText := LPSTR_TEXTCALLBACK;
iImage := I_IMAGECALLBACK;
iSelectedImage := I_IMAGECALLBACK;
end;
end;
function TTreeNodes.AddItem(Parent, Target: HTreeItem;
const Item: TTVItem; AddMode: TAddMode): HTreeItem;
var
InsertStruct: TTVInsertStruct;
begin
with InsertStruct do
begin
hParent := Parent;
case AddMode of
taAddFirst:
hInsertAfter := TVI_FIRST;
taAdd:
hInsertAfter := TVI_LAST;
taInsert:
hInsertAfter := Target;
end;
end;
InsertStruct.item := Item;
Result := TreeView_InsertItem(Handle, InsertStruct);
end;
function TTreeNodes.GetFirstNode: TTreeNode;
begin
Result := GetNode(TreeView_GetRoot(Handle));
end;
function TTreeNodes.GetNodeFromIndex(Index: Integer): TTreeNode;
begin
Result := GetFirstNode;
while (Index <> 0) and (Result <> nil) do
begin
Result := Result.GetNext;
Dec(Index);
end;
if Result = nil then TreeViewError(sInvalidIndex);
end;
function TTreeNodes.GetNode(ItemId: HTreeItem): TTreeNode;
var
Item: TTVItem;
begin
with Item do
begin
hItem := ItemId;
mask := TVIF_PARAM;
end;
if TreeView_GetItem(Handle, Item) then Result := TTreeNode(Item.lParam)
else Result := nil;
end;
procedure TTreeNodes.SetItem(Index: Integer; Value: TTreeNode);
begin
GetNodeFromIndex(Index).Assign(Value);
end;
procedure TTreeNodes.BeginUpdate;
begin
if FUpdateCount = 0 then SetUpdateState(True);
Inc(FUpdateCount);
end;
procedure TTreeNodes.SetUpdateState(Updating: Boolean);
begin
SendMessage(Handle, WM_SETREDRAW, Ord(not Updating), 0);
if not Updating then Owner.Refresh;
end;
procedure TTreeNodes.EndUpdate;
begin
Dec(FUpdateCount);
if FUpdateCount = 0 then SetUpdateState(False);
end;
procedure TTreeNodes.Assign(Source: TPersistent);
var
TreeNodes: TTreeNodes;
MemStream: TMemoryStream;
begin
if Source is TTreeNodes then
begin
TreeNodes := TTreeNodes(Source);
Clear;
MemStream := TMemoryStream.Create;
try
TreeNodes.WriteData(MemStream);
MemStream.Position := 0;
ReadData(MemStream);
finally
MemStream.Free;
end;
end
else inherited Assign(Source);
end;
procedure TTreeNodes.DefineProperties(Filer: TFiler);
function WriteNodes: Boolean;
var
I: Integer;
Nodes: TTreeNodes;
begin
Nodes := TTreeNodes(Filer.Ancestor);
if (Nodes <> nil) and (Nodes.Count = Count) then
for I := 0 to Count - 1 do
begin
Result := not Item[I].IsEqual(Nodes[I]);
if Result then Break;
end
else Result := Count > 0;
end;
begin
inherited DefineProperties(Filer);
Filer.DefineBinaryProperty('Data', ReadData, WriteData, WriteNodes);
end;
procedure TTreeNodes.ReadData(Stream: TStream);
var
I, Count: Integer;
NodeInfo: TNodeInfo;
begin
Clear;
Stream.ReadBuffer(Count, SizeOf(Count));
for I := 0 to Count - 1 do
Add(nil, '').ReadData(Stream, @NodeInfo);
end;
procedure TTreeNodes.WriteData(Stream: TStream);
var
I: Integer;
Node: TTreeNode;
NodeInfo: TNodeInfo;
begin
I := 0;
Node := GetFirstNode;
while Node <> nil do
begin
Inc(I);
Node := Node.getNextSibling;
end;
Stream.WriteBuffer(I, SizeOf(I));
Node := GetFirstNode;
while Node <> nil do
begin
Node.WriteData(Stream, @NodeInfo);
Node := Node.getNextSibling;
end;
end;
type
TTreeStrings = class(TStrings)
private
FOwner: TTreeNodes;
protected
function Get(Index: Integer): string; override;
function GetCount: Integer; override;
function GetObject(Index: Integer): TObject; override;
procedure PutObject(Index: Integer; AObject: TObject); override;
procedure SetUpdateState(Updating: Boolean); override;
public
constructor Create(AOwner: TTreeNodes);
function Add(const S: string): Integer; override;
procedure Clear; override;
procedure Delete(Index: Integer); override;
procedure Insert(Index: Integer; const S: string); override;
property Owner: TTreeNodes read FOwner;
end;
constructor TTreeStrings.Create(AOwner: TTreeNodes);
begin
inherited Create;
FOwner := AOwner;
end;
function TTreeStrings.Get(Index: Integer): string;
const
TAB = Chr(9);
var
Level, I: Integer;
Node: TTreeNode;
begin
Result := '';
Node := Owner.GetNodeFromIndex(Index);
Level := Node.Level;
for I := 0 to Level - 1 do Result := Result + TAB;
Result := Result + Node.Text;
end;
function TTreeStrings.GetObject(Index: Integer): TObject;
begin
Result := Owner.GetNodeFromIndex(Index).Data;
end;
procedure TTreeStrings.PutObject(Index: Integer; AObject: TObject);
begin
Owner.GetNodeFromIndex(Index).Data := AObject;
end;
function TTreeStrings.GetCount: Integer;
begin
Result := Owner.Count;
end;
procedure TTreeStrings.Clear;
begin
Owner.Clear;
end;
procedure TTreeStrings.Delete(Index: Integer);
begin
Owner.GetNodeFromIndex(Index).Delete;
end;
procedure TTreeStrings.SetUpdateState(Updating: Boolean);
begin
SendMessage(Owner.Handle, WM_SETREDRAW, Ord(not Updating), 0);
if not Updating then Owner.Owner.Refresh;
end;
function TTreeStrings.Add(const S: string): Integer;
var
Level, OldLevel, I: Integer;
NewStr: string;
Node: TTreeNode;
function GetBufStart(Buffer: PChar; var Level: Integer): PChar;
begin
Level := 0;
while Buffer^ in [' ', #9] do
begin
Inc(Buffer);
Inc(Level);
end;
Result := Buffer;
end;
begin
Result := GetCount;
if (Length(S) = 1) and (S[1] = Chr($1A)) then Exit;
Node := nil;
OldLevel := 0;
NewStr := GetBufStart(PChar(S), Level);
if Result > 0 then
begin
Node := Owner.GetNodeFromIndex(Result - 1);
OldLevel := Node.Level;
end;
if (Level > OldLevel) or (Node = nil) then
begin
if Level - OldLevel > 1 then TreeViewError(sInvalidLevel);
end
else begin
for I := OldLevel downto Level do
begin
Node := Node.Parent;
if (Node = nil) and (I - Level > 0) then
TreeViewError(sInvalidLevel);
end;
end;
Owner.AddChild(Node, NewStr);
end;
procedure TTreeStrings.Insert(Index: Integer; const S: string);
begin
with Owner do
Insert(GetNodeFromIndex(Index), S);
end;
{ TCustomTreeView }
constructor TCustomTreeView.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
ControlStyle := ControlStyle - [csCaptureMouse] + [csDisplayDragImage];
Width := 121;
Height := 97;
TabStop := True;
ParentColor := False;
FTreeNodes := TTreeNodes.Create(Self);
FBorderStyle := bsSingle;
FShowButtons := True;
FShowRoot := True;
FShowLines := True;
FHideSelection := True;
FDragImage := TImageList.CreateSize(32, 32);
FSaveIndent := -1;
FEditInstance := MakeObjectInstance(EditWndProc);
FImageChangeLink := TChangeLink.Create;
FImageChangeLink.OnChange := ImageListChange;
FStateChangeLink := TChangeLink.Create;
FStateChangeLink.OnChange := ImageListChange;
end;
destructor TCustomTreeView.Destroy;
begin
Items.Free;
FSaveItems.Free;
FDragImage.Free;
FMemStream.Free;
FreeObjectInstance(FEditInstance);
FImageChangeLink.Free;
FStateChangeLink.Free;
inherited Destroy;
end;
procedure TCustomTreeView.CreateParams(var Params: TCreateParams);
const
BorderStyles: array[TBorderStyle] of Integer = (0, WS_BORDER);
LineStyles: array[Boolean] of Integer = (0, TVS_HASLINES);
RootStyles: array[Boolean] of Integer = (0, TVS_LINESATROOT);
ButtonStyles: array[Boolean] of Integer = (0, TVS_HASBUTTONS);
EditStyles: array[Boolean] of Integer = (TVS_EDITLABELS, 0);
HideSelections: array[Boolean] of Integer = (TVS_SHOWSELALWAYS, 0);
DragStyles: array[TDragMode] of Integer = (TVS_DISABLEDRAGDROP, 0);
begin
InitCommonControls;
inherited CreateParams(Params);
CreateSubClass(Params, WC_TREEVIEW);
with Params do
begin
Style := Style or LineStyles[FShowLines] or BorderStyles[FBorderStyle] or
RootStyles[FShowRoot] or ButtonStyles[FShowButtons] or
EditStyles[FReadOnly] or HideSelections[FHideSelection] or
DragStyles[DragMode];
if Ctl3D and (FBorderStyle = bsSingle) then
ExStyle := Params.ExStyle or WS_EX_CLIENTEDGE;
end;
end;
procedure TCustomTreeView.CreateWnd;
begin
inherited CreateWnd;
if FMemStream <> nil then
begin
Items.ReadData(FMemStream);
FMemStream.Destroy;
FMemStream := nil;
SetTopItem(Items.GetNodeFromIndex(FSaveTopIndex));
FSaveTopIndex := 0;
SetSelection(Items.GetNodeFromIndex(FSaveIndex));
FSaveIndex := 0;
end;
if FSaveIndent <> -1 then Indent := FSaveIndent;
if (Images <> nil) and Images.HandleAllocated then
SetImageList(Images.Handle, TVSIL_NORMAL);
if (StateImages <> nil) and StateImages.HandleAllocated then
SetImageList(StateImages.Handle, TVSIL_STATE);
end;
procedure TCustomTreeView.DestroyWnd;
var
Node: TTreeNode;
begin
if Items.Count > 0 then
begin
FMemStream := TMemoryStream.Create;
Items.WriteData(FMemStream);
FMemStream.Position := 0;
Node := GetTopItem;
if Node <> nil then FSaveTopIndex := Node.AbsoluteIndex;
Node := Selected;
if Node <> nil then FSaveIndex := Node.AbsoluteIndex;
end;
FSaveIndent := Indent;
inherited DestroyWnd;
end;
procedure TCustomTreeView.EditWndProc(var Message: TMessage);
begin
try
with Message do
begin
case Msg of
WM_KEYDOWN,
WM_SYSKEYDOWN: if DoKeyDown(TWMKey(Message)) then Exit;
WM_CHAR: if DoKeyPress(TWMKey(Message)) then Exit;
WM_KEYUP,
WM_SYSKEYUP: if DoKeyUp(TWMKey(Message)) then Exit;
CN_KEYDOWN,
CN_CHAR, CN_SYSKEYDOWN,
CN_SYSCHAR:
begin
WndProc(Message);
Exit;
end;
end;
Result := CallWindowProc(FDefEditProc, FEditHandle, Msg, WParam, LParam);
end;
except
Application.HandleException(Self);
end;
end;
procedure TCustomTreeView.CMColorChanged(var Message: TMessage);
begin
inherited;
RecreateWnd;
end;
procedure TCustomTreeView.CMCtl3DChanged(var Message: TMessage);
begin
inherited;
if FBorderStyle = bsSingle then RecreateWnd;
end;
function TCustomTreeView.AlphaSort: Boolean;
var
I: Integer;
begin
if HandleAllocated then
begin
Result := CustomSort(nil, 0);
for I := 0 to Items.Count - 1 do
with Items[I] do
if HasChildren then AlphaSort;
end
else Result := False;
end;
function TCustomTreeView.CustomSort(SortProc: TTVCompare; Data: Longint): Boolean;
var
SortCB: TTVSortCB;
I: Integer;
Node: TTreeNode;
begin
Result := False;
if HandleAllocated then
begin
with SortCB do
begin
if not Assigned(SortProc) then lpfnCompare := @DefaultTreeViewSort
else lpfnCompare := SortProc;
hParent := TVI_ROOT;
lParam := Data;
Result := TreeView_SortChildrenCB(Handle, SortCB, 0);
end;
for I := 0 to Items.Count - 1 do
begin
Node := Items[I];
if Node.HasChildren then Node.CustomSort(SortProc, Data);
end;
end;
end;
procedure TCustomTreeView.SetSortType(Value: TSortType);
begin
if SortType <> Value then
begin
FSortType := Value;
if ((SortType in [stData, stBoth]) and Assigned(OnCompare)) or
(SortType in [stText, stBoth]) then
AlphaSort;
end;
end;
procedure TCustomTreeView.SetStyle(Value: Integer; UseStyle: Boolean);
var
Style: Integer;
begin
if HandleAllocated then
begin
Style := GetWindowLong(Handle, GWL_STYLE);
if not UseStyle then Style := Style and not Value
else Style := Style or Value;
SetWindowLong(Handle, GWL_STYLE, Style);
end;
end;
procedure TCustomTreeView.SetBorderStyle(Value: TBorderStyle);
begin
if BorderStyle <> Value then
begin
FBorderStyle := Value;
RecreateWnd;
end;
end;
procedure TCustomTreeView.SetDragMode(Value: TDragMode);
begin
if Value <> DragMode then
SetStyle(TVS_DISABLEDRAGDROP, Value = dmManual);
inherited;
end;
procedure TCustomTreeView.SetButtonStyle(Value: Boolean);
begin
if ShowButtons <> Value then
begin
FShowButtons := Value;
SetStyle(TVS_HASBUTTONS, Value);
end;
end;
procedure TCustomTreeView.SetLineStyle(Value: Boolean);
begin
if ShowLines <> Value then
begin
FShowLines := Value;
SetStyle(TVS_HASLINES, Value);
end;
end;
procedure TCustomTreeView.SetRootStyle(Value: Boolean);
begin
if ShowRoot <> Value then
begin
FShowRoot := Value;
SetStyle(TVS_LINESATROOT, Value);
end;
end;
procedure TCustomTreeView.SetReadOnly(Value: Boolean);
begin
if ReadOnly <> Value then
begin
FReadOnly := Value;
SetStyle(TVS_EDITLABELS, not Value);
end;
end;
procedure TCustomTreeView.SetHideSelection(Value: Boolean);
begin
if HideSelection <> Value then
begin
FHideSelection := Value;
SetStyle(TVS_SHOWSELALWAYS, not Value);
end;
end;
function TCustomTreeView.GetNodeAt(X, Y: Integer): TTreeNode;
var
HitTest: TTVHitTestInfo;
begin
with HitTest do
begin
pt.X := X;
pt.Y := Y;
if TreeView_HitTest(Handle, HitTest) <> nil then
Result := Items.GetNode(HitTest.hItem)
else Result := nil;
end;
end;
function TCustomTreeView.GetHitTestInfoAt(X, Y: Integer): THitTests;
var
HitTest: TTVHitTestInfo;
begin
Result := [];
with HitTest do
begin
pt.X := X;
pt.Y := Y;
TreeView_HitTest(Handle, HitTest);
if (flags and TVHT_ABOVE) <> 0 then Include(Result, htAbove);
if (flags and TVHT_BELOW) <> 0 then Include(Result, htBelow);
if (flags and TVHT_NOWHERE) <> 0 then Include(Result, htNowhere);
if (flags and TVHT_ONITEM) <> 0 then Include(Result, htOnItem);
if (flags and TVHT_ONITEMBUTTON) <> 0 then Include(Result, htOnButton);
if (flags and TVHT_ONITEMICON) <> 0 then Include(Result, htOnIcon);
if (flags and TVHT_ONITEMINDENT) <> 0 then Include(Result, htOnIndent);
if (flags and TVHT_ONITEMLABEL) <> 0 then Include(Result, htOnLabel);
if (flags and TVHT_ONITEMRIGHT) <> 0 then Include(Result, htOnRight);
if (flags and TVHT_ONITEMSTATEICON) <> 0 then Include(Result, htOnStateIcon);
if (flags and TVHT_TOLEFT) <> 0 then Include(Result, htToLeft);
if (flags and TVHT_TORIGHT) <> 0 then Include(Result, htToRight);
end;
end;
procedure TCustomTreeView.SetTreeNodes(Value: TTreeNodes);
begin
Items.Assign(Value);
end;
procedure TCustomTreeView.SetIndent(Value: Integer);
begin
if Value <> Indent then TreeView_SetIndent(Handle, Value);
end;
function TCustomTreeView.GetIndent: Integer;
begin
Result := TreeView_GetIndent(Handle)
end;
procedure TCustomTreeView.FullExpand;
var
Node: TTreeNode;
begin
Node := Items.GetFirstNode;
while Node <> nil do
begin
Node.Expand(True);
Node := Node.getNextSibling;
end;
end;
procedure TCustomTreeView.FullCollapse;
var
Node: TTreeNode;
begin
Node := Items.GetFirstNode;
while Node <> nil do
begin
Node.Collapse(True);
Node := Node.getNextSibling;
end;
end;
procedure TCustomTreeView.Loaded;
begin
inherited Loaded;
if csDesigning in ComponentState then FullExpand;
end;
function TCustomTreeView.GetTopItem: TTreeNode;
begin
if HandleAllocated then
Result := Items.GetNode(TreeView_GetFirstVisible(Handle))
else Result := nil;
end;
procedure TCustomTreeView.SetTopItem(Value: TTreeNode);
begin
if HandleAllocated and (Value <> nil) then
TreeView_SelectSetFirstVisible(Handle, Value.ItemId);
end;
function TCustomTreeView.GetSelection: TTreeNode;
begin
if HandleAllocated then
Result := Items.GetNode(TreeView_GetSelection(Handle))
else Result := nil;
end;
procedure TCustomTreeView.SetSelection(Value: TTreeNode);
begin
if Value <> nil then Value.Selected := True
else TreeView_SelectItem(Handle, nil);
end;
function TCustomTreeView.GetDropTarget: TTreeNode;
begin
if HandleAllocated then
begin
Result := Items.GetNode(TreeView_GetDropHilite(Handle));
if Result = nil then Result := FLastDropTarget;
end
else Result := nil;
end;
procedure TCustomTreeView.SetDropTarget(Value: TTreeNode);
begin
if HandleAllocated then
if Value <> nil then Value.DropTarget := True
else TreeView_SelectDropTarget(Handle, nil);
end;
function TCustomTreeView.GetNodeFromItem(const Item: TTVItem): TTreeNode;
begin
with Item do
if (state and TVIF_PARAM) <> 0 then Result := Pointer(lParam)
else Result := Items.GetNode(hItem);
end;
function TCustomTreeView.IsEditing: Boolean;
begin
Result := TreeView_GetEditControl(Handle) <> 0;
end;
procedure TCustomTreeView.CNNotify(var Message: TWMNotify);
var
Node: TTreeNode;
begin
with Message.NMHdr^ do
case code of
TVN_BEGINDRAG:
begin
FDragged := True;
with PNMTreeView(Pointer(Message.NMHdr))^ do
FDragNode := GetNodeFromItem(ItemNew);
end;
TVN_BEGINLABELEDIT:
begin
with PTVDispInfo(Pointer(Message.NMHdr))^ do
if Dragging or not CanEdit(GetNodeFromItem(item)) then
Message.Result := 1;
if Message.Result = 0 then
begin
FEditHandle := TreeView_GetEditControl(Handle);
FDefEditProc := Pointer(GetWindowLong(FEditHandle, GWL_WNDPROC));
SetWindowLong(FEditHandle, GWL_WNDPROC, LongInt(FEditInstance));
end;
end;
TVN_ENDLABELEDIT:
with PTVDispInfo(Pointer(Message.NMHdr))^ do
Edit(item);
TVN_ITEMEXPANDING:
with PNMTreeView(Pointer(Message.NMHdr))^ do
begin
Node := GetNodeFromItem(ItemNew);
if (action = TVE_EXPAND) and not CanExpand(Node) then
Message.Result := 1
else if (action = TVE_COLLAPSE) and
not CanCollapse(Node) then Message.Result := 1;
end;
TVN_ITEMEXPANDED:
with PNMTreeView(Pointer(Message.NMHdr))^ do
begin
Node := GetNodeFromItem(itemNew);
if (action = TVE_EXPAND) then Expand(Node)
else if (action = TVE_COLLAPSE) then Collapse(Node);
end;
TVN_SELCHANGING:
with PNMTreeView(Pointer(Message.NMHdr))^ do
if not CanChange(GetNodeFromItem(itemNew)) then
Message.Result := 1;
TVN_SELCHANGED:
with PNMTreeView(Pointer(Message.NMHdr))^ do
Change(GetNodeFromItem(itemNew));
TVN_DELETEITEM:
begin
with PNMTreeView(Pointer(Message.NMHdr))^ do
Node := GetNodeFromItem(itemOld);
if Node <> nil then
begin
Node.FItemId := nil;
Items.Delete(Node);
end;
end;
TVN_SETDISPINFO:
with PTVDispInfo(Pointer(Message.NMHdr))^ do
begin
Node := GetNodeFromItem(item);
if (Node <> nil) and ((item.mask and TVIF_TEXT) <> 0) then
Node.Text := item.pszText;
end;
TVN_GETDISPINFO:
with PTVDispInfo(Pointer(Message.NMHdr))^ do
begin
Node := GetNodeFromItem(item);
if Node <> nil then
begin
if (item.mask and TVIF_TEXT) <> 0 then
StrLCopy(item.pszText, PChar(Node.Text), item.cchTextMax);
if (item.mask and TVIF_IMAGE) <> 0 then
begin
GetImageIndex(Node);
item.iImage := Node.ImageIndex;
end;
if (item.mask and TVIF_SELECTEDIMAGE) <> 0 then
begin
GetSelectedIndex(Node);
item.iSelectedImage := Node.SelectedIndex;
end;
end;
end;
NM_RCLICK: FRClicked := True;
end;
end;
function TCustomTreeView.GetDragImages: TCustomImageList;
begin
if FDragImage.Count > 0 then
Result := FDragImage else
Result := nil;
end;
procedure TCustomTreeView.WndProc(var Message: TMessage);
begin
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;
procedure TCustomTreeView.DoStartDrag(var DragObject: TDragObject);
var
ImageHandle: HImageList;
DragNode: TTreeNode;
P: TPoint;
begin
inherited DoStartDrag(DragObject);
DragNode := FDragNode;
FLastDropTarget := nil;
FDragNode := nil;
if DragNode = nil then
begin
GetCursorPos(P);
with ScreenToClient(P) do DragNode := GetNodeAt(X, Y);
end;
if DragNode <> nil then
begin
ImageHandle := TreeView_CreateDragImage(Handle, DragNode.ItemId);
if ImageHandle <> 0 then
with FDragImage do
begin
Handle := ImageHandle;
SetDragImage(0, 2, 2);
end;
end;
end;
procedure TCustomTreeView.DoEndDrag(Target: TObject; X, Y: Integer);
begin
inherited DoEndDrag(Target, X, Y);
FLastDropTarget := nil;
end;
procedure TCustomTreeView.CMDrag(var Message: TCMDrag);
begin
inherited;
if Message.Result <> 0 then
with Message, DragRec^ do
case DragMessage of
dmDragMove: with ScreenToClient(Pos) do DoDragOver(Source, X, Y);
dmDragLeave:
begin
TDragObject(Source).HideDragImage;
FLastDropTarget := DropTarget;
DropTarget := nil;
TDragObject(Source).ShowDragImage;
end;
dmDragDrop: FLastDropTarget := nil;
end;
end;
procedure TCustomTreeView.DoDragOver(Source: TDragObject; X, Y: Integer);
var
Node: TTreeNode;
begin
Node := GetNodeAt(X, Y);
if (Node <> nil) and
((Node <> DropTarget) or (Node = FLastDropTarget)) then
begin
FLastDropTarget := nil;
TDragObject(Source).HideDragImage;
Node.DropTarget := True;
TDragObject(Source).ShowDragImage;
end;
end;
procedure TCustomTreeView.GetImageIndex(Node: TTreeNode);
begin
if Assigned(FOnGetImageIndex) then FOnGetImageIndex(Self, Node);
end;
procedure TCustomTreeView.GetSelectedIndex(Node: TTreeNode);
begin
if Assigned(FOnGetSelectedIndex) then FOnGetSelectedIndex(Self, Node);
end;
function TCustomTreeView.CanChange(Node: TTreeNode): Boolean;
begin
Result := True;
if Assigned(FOnChanging) then FOnChanging(Self, Node, Result);
end;
procedure TCustomTreeView.Change(Node: TTreeNode);
begin
if Assigned(FOnChange) then FOnChange(Self, Node);
end;
procedure TCustomTreeView.Expand(Node: TTreeNode);
begin
if Assigned(FOnExpanded) then FOnExpanded(Self, Node);
end;
function TCustomTreeView.CanExpand(Node: TTreeNode): Boolean;
begin
Result := True;
if Assigned(FOnExpanding) then FOnExpanding(Self, Node, Result);
end;
procedure TCustomTreeView.Collapse(Node: TTreeNode);
begin
if Assigned(FOnCollapsed) then FOnCollapsed(Self, Node);
end;
function TCustomTreeView.CanCollapse(Node: TTreeNode): Boolean;
begin
Result := True;
if Assigned(FOnCollapsing) then FOnCollapsing(Self, Node, Result);
end;
function TCustomTreeView.CanEdit(Node: TTreeNode): Boolean;
begin
Result := True;
if Assigned(FOnEditing) then FOnEditing(Self, Node, Result);
end;
procedure TCustomTreeView.Edit(const Item: TTVItem);
var
S: string;
Node: TTreeNode;
begin
with Item do
if pszText <> nil then
begin
S := pszText;
Node := GetNodeFromItem(Item);
if Assigned(FOnEdited) then FOnEdited(Self, Node, S);
if Node <> nil then Node.Text := S;
end;
end;
function TCustomTreeView.CreateNode: TTreeNode;
begin
Result := TTreeNode.Create(Items);
end;
procedure TCustomTreeView.SetImageList(Value: HImageList; Flags: Integer);
begin
if HandleAllocated then TreeView_SetImageList(Handle, Value, Flags);
end;
procedure TCustomTreeView.ImageListChange(Sender: TObject);
var
ImageHandle: HImageList;
begin
if HandleAllocated then
begin
ImageHandle := TImageList(Sender).Handle;
if Sender = Images then
SetImageList(ImageHandle, TVSIL_NORMAL)
else if Sender = StateImages then
SetImageList(ImageHandle, TVSIL_STATE);
end;
end;
procedure TCustomTreeView.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 TCustomTreeView.SetImages(Value: TImageList);
begin
if Images <> nil then
Images.UnRegisterChanges(FImageChangeLink);
FImages := Value;
if Images <> nil then
begin
Images.RegisterChanges(FImageChangeLink);
SetImageList(Images.Handle, TVSIL_NORMAL)
end
else SetImageList(0, TVSIL_NORMAL);
end;
procedure TCustomTreeView.SetStateImages(Value: TImageList);
begin
if StateImages <> nil then
StateImages.UnRegisterChanges(FStateChangeLink);
FStateImages := Value;
if StateImages <> nil then
begin
StateImages.RegisterChanges(FStateChangeLink);
SetImageList(StateImages.Handle, TVSIL_STATE)
end
else SetImageList(0, TVSIL_STATE);
end;
procedure TCustomTreeView.LoadFromFile(const FileName: string);
var
Stream: TStream;
begin
Stream := TFileStream.Create(FileName, fmOpenRead);
try
LoadFromStream(Stream);
finally
Stream.Free;
end;
end;
procedure TCustomTreeView.LoadFromStream(Stream: TStream);
begin
with TTreeStrings.Create(Items) do
try
LoadFromStream(Stream);
finally
Free;
end;
end;
procedure TCustomTreeView.SaveToFile(const FileName: string);
var
Stream: TStream;
begin
Stream := TFileStream.Create(FileName, fmCreate);
try
SaveToStream(Stream);
finally
Stream.Free;
end;
end;
procedure TCustomTreeView.SaveToStream(Stream: TStream);
begin
with TTreeStrings.Create(Items) do
try
SaveToStream(Stream);
finally
Free;
end;
end;
procedure TCustomTreeView.WMRButtonDown(var Message: TWMRButtonDown);
var
MousePos: TPoint;
begin
FRClicked := False;
inherited;
if FRClicked then
begin
GetCursorPos(MousePos);
with PointToSmallPoint(ScreenToClient(MousePos)) do
Perform(WM_RBUTTONUP, 0, MakeLong(X, Y));
end;
end;
procedure TCustomTreeView.WMLButtonDown(var Message: TWMLButtonDown);
var
Node: TTreeNode;
MousePos: TPoint;
begin
FDragged := False;
FDragNode := nil;
try
inherited;
if DragMode = dmAutomatic then
begin
SetFocus;
if not FDragged then
begin
GetCursorPos(MousePos);
with PointToSmallPoint(ScreenToClient(MousePos)) do
Perform(WM_LBUTTONUP, 0, MakeLong(X, Y));
end
else begin
Node := GetNodeAt(Message.XPos, Message.YPos);
if Node <> nil then
begin
Node.Focused := True;
Node.Selected := True;
BeginDrag(False);
end;
end;
end;
finally
FDragNode := nil;
end;
end;
{ TTrackBar }
constructor TTrackBar.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Width := 150;
Height := 45;
TabStop := True;
FMin := 0;
FMax := 10;
FLineSize := 1;
FPageSize := 2;
FFrequency := 1;
FTickMarks := tmBottomRight;
FTickStyle := tsAuto;
FOrientation := trHorizontal;
ControlStyle := ControlStyle - [csDoubleClicks];
end;
procedure TTrackBar.CreateParams(var Params: TCreateParams);
const
OrientationStyle: array[TTrackbarOrientation] of Longint = (TBS_HORZ, TBS_VERT);
TickStyles: array[TTickStyle] of Longint = (TBS_NOTICKS, TBS_AUTOTICKS, 0);
ATickMarks: array[TTickMark] of Longint = (TBS_BOTTOM, TBS_TOP, TBS_BOTH);
begin
InitCommonControls;
inherited CreateParams(Params);
CreateSubClass(Params, TRACKBAR_CLASS);
Params.Style := Params.Style or OrientationStyle[FOrientation] or
TickStyles[FTickStyle] or ATickMarks[FTickMarks] or TBS_ENABLESELRANGE;
Params.WindowClass.style := Params.WindowClass.style or CS_DBLCLKS;
end;
procedure TTrackBar.CreateWnd;
begin
inherited CreateWnd;
if HandleAllocated then
begin
SendMessage(Handle, TBM_SETLINESIZE, 0, FLineSize);
SendMessage(Handle, TBM_SETPAGESIZE, 0, FPageSize);
SendMessage(Handle, TBM_SETRANGEMIN, 0, FMin);
SendMessage(Handle, TBM_SETRANGEMAX, 0, FMax);
UpdateSelection;
SendMessage(Handle, TBM_SETPOS, 1, FPosition);
SendMessage(Handle, TBM_SETTICFREQ, FFrequency, 1);
end;
end;
procedure TTrackBar.DestroyWnd;
begin
inherited DestroyWnd;
end;
procedure TTrackBar.CNHScroll(var Message: TWMHScroll);
begin
inherited;
FPosition := SendMessage(Handle, TBM_GETPOS, 0, 0);
if Assigned(FOnChange) then
FOnChange(Self);
Message.Result := 0;
end;
procedure TTrackBar.CNVScroll(var Message: TWMVScroll);
begin
inherited;
FPosition := SendMessage(Handle, TBM_GETPOS, 0, 0);
if Assigned(FOnChange) then
FOnChange(Self);
Message.Result := 0;
end;
procedure TTrackBar.SetOrientation(Value: TTrackBarOrientation);
begin
if Value <> FOrientation then
begin
FOrientation := Value;
if ComponentState * [csLoading, csUpdating] = [] then
SetBounds(Left, Top, Height, Width);
RecreateWnd;
end;
end;
procedure TTrackBar.SetParams(APosition, AMin, AMax: Integer);
begin
if AMax < AMin then
raise EInvalidOperation.CreateResFmt(SPropertyOutOfRange, [Self.Classname]);
if APosition < AMin then APosition := AMin;
if APosition > AMax then APosition := AMax;
if (FMin <> AMin) then
begin
FMin := AMin;
if HandleAllocated then
SendMessage(Handle, TBM_SETRANGEMIN, 1, AMin);
end;
if (FMax <> AMax) then
begin
FMax := AMax;
if HandleAllocated then
SendMessage(Handle, TBM_SETRANGEMAX, 1, AMax);
end;
if FPosition <> APosition then
begin
FPosition := APosition;
if HandleAllocated then
SendMessage(Handle, TBM_SETPOS, 1, APosition);
end;
end;
procedure TTrackBar.SetPosition(Value: Integer);
begin
SetParams(Value, FMin, FMax);
end;
procedure TTrackBar.SetMin(Value: Integer);
begin
SetParams(FPosition, Value, FMax);
end;
procedure TTrackBar.SetMax(Value: Integer);
begin
SetParams(FPosition, FMin, Value);
end;
procedure TTrackBar.SetFrequency(Value: Integer);
begin
if Value <> FFrequency then
begin
FFrequency := Value;
if HandleAllocated then
SendMessage(Handle, TBM_SETTICFREQ, FFrequency, 1);
end;
end;
procedure TTrackBar.SetTick(Value: Integer);
begin
if HandleAllocated then
SendMessage(Handle, TBM_SETTIC, 0, Value);
end;
procedure TTrackBar.SetTickStyle(Value: TTickStyle);
begin
if Value <> FTickStyle then
begin
FTickStyle := Value;
RecreateWnd;
end;
end;
procedure TTrackBar.SetTickMarks(Value: TTickMark);
begin
if Value <> FTickMarks then
begin
FTickMarks := Value;
RecreateWnd;
end;
end;
procedure TTrackBar.SetLineSize(Value: Integer);
begin
if Value <> FLineSize then
begin
FLineSize := Value;
if HandleAllocated then
SendMessage(Handle, TBM_SETLINESIZE, 0, FLineSize);
end;
end;
procedure TTrackBar.SetPageSize(Value: Integer);
begin
if Value <> FPageSize then
begin
FPageSize := Value;
if HandleAllocated then
SendMessage(Handle, TBM_SETPAGESIZE, 0, FPageSize);
end;
end;
procedure TTrackBar.UpdateSelection;
begin
if HandleAllocated then
begin
if (FSelStart = 0) and (FSelEnd = 0) then
SendMessage(Handle, TBM_CLEARSEL, 1, 0)
else
SendMessage(Handle, TBM_SETSEL, Integer(True), MakeLong(FSelStart, FSelEnd));
end;
end;
procedure TTrackBar.SetSelStart(Value: Integer);
begin
if Value <> FSelStart then
begin
FSelStart := Value;
UpdateSelection;
end;
end;
procedure TTrackBar.SetSelEnd(Value: Integer);
begin
if Value <> FSelEnd then
begin
FSelEnd := Value;
UpdateSelection;
end;
end;
{ TProgressBar }
constructor TProgressBar.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Width := 150;
Height := GetSystemMetrics(SM_CYVSCROLL);
FMin := 0;
FMax := 100;
FStep := 10;
end;
procedure TProgressBar.CreateParams(var Params: TCreateParams);
begin
InitCommonControls;
inherited CreateParams(Params);
CreateSubClass(Params, PROGRESS_CLASS);
end;
procedure TProgressBar.CreateWnd;
begin
inherited CreateWnd;
SendMessage(Handle, PBM_SETRANGE, 0, MakeLong(FMin, FMax));
SendMessage(Handle, PBM_SETSTEP, FStep, 0);
Position := FPosition;
end;
function TProgressBar.GetPosition: TProgressRange;
begin
if HandleAllocated then
Result := SendMessage(Handle, PBM_DELTAPOS, 0, 0) else
Result := FPosition;
end;
procedure TProgressBar.SetParams(AMin, AMax: TProgressRange);
begin
if AMax < AMin then
raise EInvalidOperation.CreateResFmt(SPropertyOutOfRange, [Self.Classname]);
if (FMin <> AMin) or (FMax <> AMax) then
begin
if HandleAllocated then
begin
SendMessage(Handle, PBM_SETRANGE, 0, MakeLong(AMin, AMax));
if FMin > AMin then // since Windows sets Position when increase Min..
SendMessage(Handle, PBM_SETPOS, AMin, 0); // set it back if decrease
end;
FMin := AMin;
FMax := AMax;
end;
end;
procedure TProgressBar.SetMin(Value: TProgressRange);
begin
SetParams(Value, FMax);
end;
procedure TProgressBar.SetMax(Value: TProgressRange);
begin
SetParams(FMin, Value);
end;
procedure TProgressBar.SetPosition(Value: TProgressRange);
begin
if HandleAllocated then
SendMessage(Handle, PBM_SETPOS, Value, 0) else
FPosition := Value;
end;
procedure TProgressBar.SetStep(Value: TProgressRange);
begin
if Value <> FStep then
begin
FStep := Value;
if HandleAllocated then
SendMessage(Handle, PBM_SETSTEP, FStep, 0);
end;
end;
procedure TProgressBar.StepIt;
begin
if HandleAllocated then
SendMessage(Handle, PBM_STEPIT, 0, 0);
end;
procedure TProgressBar.StepBy(Delta: TProgressRange);
begin
if HandleAllocated then
SendMessage(Handle, PBM_DELTAPOS, Delta, 0);
end;
{ TTextAttributes }
constructor TTextAttributes.Create(AOwner: TCustomRichEdit;
AttributeType: TAttributeType);
begin
inherited Create;
RichEdit := AOwner;
FType := AttributeType;
end;
procedure TTextAttributes.InitFormat(var Format: TCharFormat);
begin
FillChar(Format, SizeOf(TCharFormat), 0);
Format.cbSize := SizeOf(TCharFormat);
end;
function TTextAttributes.GetConsistentAttributes: TConsistentAttributes;
var
Format: TCharFormat;
begin
Result := [];
if RichEdit.HandleAllocated and (FType = atSelected) then
begin
InitFormat(Format);
SendMessage(RichEdit.Handle, EM_GETCHARFORMAT,
WPARAM(FType = atSelected), LPARAM(@Format));
with Format do
begin
if (dwMask and CFM_BOLD) <> 0 then Include(Result, caBold);
if (dwMask and CFM_COLOR) <> 0 then Include(Result, caColor);
if (dwMask and CFM_FACE) <> 0 then Include(Result, caFace);
if (dwMask and CFM_ITALIC) <> 0 then Include(Result, caItalic);
if (dwMask and CFM_SIZE) <> 0 then Include(Result, caSize);
if (dwMask and CFM_STRIKEOUT) <> 0 then Include(Result, caStrikeOut);
if (dwMask and CFM_UNDERLINE) <> 0 then Include(Result, caUnderline);
if (dwMask and CFM_PROTECTED) <> 0 then Include(Result, caProtected);
end;
end;
end;
procedure TTextAttributes.GetAttributes(var Format: TCharFormat);
begin
InitFormat(Format);
if RichEdit.HandleAllocated then
SendMessage(RichEdit.Handle, EM_GETCHARFORMAT,
WPARAM(FType = atSelected), LPARAM(@Format));
end;
procedure TTextAttributes.SetAttributes(var Format: TCharFormat);
var
Flag: Longint;
begin
if FType = atSelected then Flag := SCF_SELECTION
else Flag := 0;
if RichEdit.HandleAllocated then
SendMessage(RichEdit.Handle, EM_SETCHARFORMAT, Flag, LPARAM(@Format))
end;
function TTextAttributes.GetProtected: Boolean;
var
Format: TCharFormat;
begin
GetAttributes(Format);
with Format do
if (dwEffects and CFE_PROTECTED) <> 0 then
Result := True else
Result := False;
end;
procedure TTextAttributes.SetProtected(Value: Boolean);
var
Format: TCharFormat;
begin
InitFormat(Format);
with Format do
begin
dwMask := CFM_PROTECTED;
if Value then dwEffects := CFE_PROTECTED;
end;
SetAttributes(Format);
end;
function TTextAttributes.GetColor: TColor;
var
Format: TCharFormat;
begin
GetAttributes(Format);
with Format do
if (dwEffects and CFE_AUTOCOLOR) <> 0 then
Result := clWindowText else
Result := crTextColor;
end;
procedure TTextAttributes.SetColor(Value: TColor);
var
Format: TCharFormat;
begin
InitFormat(Format);
with Format do
begin
dwMask := CFM_COLOR;
if Value = clWindowText then
dwEffects := CFE_AUTOCOLOR else
crTextColor := ColorToRGB(Value);
end;
SetAttributes(Format);
end;
function TTextAttributes.GetName: TFontName;
var
Format: TCharFormat;
begin
GetAttributes(Format);
Result := Format.szFaceName;
end;
procedure TTextAttributes.SetName(Value: TFontName);
var
Format: TCharFormat;
begin
InitFormat(Format);
with Format do
begin
dwMask := CFM_FACE;
StrPLCopy(szFaceName, Value, SizeOf(szFaceName));
end;
SetAttributes(Format);
end;
function TTextAttributes.GetStyle: TFontStyles;
var
Format: TCharFormat;
begin
Result := [];
GetAttributes(Format);
with Format do
begin
if (dwEffects and CFE_BOLD) <> 0 then Include(Result, fsBold);
if (dwEffects and CFE_ITALIC) <> 0 then Include(Result, fsItalic);
if (dwEffects and CFE_UNDERLINE) <> 0 then Include(Result, fsUnderline);
if (dwEffects and CFE_STRIKEOUT) <> 0 then Include(Result, fsStrikeOut);
end;
end;
procedure TTextAttributes.SetStyle(Value: TFontStyles);
var
Format: TCharFormat;
begin
InitFormat(Format);
with Format do
begin
dwMask := CFM_BOLD or CFM_ITALIC or CFM_UNDERLINE or CFM_STRIKEOUT;
if fsBold in Value then dwEffects := dwEffects or CFE_BOLD;
if fsItalic in Value then dwEffects := dwEffects or CFE_ITALIC;
if fsUnderline in Value then dwEffects := dwEffects or CFE_UNDERLINE;
if fsStrikeOut in Value then dwEffects := dwEffects or CFE_STRIKEOUT;
end;
SetAttributes(Format);
end;
function TTextAttributes.GetSize: Integer;
var
Format: TCharFormat;
begin
GetAttributes(Format);
Result := Format.yHeight div 20;
end;
procedure TTextAttributes.SetSize(Value: Integer);
var
Format: TCharFormat;
begin
InitFormat(Format);
with Format do
begin
dwMask := CFM_SIZE;
yHeight := Value * 20;
end;
SetAttributes(Format);
end;
function TTextAttributes.GetHeight: Integer;
begin
Result := MulDiv(Size, RichEdit.FScreenLogPixels, 72);
end;
procedure TTextAttributes.SetHeight(Value: Integer);
begin
Size := MulDiv(Value, 72, RichEdit.FScreenLogPixels);
end;
function TTextAttributes.GetPitch: TFontPitch;
var
Format: TCharFormat;
begin
GetAttributes(Format);
case (Format.bPitchAndFamily and $03) of
DEFAULT_PITCH: Result := fpDefault;
VARIABLE_PITCH: Result := fpVariable;
FIXED_PITCH: Result := fpFixed;
else
Result := fpDefault;
end;
end;
procedure TTextAttributes.SetPitch(Value: TFontPitch);
var
Format: TCharFormat;
begin
InitFormat(Format);
with Format do
begin
case Value of
fpVariable: Format.bPitchAndFamily := VARIABLE_PITCH;
fpFixed: Format.bPitchAndFamily := FIXED_PITCH;
else
Format.bPitchAndFamily := DEFAULT_PITCH;
end;
end;
SetAttributes(Format);
end;
procedure TTextAttributes.Assign(Source: TPersistent);
begin
if Source is TFont then
begin
Color := TFont(Source).Color;
Name := TFont(Source).Name;
Style := TFont(Source).Style;
Size := TFont(Source).Size;
Pitch := TFont(Source).Pitch;
end
else if Source is TTextAttributes then
begin
Color := TTextAttributes(Source).Color;
Name := TTextAttributes(Source).Name;
Style := TTextAttributes(Source).Style;
Pitch := TTextAttributes(Source).Pitch;
end
else inherited Assign(Source);
end;
procedure TTextAttributes.AssignTo(Dest: TPersistent);
begin
if Dest is TFont then
begin
TFont(Dest).Color := Color;
TFont(Dest).Name := Name;
TFont(Dest).Style := Style;
TFont(Dest).Size := Size;
TFont(Dest).Pitch := Pitch;
end
else if Dest is TTextAttributes then
begin
TTextAttributes(Dest).Color := Color;
TTextAttributes(Dest).Name := Name;
TTextAttributes(Dest).Style := Style;
TTextAttributes(Dest).Pitch := Pitch;
end
else inherited AssignTo(Dest);
end;
{ TParaAttributes }
constructor TParaAttributes.Create(AOwner: TCustomRichEdit);
begin
inherited Create;
RichEdit := AOwner;
end;
procedure TParaAttributes.InitPara(var Paragraph: TParaFormat);
begin
FillChar(Paragraph, SizeOf(TParaFormat), 0);
Paragraph.cbSize := SizeOf(TParaFormat);
end;
procedure TParaAttributes.GetAttributes(var Paragraph: TParaFormat);
begin
InitPara(Paragraph);
if RichEdit.HandleAllocated then
SendMessage(RichEdit.Handle, EM_GETPARAFORMAT, 0, LPARAM(@Paragraph));
end;
procedure TParaAttributes.SetAttributes(var Paragraph: TParaFormat);
begin
if RichEdit.HandleAllocated then
SendMessage(RichEdit.Handle, EM_SETPARAFORMAT, 0, LPARAM(@Paragraph))
end;
function TParaAttributes.GetAlignment: TAlignment;
var
Paragraph: TParaFormat;
begin
GetAttributes(Paragraph);
Result := TAlignment(Paragraph.wAlignment - 1);
end;
procedure TParaAttributes.SetAlignment(Value: TAlignment);
var
Paragraph: TParaFormat;
begin
InitPara(Paragraph);
with Paragraph do
begin
dwMask := PFM_ALIGNMENT;
wAlignment := Ord(Value) + 1;
end;
SetAttributes(Paragraph);
end;
function TParaAttributes.GetNumbering: TNumberingStyle;
var
Paragraph: TParaFormat;
begin
GetAttributes(Paragraph);
Result := TNumberingStyle(Paragraph.wNumbering);
end;
procedure TParaAttributes.SetNumbering(Value: TNumberingStyle);
var
Paragraph: TParaFormat;
begin
case Value of
nsBullet: if LeftIndent < 10 then LeftIndent := 10;
nsNone: LeftIndent := 0;
end;
InitPara(Paragraph);
with Paragraph do
begin
dwMask := PFM_NUMBERING;
wNumbering := Ord(Value);
end;
SetAttributes(Paragraph);
end;
function TParaAttributes.GetFirstIndent: Longint;
var
Paragraph: TParaFormat;
begin
GetAttributes(Paragraph);
Result := Paragraph.dxStartIndent div 20
end;
procedure TParaAttributes.SetFirstIndent(Value: Longint);
var
Paragraph: TParaFormat;
begin
InitPara(Paragraph);
with Paragraph do
begin
dwMask := PFM_STARTINDENT;
dxStartIndent := Value * 20;
end;
SetAttributes(Paragraph);
end;
function TParaAttributes.GetLeftIndent: Longint;
var
Paragraph: TParaFormat;
begin
GetAttributes(Paragraph);
Result := Paragraph.dxOffset div 20;
end;
procedure TParaAttributes.SetLeftIndent(Value: Longint);
var
Paragraph: TParaFormat;
begin
InitPara(Paragraph);
with Paragraph do
begin
dwMask := PFM_OFFSET;
dxOffset := Value * 20;
end;
SetAttributes(Paragraph);
end;
function TParaAttributes.GetRightIndent: Longint;
var
Paragraph: TParaFormat;
begin
GetAttributes(Paragraph);
Result := Paragraph.dxRightIndent div 20;
end;
procedure TParaAttributes.SetRightIndent(Value: Longint);
var
Paragraph: TParaFormat;
begin
InitPara(Paragraph);
with Paragraph do
begin
dwMask := PFM_RIGHTINDENT;
dxRightIndent := Value * 20;
end;
SetAttributes(Paragraph);
end;
function TParaAttributes.GetTab(Index: Byte): Longint;
var
Paragraph: TParaFormat;
begin
GetAttributes(Paragraph);
Result := Paragraph.rgxTabs[Index] div 20;
end;
procedure TParaAttributes.SetTab(Index: Byte; Value: Longint);
var
Paragraph: TParaFormat;
begin
GetAttributes(Paragraph);
with Paragraph do
begin
rgxTabs[Index] := Value * 20;
dwMask := PFM_TABSTOPS;
if cTabCount < Index then cTabCount := Index;
SetAttributes(Paragraph);
end;
end;
function TParaAttributes.GetTabCount: Integer;
var
Paragraph: TParaFormat;
begin
GetAttributes(Paragraph);
Result := Paragraph.cTabCount;
end;
procedure TParaAttributes.SetTabCount(Value: Integer);
var
Paragraph: TParaFormat;
begin
GetAttributes(Paragraph);
with Paragraph do
begin
dwMask := PFM_TABSTOPS;
cTabCount := Value;
SetAttributes(Paragraph);
end;
end;
procedure TParaAttributes.Assign(Source: TPersistent);
var
I: Integer;
begin
if Source is TParaAttributes then
begin
Alignment := TParaAttributes(Source).Alignment;
FirstIndent := TParaAttributes(Source).FirstIndent;
LeftIndent := TParaAttributes(Source).LeftIndent;
RightIndent := TParaAttributes(Source).RightIndent;
Numbering := TParaAttributes(Source).Numbering;
for I := 0 to MAX_TAB_STOPS - 1 do
Tab[I] := TParaAttributes(Source).Tab[I];
end
else inherited Assign(Source);
end;
{ TConversion }
function TConversion.ConvertReadStream(Stream: TStream; Buffer: PChar; BufSize: Integer): Integer;
begin
Result := Stream.Read(Buffer^, BufSize);
end;
function TConversion.ConvertWriteStream(Stream: TStream; Buffer: PChar; BufSize: Integer): Integer;
begin
Result := Stream.Write(Buffer^, BufSize);
end;
{ TRichEditStrings }
const
ReadError = $0001;
WriteError = $0002;
NoError = $0000;
type
TSelection = record
StartPos, EndPos: Integer;
end;
TRichEditStrings = class(TStrings)
private
RichEdit: TCustomRichEdit;
FPlainText: Boolean;
FConverter: TConversion;
protected
function Get(Index: Integer): string; override;
function GetCount: Integer; override;
procedure Put(Index: Integer; const S: string); override;
procedure SetUpdateState(Updating: Boolean); override;
public
procedure Clear; override;
procedure AddStrings(Strings: TStrings); override;
procedure Delete(Index: Integer); override;
procedure Insert(Index: Integer; const S: string); override;
procedure LoadFromFile(const FileName: string); override;
procedure LoadFromStream(Stream: TStream); override;
procedure SaveToFile(const FileName: string); override;
procedure SaveToStream(Stream: TStream); override;
property PlainText: Boolean read FPlainText write FPlainText;
end;
procedure TRichEditStrings.AddStrings(Strings: TStrings);
var
SelChange: TNotifyEvent;
begin
SelChange := RichEdit.OnSelectionChange;
RichEdit.OnSelectionChange := nil;
try
inherited AddStrings(Strings);
finally
RichEdit.OnSelectionChange := SelChange;
end;
end;
function TRichEditStrings.GetCount: Integer;
begin
Result := SendMessage(RichEdit.Handle, EM_GETLINECOUNT, 0, 0);
if SendMessage(RichEdit.Handle, EM_LINELENGTH, SendMessage(RichEdit.Handle,
EM_LINEINDEX, Result - 1, 0), 0) = 0 then Dec(Result);
end;
function TRichEditStrings.Get(Index: Integer): string;
var
Text: array[0..4095] of Char;
L: Integer;
begin
Word((@Text)^) := SizeOf(Text);
L := SendMessage(RichEdit.Handle, EM_GETLINE, Index, Longint(@Text));
if (Text[L - 2] = #13) and (Text[L - 1] = #10) then Dec(L, 2);
SetString(Result, Text, L);
end;
procedure TRichEditStrings.Put(Index: Integer; const S: string);
var
Selection: TSelection;
begin
if Index >= 0 then
begin
Selection.StartPos := SendMessage(RichEdit.Handle, EM_LINEINDEX, Index, 0);
if Selection.StartPos <> -1 then
begin
Selection.EndPos := Selection.StartPos +
SendMessage(RichEdit.Handle, EM_LINELENGTH, Selection.StartPos, 0);
SendMessage(RichEdit.Handle, EM_SETSEL, Selection.StartPos, Selection.EndPos);
SendMessage(RichEdit.Handle, EM_REPLACESEL, 0, Longint(PChar(S)));
end;
end;
end;
procedure TRichEditStrings.Insert(Index: Integer; const S: string);
var
L: Integer;
Selection: TSelection;
Fmt: PChar;
Str: string;
begin
if Index >= 0 then
begin
Selection.StartPos := SendMessage(RichEdit.Handle, EM_LINEINDEX, Index, 0);
if Selection.StartPos >= 0 then Fmt := '%s'#13#10
else begin
Selection.StartPos :=
SendMessage(RichEdit.Handle, EM_LINEINDEX, Index - 1, 0);
if Selection.StartPos < 0 then Exit;
L := SendMessage(RichEdit.Handle, EM_LINELENGTH, Selection.StartPos, 0);
if L = 0 then Exit;
Inc(Selection.StartPos, L);
Fmt := #13#10'%s';
end;
Selection.EndPos := Selection.StartPos;
SendMessage(RichEdit.Handle, EM_SETSEL, Selection.StartPos, Selection.EndPos);
Str := Format(Fmt, [S]);
SendMessage(RichEdit.Handle, EM_REPLACESEL, 0, LongInt(PChar(Str)));
if RichEdit.SelStart <> (Selection.EndPos + Length(Str)) then
raise EOutOfResources.CreateRes(sRichEditInsertError);
end;
end;
procedure TRichEditStrings.Delete(Index: Integer);
const
Empty: PChar = '';
var
Selection: TSelection;
begin
if Index < 0 then Exit;
Selection.StartPos := SendMessage(RichEdit.Handle, EM_LINEINDEX, Index, 0);
if Selection.StartPos <> -1 then
begin
Selection.EndPos := SendMessage(RichEdit.Handle, EM_LINEINDEX, Index + 1, 0);
if Selection.EndPos = -1 then
Selection.EndPos := Selection.StartPos +
SendMessage(RichEdit.Handle, EM_LINELENGTH, Selection.StartPos, 0);
SendMessage(RichEdit.Handle, EM_SETSEL, Selection.StartPos, Selection.EndPos);
SendMessage(RichEdit.Handle, EM_REPLACESEL, 0, Longint(Empty));
end;
end;
procedure TRichEditStrings.Clear;
begin
RichEdit.Clear;
end;
procedure TRichEditStrings.SetUpdateState(Updating: Boolean);
begin
SendMessage(RichEdit.Handle, WM_SETREDRAW, Ord(not Updating), 0);
if not Updating then RichEdit.Refresh;
end;
function AdjustLineBreaks(Dest, Source: PChar): Integer; assembler;
asm
PUSH ESI
PUSH EDI
MOV EDI,EAX
MOV ESI,EDX
MOV EDX,EAX
CLD
@@1: LODSB
@@2: OR AL,AL
JE @@4
CMP AL,0AH
JE @@3
STOSB
CMP AL,0DH
JNE @@1
MOV AL,0AH
STOSB
LODSB
CMP AL,0AH
JE @@1
JMP @@2
@@3: MOV EAX,0A0DH
STOSW
JMP @@1
@@4: STOSB
LEA EAX,[EDI-1]
SUB EAX,EDX
POP EDI
POP ESI
end;
function StreamSave(dwCookie: Longint; pbBuff: PByte;
cb: Longint; var pcb: Longint): Longint; stdcall;
var
StreamInfo: PRichEditStreamInfo;
begin
Result := NoError;
StreamInfo := PRichEditStreamInfo(Pointer(dwCookie));
try
pcb := 0;
if StreamInfo^.Converter <> nil then
pcb := StreamInfo^.Converter.ConvertWriteStream(StreamInfo^.Stream, PChar(pbBuff), cb);
except
Result := WriteError;
end;
end;
function StreamLoad(dwCookie: Longint; pbBuff: PByte;
cb: Longint; var pcb: Longint): Longint; stdcall;
var
Buffer, pBuff: PChar;
StreamInfo: PRichEditStreamInfo;
begin
Result := NoError;
StreamInfo := PRichEditStreamInfo(Pointer(dwCookie));
Buffer := StrAlloc(cb + 1);
try
cb := cb div 2;
pcb := 0;
pBuff := Buffer + cb;
try
if StreamInfo^.Converter <> nil then
pcb := StreamInfo^.Converter.ConvertReadStream(StreamInfo^.Stream, pBuff, cb);
if pcb > 0 then
begin
pBuff[pcb] := #0;
if pBuff[pcb - 1] = #13 then pBuff[pcb - 1] := #0;
pcb := AdjustLineBreaks(Buffer, pBuff);
Move(Buffer^, pbBuff^, pcb);
end;
except
Result := ReadError;
end;
finally
StrDispose(Buffer);
end;
end;
procedure TRichEditStrings.LoadFromStream(Stream: TStream);
var
EditStream: TEditStream;
Position: Longint;
TextType: Longint;
StreamInfo: TRichEditStreamInfo;
Converter: TConversion;
begin
StreamInfo.Stream := Stream;
if FConverter <> nil then
Converter := FConverter else
Converter := RichEdit.DefaultConverter.Create;
StreamInfo.Converter := Converter;
try
with EditStream do
begin
dwCookie := LongInt(Pointer(@StreamInfo));
pfnCallBack := @StreamLoad;
dwError := 0;
end;
Position := Stream.Position;
if PlainText then TextType := SF_TEXT
else TextType := SF_RTF;
SendMessage(RichEdit.Handle, EM_STREAMIN, TextType, Longint(@EditStream));
if (TextType = SF_RTF) and (EditStream.dwError <> 0) then
begin
Stream.Position := Position;
if PlainText then TextType := SF_RTF
else TextType := SF_TEXT;
SendMessage(RichEdit.Handle, EM_STREAMIN, TextType, Longint(@EditStream));
if EditStream.dwError <> 0 then
raise EOutOfResources.CreateRes(sRichEditLoadFail);
end;
finally
if FConverter = nil then Converter.Free;
end;
end;
procedure TRichEditStrings.SaveToStream(Stream: TStream);
var
EditStream: TEditStream;
TextType: Longint;
StreamInfo: TRichEditStreamInfo;
Converter: TConversion;
begin
if FConverter <> nil then
Converter := FConverter else
Converter := RichEdit.DefaultConverter.Create;
StreamInfo.Stream := Stream;
StreamInfo.Converter := Converter;
try
with EditStream do
begin
dwCookie := LongInt(Pointer(@StreamInfo));
pfnCallBack := @StreamSave;
dwError := 0;
end;
if PlainText then TextType := SF_TEXT
else TextType := SF_RTF;
SendMessage(RichEdit.Handle, EM_STREAMOUT, TextType, Longint(@EditStream));
if EditStream.dwError <> 0 then
raise EOutOfResources.CreateRes(sRichEditSaveFail);
finally
if FConverter = nil then Converter.Free;
end;
end;
procedure TRichEditStrings.LoadFromFile(const FileName: string);
var
Ext: string;
Convert: PConversionFormat;
begin
Ext := AnsiLowerCaseFileName(Copy(ExtractFileExt(Filename), 2, Maxint));
Convert := ConversionFormatList;
while Convert <> nil do
with Convert^ do
if Extension <> Ext then Convert := Next
else Break;
if Convert = nil then
Convert := @TextConversionFormat;
FConverter := Convert^.ConversionClass.Create;
try
inherited LoadFromFile(FileName);
except
FConverter.Free;
FConverter := nil;
raise;
end;
end;
procedure TRichEditStrings.SaveToFile(const FileName: string);
var
Ext: string;
Convert: PConversionFormat;
begin
Ext := AnsiLowerCaseFileName(Copy(ExtractFileExt(Filename), 2, Maxint));
Convert := ConversionFormatList;
while Convert <> nil do
with Convert^ do
if Extension <> Ext then Convert := Next
else Break;
if Convert = nil then
Convert := @TextConversionFormat;
FConverter := Convert^.ConversionClass.Create;
try
inherited SaveToFile(FileName);
except
FConverter.Free;
FConverter := nil;
raise;
end;
end;
{ TRichEdit }
constructor TCustomRichEdit.Create(AOwner: TComponent);
var
DC: HDC;
begin
inherited Create(AOwner);
FSelAttributes := TTextAttributes.Create(Self, atSelected);
FDefAttributes := TTextAttributes.Create(Self, atDefaultText);
FParagraph := TParaAttributes.Create(Self);
FRichEditStrings := TRichEditStrings.Create;
TRichEditStrings(FRichEditStrings).RichEdit := Self;
TabStop := True;
Width := 185;
Height := 89;
AutoSize := False;
FHideSelection := True;
HideScrollBars := True;
DC := GetDC(0);
FScreenLogPixels := GetDeviceCaps(DC, LOGPIXELSY);
DefaultConverter := TConversion;
ReleaseDC(0, DC);
end;
destructor TCustomRichEdit.Destroy;
begin
FSelAttributes.Free;
FDefAttributes.Free;
FParagraph.Free;
FRichEditStrings.Free;
FMemStream.Free;
inherited Destroy;
end;
procedure TCustomRichEdit.CreateParams(var Params: TCreateParams);
const
RichEditModuleName = 'RICHED32.DLL';
HideScrollBars: array[Boolean] of Longint = (ES_DISABLENOSCROLL, 0);
HideSelections: array[Boolean] of Longint = (ES_NOHIDESEL, 0);
var
OldError: Longint;
begin
OldError := SetErrorMode(SEM_NOOPENFILEERRORBOX);
FLibHandle := LoadLibrary(RichEditModuleName);
if FLibHandle < HINSTANCE_ERROR then FLibHandle := 0;
SetErrorMode(OldError);
inherited CreateParams(Params);
CreateSubClass(Params, 'RICHEDIT');
with Params do
Style := Style or HideScrollBars[FHideScrollBars] or
HideSelections[HideSelection];
end;
procedure TCustomRichEdit.CreateWnd;
var
Plain: Boolean;
Format: TCharFormat;
begin
inherited CreateWnd;
FillChar(Format, SizeOf(TCharFormat), 0);
Format.cbSize := SizeOf(TCharFormat);
with Format do
begin
dwMask := CFM_CHARSET;
bCharSet := GetDefFontCharset;
end;
SendMessage(Handle, EM_SETCHARFORMAT, SCF_DEFAULT, LPARAM(@Format));
SendMessage(Handle, EM_SETEVENTMASK, 0,
ENM_CHANGE or ENM_SELCHANGE or ENM_REQUESTRESIZE or
ENM_PROTECTED);
SendMessage(Handle, EM_SETBKGNDCOLOR, 0, ColorToRGB(Color));
if FMemStream <> nil then
begin
Plain := PlainText;
PlainText := False;
try
Lines.LoadFromStream(FMemStream);
FMemStream.Free;
FMemStream := nil;
finally
PlainText := Plain;
end;
end;
Modified := FModified;
end;
procedure TCustomRichEdit.DestroyWnd;
var
Plain: Boolean;
begin
FModified := Modified;
FMemStream := TMemoryStream.Create;
Plain := PlainText;
PlainText := False;
try
Lines.SaveToStream(FMemStream);
FMemStream.Position := 0;
finally
PlainText := Plain;
end;
inherited DestroyWnd;
end;
procedure TCustomRichEdit.WMNCDestroy(var Message: TWMNCDestroy);
begin
inherited;
if FLibHandle <> 0 then FreeLibrary(FLibHandle);
end;
procedure TCustomRichEdit.WMSetFont(var Message: TWMSetFont);
begin
FDefAttributes.Assign(Font);
end;
procedure TCustomRichEdit.CMFontChanged(var Message: TMessage);
begin
FDefAttributes.Assign(Font);
end;
procedure TCustomRichEdit.SetHideScrollBars(Value: Boolean);
begin
if HideScrollBars <> Value then
begin
FHideScrollBars := value;
RecreateWnd;
end;
end;
procedure TCustomRichEdit.SetHideSelection(Value: Boolean);
begin
if HideSelection <> Value then
begin
FHideSelection := Value;
SendMessage(Handle, EM_HIDESELECTION, Ord(HideSelection), LongInt(True));
end;
end;
procedure TCustomRichEdit.SetSelAttributes(Value: TTextAttributes);
begin
SelAttributes.Assign(Value);
end;
procedure TCustomRichEdit.SetDefAttributes(Value: TTextAttributes);
begin
DefAttributes.Assign(Value);
end;
function TCustomRichEdit.GetPlainText: Boolean;
begin
Result := TRichEditStrings(Lines).PlainText;
end;
procedure TCustomRichEdit.SetPlainText(Value: Boolean);
begin
TRichEditStrings(Lines).PlainText := Value;
end;
procedure TCustomRichEdit.CMColorChanged(var Message: TMessage);
begin
inherited;
SendMessage(Handle, EM_SETBKGNDCOLOR, 0, ColorToRGB(Color))
end;
procedure TCustomRichEdit.SetRichEditStrings(Value: TStrings);
begin
FRichEditStrings.Assign(Value);
end;
procedure TCustomRichEdit.Print(const Caption: string);
var
Range: TFormatRange;
LastChar, MaxLen, LogX, LogY, OldMap: Integer;
begin
FillChar(Range, SizeOf(TFormatRange), 0);
with Printer, Range do
begin
BeginDoc;
hdc := Handle;
hdcTarget := hdc;
LogX := GetDeviceCaps(Handle, LOGPIXELSX);
LogY := GetDeviceCaps(Handle, LOGPIXELSY);
if IsRectEmpty(PageRect) then
begin
rc.right := PageWidth * 1440 div LogX;
rc.bottom := PageHeight * 1440 div LogY;
end
else begin
rc.left := PageRect.Left * 1440 div LogX;
rc.top := PageRect.Top * 1440 div LogY;
rc.right := PageRect.Right * 1440 div LogX;
rc.bottom := PageRect.Bottom * 1440 div LogY;
end;
rcPage := rc;
Title := Caption;
LastChar := 0;
MaxLen := GetTextLen;
chrg.cpMax := -1;
// ensure printer DC is in text map mode
OldMap := SetMapMode(hdc, MM_TEXT);
SendMessage(Handle, EM_FORMATRANGE, 0, 0); // flush buffer
try
repeat
chrg.cpMin := LastChar;
LastChar := SendMessage(Self.Handle, EM_FORMATRANGE, 1, Longint(@Range));
if (LastChar < MaxLen) and (LastChar <> -1) then NewPage;
until (LastChar >= MaxLen) or (LastChar = -1);
EndDoc;
finally
SendMessage(Handle, EM_FORMATRANGE, 0, 0); // flush buffer
SetMapMode(hdc, OldMap); // restore previous map mode
end;
end;
end;
var
Painting: Boolean = False;
procedure TCustomRichEdit.WMPaint(var Message: TWMPaint);
var
R, R1: TRect;
begin
if GetUpdateRect(Handle, R, True) then
begin
with ClientRect do R1 := Rect(Right - 3, Top, Right, Bottom);
if IntersectRect(R, R, R1) then InvalidateRect(Handle, @R1, True);
end;
if Painting then
Invalidate
else begin
Painting := True;
try
inherited;
finally
Painting := False;
end;
end;
end;
procedure TCustomRichEdit.WMSetCursor(var Message: TWMSetCursor);
var
P: TPoint;
begin
inherited;
if Message.Result = 0 then
begin
Message.Result := 1;
GetCursorPos(P);
with PointToSmallPoint(P) do
case Perform(WM_NCHITTEST, 0, MakeLong(X, Y)) of
HTVSCROLL,
HTHSCROLL:
Windows.SetCursor(Screen.Cursors[crArrow]);
HTCLIENT:
Windows.SetCursor(Screen.Cursors[crIBeam]);
end;
end;
end;
procedure TCustomRichEdit.CNNotify(var Message: TWMNotify);
begin
with Message.NMHdr^ do
case code of
EN_SELCHANGE: SelectionChange;
EN_REQUESTRESIZE: RequestSize(PReqSize(Pointer(Message.NMHdr))^.rc);
EN_SAVECLIPBOARD:
with PENSaveClipboard(Pointer(Message.NMHdr))^ do
if not SaveClipboard(cObjectCount, cch) then Message.Result := 1;
EN_PROTECTED:
with PENProtected(Pointer(Message.NMHdr))^.chrg do
if not ProtectChange(cpMin, cpMax) then Message.Result := 1;
end;
end;
function TCustomRichEdit.SaveClipboard(NumObj, NumChars: Integer): Boolean;
begin
Result := True;
if Assigned(OnSaveClipboard) then OnSaveClipboard(Self, NumObj, NumChars, Result);
end;
function TCustomRichEdit.ProtectChange(StartPos, EndPos: Integer): Boolean;
begin
Result := False;
if Assigned(OnProtectChange) then OnProtectChange(Self, StartPos, EndPos, Result);
end;
procedure TCustomRichEdit.SelectionChange;
begin
if Assigned(OnSelectionChange) then OnSelectionChange(Self);
end;
procedure TCustomRichEdit.RequestSize(const Rect: TRect);
begin
if Assigned(OnResizeRequest) then OnResizeRequest(Self, Rect);
end;
function TCustomRichEdit.FindText(const SearchStr: string;
StartPos, Length: Integer; Options: TSearchTypes): Integer;
var
Find: TFindText;
Flags: Integer;
begin
with Find.chrg do
begin
cpMin := StartPos;
cpMax := cpMin + Length;
end;
Flags := 0;
if stWholeWord in Options then Flags := Flags or FT_WHOLEWORD;
if stMatchCase in Options then Flags := Flags or FT_MATCHCASE;
Find.lpstrText := PChar(SearchStr);
Result := SendMessage(Handle, EM_FINDTEXT, Flags, LongInt(@Find));
end;
procedure AppendConversionFormat(const Ext: string; AClass: TConversionClass);
var
NewRec: PConversionFormat;
begin
New(NewRec);
with NewRec^ do
begin
Extension := AnsiLowerCaseFileName(Ext);
ConversionClass := AClass;
Next := ConversionFormatList;
end;
ConversionFormatList := NewRec;
end;
class procedure TCustomRichEdit.RegisterConversionFormat(const AExtension: string;
AConversionClass: TConversionClass);
begin
AppendConversionFormat(AExtension, AConversionClass);
end;
{ TUpDown }
constructor TCustomUpDown.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Width := GetSystemMetrics(SM_CXVSCROLL);
Height := GetSystemMetrics(SM_CYVSCROLL);
Height := Height + (Height div 2);
FArrowKeys := True;
FMax := 100;
FIncrement := 1;
FAlignButton := udRight;
FOrientation := udVertical;
FThousands := True;
ControlStyle := ControlStyle - [csDoubleClicks];
end;
procedure TCustomUpDown.CreateParams(var Params: TCreateParams);
begin
InitCommonControls;
inherited CreateParams(Params);
with Params do
begin
Style := Style or UDS_SETBUDDYINT;
if FAlignButton = udRight then Style := Style or UDS_ALIGNRIGHT
else Style := Style or UDS_ALIGNLEFT;
if FOrientation = udHorizontal then Style := Style or UDS_HORZ;
if FArrowKeys then Style := Style or UDS_ARROWKEYS;
if not FThousands then Style := Style or UDS_NOTHOUSANDS;
if FWrap then Style := Style or UDS_WRAP;
end;
CreateSubClass(Params, UPDOWN_CLASS);
Params.WindowClass.style := Params.WindowClass.style or CS_DBLCLKS;
end;
procedure TCustomUpDown.CreateWnd;
var
OrigWidth: Integer;
AccelArray: array [0..0] of TUDAccel;
begin
OrigWidth := Width; { control resizes width - disallowing user to set width }
inherited CreateWnd;
Width := OrigWidth;
SendMessage(Handle, UDM_SETRANGE, 0, MakeLong(FMax, FMin));
if SysLocale.PriLangID <> LANG_JAPANESE then
SendMessage(Handle, UDM_SETPOS, 0, MakeLong(FPosition, 0));
SendMessage(Handle, UDM_GETACCEL, 1, Longint(@AccelArray));
AccelArray[0].nInc := FIncrement;
SendMessage(Handle, UDM_SETACCEL, 1, Longint(@AccelArray));
if FAssociate <> nil then
begin
UndoAutoResizing(FAssociate);
SendMessage(Handle, UDM_SETBUDDY, FAssociate.Handle, 0);
if SysLocale.PriLangID = LANG_JAPANESE then
SendMessage(Handle, UDM_SETPOS, 0, MakeLong(FPosition, 0));
end;
end;
procedure TCustomUpDown.WMVScroll(var Message: TWMVScroll);
begin
inherited;
if Message.ScrollCode = SB_THUMBPOSITION then
begin
if Message.Pos > FPosition then Click(btNext)
else if Message.Pos < FPosition then Click(btPrev);
FPosition := Message.Pos;
end;
end;
procedure TCustomUpDown.WMHScroll(var Message: TWMHScroll);
begin
inherited;
if Message.ScrollCode = SB_THUMBPOSITION then
begin
if Message.Pos > FPosition then Click(btNext)
else if Message.Pos < FPosition then Click(btPrev);
FPosition := Message.Pos;
end;
end;
function TCustomUpDown.CanChange: Boolean;
begin
Result := True;
if Assigned(FOnChanging) then
FOnChanging(Self, Result);
end;
procedure TCustomUpDown.CNNotify(var Message: TWMNotify);
begin
with Message.NMHdr^ do
begin
case code of
UDN_DELTAPOS: LongBool(Message.Result) := not CanChange;
end;
end;
end;
procedure TCustomUpDown.Click(Button: TUDBtnType);
begin
if Assigned(FOnClick) then FOnClick(Self, Button);
end;
procedure TCustomUpDown.SetAssociate(Value: TWinControl);
var
I: Integer;
function IsClass(ClassType: TClass; const Name: string): Boolean;
begin
Result := True;
while ClassType <> nil do
begin
if ClassType.ClassNameIs(Name) then Exit;
ClassType := ClassType.ClassParent;
end;
Result := False;
end;
begin
for I := 0 to Parent.ControlCount - 1 do
if (Parent.Controls[I] is TCustomUpDown) and (Parent.Controls[I] <> Self) then
if TCustomUpDown(Parent.Controls[I]).Associate = Value then
raise Exception.CreateResFmt(sUDAssociated,
[Value.Name, Parent.Controls[I].Name]);
if FAssociate <> nil then { undo the current associate control }
begin
if HandleAllocated then
SendMessage(Handle, UDM_SETBUDDY, 0, 0);
FAssociate := nil;
end;
if (Value <> nil) and (Value.Parent = Self.Parent) and
not (Value is TCustomUpDown) and
not (Value is TCustomTreeView) and not (Value is TCustomListView) and
not IsClass(Value.ClassType, 'TDBEdit') and
not IsClass(Value.ClassType, 'TDBMemo') then
begin
if HandleAllocated then
begin
UndoAutoResizing(Value);
SendMessage(Handle, UDM_SETBUDDY, Value.Handle, 0);
end;
FAssociate := Value;
if Value is TCustomEdit then
TCustomEdit(Value).Text := IntToStr(FPosition);
end;
end;
procedure TCustomUpDown.UndoAutoResizing(Value: TWinControl);
var
OrigWidth, NewWidth, DeltaWidth: Integer;
OrigLeft, NewLeft, DeltaLeft: Integer;
begin
{ undo Window's auto-resizing }
OrigWidth := Value.Width;
OrigLeft := Value.Left;
SendMessage(Handle, UDM_SETBUDDY, Value.Handle, 0);
NewWidth := Value.Width;
NewLeft := Value.Left;
DeltaWidth := OrigWidth - NewWidth;
DeltaLeft := NewLeft - OrigLeft;
Value.Width := OrigWidth + DeltaWidth;
Value.Left := OrigLeft - DeltaLeft;
end;
procedure TCustomUpDown.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (Operation = opRemove) and (AComponent = FAssociate) then
if HandleAllocated then
begin
SendMessage(Handle, UDM_SETBUDDY, 0, 0);
FAssociate := nil;
end;
end;
function TCustomUpDown.GetPosition: SmallInt;
begin
if HandleAllocated then
begin
Result := LoWord(SendMessage(Handle, UDM_GETPOS, 0, 0));
FPosition := Result;
end
else Result := FPosition;
end;
procedure TCustomUpDown.SetMin(Value: SmallInt);
begin
if Value <> FMin then
begin
FMin := Value;
if HandleAllocated then
SendMessage(Handle, UDM_SETRANGE, 0, MakeLong(FMax, FMin));
end;
end;
procedure TCustomUpDown.SetMax(Value: SmallInt);
begin
if Value <> FMax then
begin
FMax := Value;
if HandleAllocated then
SendMessage(Handle, UDM_SETRANGE, 0, MakeLong(FMax, FMin));
end;
end;
procedure TCustomUpDown.SetIncrement(Value: Integer);
var
AccelArray: array [0..0] of TUDAccel;
begin
if Value <> FIncrement then
begin
FIncrement := Value;
if HandleAllocated then
begin
SendMessage(Handle, UDM_GETACCEL, 1, Longint(@AccelArray));
AccelArray[0].nInc := Value;
SendMessage(Handle, UDM_SETACCEL, 1, Longint(@AccelArray));
end;
end;
end;
procedure TCustomUpDown.SetPosition(Value: SmallInt);
begin
if Value <> FPosition then
begin
FPosition := Value;
if (csDesigning in ComponentState) and (FAssociate <> nil) then
if FAssociate is TCustomEdit then
TCustomEdit(FAssociate).Text := IntToStr(FPosition);
if HandleAllocated then
SendMessage(Handle, UDM_SETPOS, 0, MakeLong(FPosition, 0));
end;
end;
procedure TCustomUpDown.SetOrientation(Value: TUDOrientation);
begin
if Value <> FOrientation then
begin
FOrientation := Value;
if ComponentState * [csLoading, csUpdating] = [] then
SetBounds(Left, Top, Height, Width);
if HandleAllocated then
SendMessage(Handle, UDM_SETBUDDY, 0, 0);
RecreateWnd;
end;
end;
procedure TCustomUpDown.SetAlignButton(Value: TUDAlignButton);
begin
if Value <> FAlignButton then
begin
FAlignButton := Value;
if HandleAllocated then
SendMessage(Handle, UDM_SETBUDDY, 0, 0);
RecreateWnd;
end;
end;
procedure TCustomUpDown.SetArrowKeys(Value: Boolean);
begin
if Value <> FArrowKeys then
begin
FArrowKeys := Value;
if HandleAllocated then
SendMessage(Handle, UDM_SETBUDDY, 0, 0);
RecreateWnd;
end;
end;
procedure TCustomUpDown.SetThousands(Value: Boolean);
begin
if Value <> FThousands then
begin
FThousands := Value;
if HandleAllocated then
SendMessage(Handle, UDM_SETBUDDY, 0, 0);
RecreateWnd;
end;
end;
procedure TCustomUpDown.SetWrap(Value: Boolean);
begin
if Value <> FWrap then
begin
FWrap := Value;
if HandleAllocated then
SendMessage(Handle, UDM_SETBUDDY, 0, 0);
RecreateWnd;
end;
end;
{ THotKey }
constructor TCustomHotKey.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Width := 121;
Height := 25;
TabStop := True;
ParentColor := False;
FAutoSize := True;
FInvalidKeys := [hcNone, hcShift];
FModifiers := [hkAlt];
FHotKey := $0041; // default - 'Alt+A'
AdjustHeight;
end;
procedure TCustomHotKey.CreateParams(var Params: TCreateParams);
begin
InitCommonControls;
inherited CreateParams(Params);
CreateSubClass(Params, HOTKEYCLASS);
end;
procedure TCustomHotKey.CreateWnd;
begin
inherited CreateWnd;
SendMessage(Handle, HKM_SETRULES, Byte(FInvalidKeys), MakeLong(Byte(FModifiers), 0));
SendMessage(Handle, HKM_SETHOTKEY, MakeWord(Byte(FHotKey), Byte(FModifiers)), 0);
end;
procedure TCustomHotKey.SetAutoSize(Value: Boolean);
begin
if FAutoSize <> Value then
begin
FAutoSize := Value;
UpdateHeight;
end;
end;
procedure TCustomHotKey.SetModifiers(Value: THKModifiers);
begin
if Value <> FModifiers then
begin
FModifiers := Value;
SendMessage(Handle, HKM_SETRULES, Byte(FInvalidKeys), MakeLong(Byte(Value), 0));
SendMessage(Handle, HKM_SETHOTKEY, MakeWord(Byte(FHotKey), Byte(FModifiers)), 0);
end;
end;
procedure TCustomHotKey.SetInvalidKeys(Value: THKInvalidKeys);
begin
if Value <> FInvalidKeys then
begin
FInvalidKeys := Value;
SendMessage(Handle, HKM_SETRULES, Byte(Value), MakeLong(Byte(FModifiers), 0));
SendMessage(Handle, HKM_SETHOTKEY, MakeWord(Byte(FHotKey), Byte(FModifiers)), 0);
end;
end;
function TCustomHotKey.GetHotKey: TShortCut;
var
HK: Longint;
begin
HK := SendMessage(Handle, HKM_GETHOTKEY, 0, 0);
Result := HotKeyToShortCut(HK);
end;
procedure TCustomHotKey.SetHotKey(Value: TShortCut);
begin
ShortCutToHotKey(Value);
SendMessage(Handle, HKM_SETHOTKEY, MakeWord(Byte(FHotKey), Byte(FModifiers)), 0);
end;
procedure TCustomHotKey.UpdateHeight;
begin
if FAutoSize then
begin
ControlStyle := ControlStyle + [csFixedHeight];
AdjustHeight;
end else
ControlStyle := ControlStyle - [csFixedHeight];
end;
procedure TCustomHotKey.AdjustHeight;
var
DC: HDC;
SaveFont: HFont;
I: Integer;
SysMetrics, Metrics: TTextMetric;
begin
DC := GetDC(0);
GetTextMetrics(DC, SysMetrics);
SaveFont := SelectObject(DC, Font.Handle);
GetTextMetrics(DC, Metrics);
SelectObject(DC, SaveFont);
ReleaseDC(0, DC);
if NewStyleControls then
begin
if Ctl3D then I := 8 else I := 6;
I := GetSystemMetrics(SM_CYBORDER) * I;
end else
begin
I := SysMetrics.tmHeight;
if I > Metrics.tmHeight then I := Metrics.tmHeight;
I := I div 4 + GetSystemMetrics(SM_CYBORDER) * 4;
end;
Height := Metrics.tmHeight + I;
end;
procedure TCustomHotKey.ShortCutToHotKey(Value: TShortCut);
begin
FHotKey := Value and not (scShift + scCtrl + scAlt);
FModifiers := [];
if Value and scShift <> 0 then Include(FModifiers, hkShift);
if Value and scCtrl <> 0 then Include(FModifiers, hkCtrl);
if Value and scAlt <> 0 then Include(FModifiers, hkAlt);
end;
function TCustomHotKey.HotKeyToShortCut(Value: Longint): TShortCut;
begin
Byte(FModifiers) := LoWord(HiByte(Value));
FHotKey := LoWord(LoByte(Value));
Result := FHotKey;
if hkShift in FModifiers then Inc(Result, scShift);
if hkCtrl in FModifiers then Inc(Result, scCtrl);
if hkAlt in FModifiers then Inc(Result, scAlt);
end;
{ TListColumn }
constructor TListColumn.Create(Collection: TCollection);
var
Column: TLVColumn;
begin
inherited Create(Collection);
FWidth := 50;
FAlignment := taLeftJustify;
with Column do
begin
mask := LVCF_FMT or LVCF_WIDTH;
fmt := LVCFMT_LEFT;
cx := FWidth;
end;
ListView_InsertColumn(TListColumns(Collection).Owner.Handle, Index, Column);
end;
destructor TListColumn.Destroy;
begin
if TListColumns(Collection).Owner.HandleAllocated then
ListView_DeleteColumn(TListColumns(Collection).Owner.Handle, Index);
inherited Destroy;
end;
procedure TListColumn.DefineProperties(Filer: TFiler);
begin
inherited DefineProperties(Filer);
Filer.DefineProperty('WidthType', ReadData, WriteData,
WidthType <= ColumnTextWidth);
end;
procedure TListColumn.ReadData(Reader: TReader);
begin
with Reader do
begin
ReadListBegin;
Width := TWidth(ReadInteger);
ReadListEnd;
end;
end;
procedure TListColumn.WriteData(Writer: TWriter);
begin
with Writer do
begin
WriteListBegin;
WriteInteger(Ord(WidthType));
WriteListEnd;
end;
end;
procedure TListColumn.DoChange;
var
I: Integer;
begin
for I := 0 to Collection.Count - 1 do
if TListColumn(Collection.Items[I]).WidthType <= ColumnTextWidth then Break;
Changed(I <> Collection.Count);
end;
procedure TListColumn.SetCaption(const Value: string);
begin
if FCaption <> Value then
begin
FCaption := Value;
DoChange;
end;
end;
function TListColumn.GetWidth: TWidth;
var
Column: TLVColumn;
ListView: TCustomListView;
begin
ListView := TListColumns(Collection).Owner;
if ListView.HandleAllocated then
begin
Column.mask := LVCF_WIDTH;
ListView_GetColumn(ListView.Handle, Index, Column);
Result := Column.cx;
if WidthType > ColumnTextWidth then FWidth := Result;
end
else Result := 0;
end;
procedure TListColumn.SetWidth(Value: TWidth);
begin
if Width <> Value then
begin
FWidth := Value;
DoChange;
end;
end;
procedure TListColumn.SetAlignment(Value: TAlignment);
begin
if (Alignment <> Value) and (Index <> 0) then
begin
FAlignment := Value;
Changed(False);
TListColumns(Collection).Owner.Repaint;
end;
end;
procedure TListColumn.Assign(Source: TPersistent);
var
Column: TListColumn;
begin
if Source is TListColumn then
begin
Column := TListColumn(Source);
Alignment := Column.Alignment;
Width := Column.Width;
Caption := Column.Caption;
end
else inherited Assign(Source);
end;
{ TListColumns }
constructor TListColumns.Create(AOwner: TCustomListView);
begin
inherited Create(TListColumn);
FOwner := AOwner;
end;
function TListColumns.GetItem(Index: Integer): TListColumn;
begin
Result := TListColumn(inherited GetItem(Index));
end;
procedure TListColumns.SetItem(Index: Integer; Value: TListColumn);
begin
inherited SetItem(Index, Value);
end;
function TListColumns.Add: TListColumn;
begin
Result := TListColumn(inherited Add);
end;
procedure TListColumns.Update(Item: TCollectionItem);
begin
if Item <> nil then Owner.UpdateColumn(Item.Index)
else Owner.UpdateColumns;
end;
{ TSubItems }
type
TSubItems = class(TStringList)
private
FOwner: TListItem;
procedure SetColumnWidth(Index: Integer);
protected
function GetHandle: HWND;
procedure SetUpdateState(Updating: Boolean); override;
public
constructor Create(AOwner: TListItem);
function Add(const S: string): Integer; override;
procedure Insert(Index: Integer; const S: string); override;
property Handle: HWND read GetHandle;
property Owner: TListItem read FOwner;
end;
constructor TSubItems.Create(AOwner: TListItem);
begin
inherited Create;
FOwner := AOwner;
end;
function TSubItems.GetHandle: HWND;
begin
Result := Owner.Owner.Handle;
end;
procedure TSubItems.SetColumnWidth(Index: Integer);
var
ListView: TCustomListView;
begin
ListView := Owner.ListView;
if ListView.ColumnsShowing and
(ListView.Columns.Count > Index) and
(ListView.Column[Index].WidthType = ColumnTextWidth) then
ListView.UpdateColumn(Index);
end;
function TSubItems.Add(const S: string): Integer;
begin
Result := inherited Add(S);
ListView_SetItemText(Handle, Owner.Index, Count, LPSTR_TEXTCALLBACK);
SetColumnWidth(Count);
end;
procedure TSubItems.Insert(Index: Integer; const S: string);
begin
inherited Insert(Index, S);
ListView_SetItemText(Handle, Owner.Index, Index + 1, LPSTR_TEXTCALLBACK);
SetColumnWidth(Index + 1);
end;
procedure TSubItems.SetUpdateState(Updating: Boolean);
begin
Owner.Owner.SetUpdateState(Updating);
end;
{ TListItem }
constructor TListItem.Create(AOwner: TListItems);
begin
FOwner := AOwner;
FSubItems := TSubItems.Create(Self);
FOverlayIndex := -1;
FStateIndex := -1;
end;
destructor TListItem.Destroy;
begin
FDeleting := True;
if ListView.HandleAllocated then ListView_DeleteItem(Handle, Index);
FSubItems.Free;
inherited Destroy;
end;
function TListItem.GetListView: TCustomListView;
begin
Result := Owner.Owner;
end;
procedure TListItem.Delete;
begin
if not FDeleting then Free;
end;
function TListItem.GetHandle: HWND;
begin
Result := ListView.Handle;
end;
procedure TListItem.MakeVisible(PartialOK: Boolean);
begin
ListView_EnsureVisible(Handle, Index, PartialOK);
end;
function TListItem.GetLeft: Integer;
begin
Result := GetPosition.X;
end;
procedure TListItem.SetLeft(Value: Integer);
begin
SetPosition(Point(Value, 0));
end;
function TListItem.GetTop: Integer;
begin
Result := GetPosition.Y;
end;
procedure TListItem.SetTop(Value: Integer);
begin
SetPosition(Point(0, Value));
end;
procedure TListItem.Update;
begin
ListView_Update(Handle, Index);
end;
procedure TListItem.SetCaption(const Value: string);
begin
FCaption := Value;
ListView_SetItemText(Handle, Index, 0, LPSTR_TEXTCALLBACK);
if ListView.ColumnsShowing and
(ListView.Columns.Count > 0) and
(ListView.Column[0].WidthType <= ColumnTextWidth) then
ListView.UpdateColumns;
if ListView.SortType in [stBoth, stText] then ListView.AlphaSort;
end;
procedure TListItem.SetData(Value: Pointer);
begin
FData := Value;
if ListView.SortType in [stBoth, stData] then ListView.AlphaSort;
end;
function TListItem.EditCaption: Boolean;
begin
Result := ListView_EditLabel(Handle, Index) <> 0;
end;
procedure TListItem.CancelEdit;
begin
ListView_EditLabel(Handle, -1);
end;
function TListItem.GetState(Index: Integer): Boolean;
var
Mask: Integer;
begin
case Index of
0: Mask := LVIS_CUT;
1: Mask := LVIS_DROPHILITED;
2: Mask := LVIS_FOCUSED;
3: Mask := LVIS_SELECTED;
end;
Result := ListView_GetItemState(Handle, Self.Index, Mask) and Mask <> 0;
end;
procedure TListItem.SetState(Index: Integer; State: Boolean);
var
Mask: Integer;
Data: Integer;
begin
case Index of
0: Mask := LVIS_CUT;
1: Mask := LVIS_DROPHILITED;
2: Mask := LVIS_FOCUSED;
3: Mask := LVIS_SELECTED;
end;
if State then Data := Mask
else Data := 0;
ListView_SetItemState(Handle, Self.Index, Data, Mask);
end;
procedure TListItem.SetImage(Index: Integer; Value: Integer);
var
Item: TLVItem;
begin
case Index of
0:
begin
FImageIndex := Value;
with Item do
begin
mask := LVIF_IMAGE;
iImage := I_IMAGECALLBACK;
iItem := Self.Index;
iSubItem := 0;
end;
ListView_SetItem(Handle, Item);
end;
1:
begin
FOverlayIndex := Value;
ListView_SetItemState(Handle, Self.Index,
IndexToOverlayMask(OverlayIndex + 1), LVIS_OVERLAYMASK);
end;
2:
begin
FStateIndex := Value;
ListView_SetItemState(Handle, Self.Index,
IndexToStateImageMask(StateIndex + 1), LVIS_STATEIMAGEMASK);
end;
end;
ListView.UpdateItems(Self.Index, Self.Index);
end;
procedure TListItem.Assign(Source: TPersistent);
begin
if Source is TListItem then
with Source as TListItem do
begin
Self.Caption := Caption;
Self.Data := Data;
Self.ImageIndex := ImageIndex;
Self.OverlayIndex := OverlayIndex;
Self.StateIndex := StateIndex;
Self.SubItems := SubItems;
end
else inherited Assign(Source);
end;
function TListItem.IsEqual(Item: TListItem): Boolean;
begin
Result := (Caption = Item.Caption) and (Data = Item.Data);
end;
procedure TListItem.SetSubItems(Value: TStrings);
begin
if Value <> nil then FSubItems.Assign(Value);
end;
function TListItem.GetIndex: Integer;
begin
Result := Owner.IndexOf(Self);
end;
function TListItem.GetPosition: TPoint;
begin
ListView_GetItemPosition(Handle, Index, Result);
end;
procedure TListItem.SetPosition(const Value: TPoint);
begin
if ListView.ViewStyle in [vsSmallIcon, vsIcon] then
ListView_SetItemPosition32(Handle, Index, Value.X, Value.Y);
end;
function TListItem.DisplayRect(Code: TDisplayCode): TRect;
const
Codes: array[TDisplayCode] of Longint = (LVIR_BOUNDS, LVIR_ICON, LVIR_LABEL,
LVIR_SELECTBOUNDS);
begin
ListView_GetItemRect(Handle, Index, Result, Codes[Code]);
end;
{ TListItems }
type
PItemHeader = ^TItemHeader;
TItemHeader = packed record
Size, Count: Integer;
Items: record end;
end;
PItemInfo = ^TItemInfo;
TItemInfo = packed record
ImageIndex: Integer;
StateIndex: Integer;
OverlayIndex: Integer;
SubItemCount: Integer;
Data: Pointer;
Caption: string[255];
end;
ShortStr = string[255];
PShortStr = ^ShortStr;
constructor TListItems.Create(AOwner: TCustomListView);
begin
inherited Create;
FOwner := AOwner;
end;
destructor TListItems.Destroy;
begin
Clear;
inherited Destroy;
end;
function TListItems.Add: TListItem;
begin
Result := Owner.CreateListItem;
ListView_InsertItem(Handle, CreateItem(Count, Result));
end;
function TListItems.Insert(Index: Integer): TListItem;
begin
Result := Owner.CreateListItem;
ListView_InsertItem(Handle, CreateItem(Index, Result));
end;
function TListItems.GetCount: Integer;
begin
if Owner.HandleAllocated then Result := ListView_GetItemCount(Handle)
else Result := 0;
end;
function TListItems.GetHandle: HWND;
begin
Result := Owner.Handle;
end;
function TListItems.GetItem(Index: Integer): TListItem;
var
Item: TLVItem;
begin
Result := nil;
if Owner.HandleAllocated then
begin
with Item do
begin
mask := LVIF_PARAM;
iItem := Index;
iSubItem := 0;
end;
if ListView_GetItem(Handle, Item) then Result := TListItem(Item.lParam);
end;
end;
function TListItems.IndexOf(Value: TListItem): Integer;
var
Info: TLVFindInfo;
begin
with Info do
begin
flags := LVFI_PARAM;
lParam := Integer(Value);
end;
Result := ListView_FindItem(Handle, -1, Info);
end;
procedure TListItems.SetItem(Index: Integer; Value: TListItem);
begin
Item[Index].Assign(Value);
end;
procedure TListItems.Clear;
begin
if Owner.HandleAllocated then ListView_DeleteAllItems(Handle);
end;
procedure TListItems.BeginUpdate;
begin
if FUpdateCount = 0 then SetUpdateState(True);
Inc(FUpdateCount);
end;
procedure TListItems.SetUpdateState(Updating: Boolean);
begin
if Updating then
begin
SendMessage(Handle, WM_SETREDRAW, 0, 0);
if Owner.ColumnsShowing and Owner.ValidHeaderHandle then
SendMessage(Owner.FHeaderHandle, WM_SETREDRAW, 0, 0);
end
else if FUpdateCount = 0 then
begin
FNoRedraw := True;
try
SendMessage(Handle, WM_SETREDRAW, 1, 0);
Owner.Invalidate;
finally
FNoRedraw := False;
end;
if Owner.ColumnsShowing and Owner.ValidHeaderHandle then
SendMessage(Owner.FHeaderHandle, WM_SETREDRAW, 1, 0);
end;
end;
procedure TListItems.EndUpdate;
begin
Dec(FUpdateCount);
if FUpdateCount = 0 then SetUpdateState(False);
end;
procedure TListItems.Assign(Source: TPersistent);
var
Items: TListItems;
I: Integer;
begin
if Source is TListItems then
begin
Clear;
Items := TListItems(Source);
for I := 0 to Items.Count - 1 do Add.Assign(Items[I]);
end
else inherited Assign(Source);
end;
procedure TListItems.DefineProperties(Filer: TFiler);
function WriteItems: Boolean;
var
I: Integer;
Items: TListItems;
begin
Items := TListItems(Filer.Ancestor);
if (Items = nil) then
Result := Count > 0
else if (Items.Count <> Count) then
Result := True
else
begin
Result := False;
for I := 0 to Count - 1 do
begin
Result := not Item[I].IsEqual(Items[I]);
if Result then Break;
end
end;
end;
begin
inherited DefineProperties(Filer);
Filer.DefineBinaryProperty('Data', ReadData, WriteData, WriteItems);
end;
procedure TListItems.ReadData(Stream: TStream);
var
I, J, Size, L, Len: Integer;
ItemHeader: PItemHeader;
ItemInfo: PItemInfo;
PStr: PShortStr;
begin
Clear;
Stream.ReadBuffer(Size, SizeOf(Integer));
ItemHeader := AllocMem(Size);
try
Stream.ReadBuffer(ItemHeader^.Count, Size - SizeOf(Integer));
ItemInfo := @ItemHeader^.Items;
for I := 0 to ItemHeader^.Count - 1 do
begin
with Add do
begin
Caption := ItemInfo^.Caption;
ImageIndex := ItemInfo^.ImageIndex;
OverlayIndex := ItemInfo^.OverlayIndex;
StateIndex := ItemInfo^.StateIndex;
Data := ItemInfo^.Data;
PStr := @ItemInfo^.Caption;
Inc(Integer(PStr), Length(PStr^) + 1);
Len := 0;
for J := 0 to ItemInfo^.SubItemCount - 1 do
begin
SubItems.Add(PStr^);
L := Length(PStr^);
Inc(Len, L + 1);
Inc(Integer(PStr), L + 1);
end;
end;
Inc(Integer(ItemInfo), SizeOf(TItemInfo) - 255 +
Length(ItemInfo.Caption) + Len);
end;
finally
FreeMem(ItemHeader, Size);
end;
end;
procedure TListItems.WriteData(Stream: TStream);
var
I, J, Size, L, Len: Integer;
ItemHeader: PItemHeader;
ItemInfo: PItemInfo;
PStr: PShortStr;
function GetLength(const S: string): Integer;
begin
Result := Length(S);
if Result > 255 then Result := 255;
end;
begin
Size := SizeOf(TItemHeader);
for I := 0 to Count - 1 do
begin
L := GetLength(Item[I].Caption);
for J := 0 to Item[I].SubItems.Count - 1 do
Inc(L, GetLength(Item[I].SubItems[J]) + 1);
Inc(Size, SizeOf(TItemInfo) - 255 + L);
end;
ItemHeader := AllocMem(Size);
try
ItemHeader^.Size := Size;
ItemHeader^.Count := Count;
ItemInfo := @ItemHeader^.Items;
for I := 0 to Count - 1 do
begin
with Item[I] do
begin
ItemInfo^.Caption := Caption;
ItemInfo^.ImageIndex := ImageIndex;
ItemInfo^.OverlayIndex := OverlayIndex;
ItemInfo^.StateIndex := StateIndex;
ItemInfo^.Data := Data;
ItemInfo^.SubItemCount := SubItems.Count;
PStr := @ItemInfo^.Caption;
Inc(Integer(PStr), Length(ItemInfo^.Caption) + 1);
Len := 0;
for J := 0 to SubItems.Count - 1 do
begin
PStr^ := SubItems[J];
L := Length(PStr^);
Inc(Len, L + 1);
Inc(Integer(PStr), L + 1);
end;
end;
Inc(Integer(ItemInfo), SizeOf(TItemInfo) - 255 +
Length(ItemInfo^.Caption) + Len);
end;
Stream.WriteBuffer(ItemHeader^, Size);
finally
FreeMem(ItemHeader, Size);
end;
end;
procedure TListItems.Delete(Index: Integer);
begin
Item[Index].Delete;
end;
function TListItems.CreateItem(Index: Integer;
ListItem: TListItem): TLVItem;
begin
with Result do
begin
mask := LVIF_PARAM or LVIF_IMAGE;
iItem := Index;
iSubItem := 0;
iImage := I_IMAGECALLBACK;
lParam := Longint(ListItem);
end;
end;
{ TIconOptions }
constructor TIconOptions.Create(AOwner: TCustomListView);
begin
inherited Create;
if AOwner = nil then raise Exception.CreateRes(sInvalidOwner);
FListView := AOwner;
Arrangement := iaTop;
AutoArrange := False;
WrapText := True;
end;
procedure TIconOptions.SetArrangement(Value: TIconArrangement);
begin
if Value <> Arrangement then
begin;
FArrangement := Value;
FListView.RecreateWnd;
{FListView.SetIconArrangement(Value);}
end;
end;
procedure TIconOptions.SetAutoArrange(Value: Boolean);
begin
if Value <> AutoArrange then
begin
FAutoArrange := Value;
FListView.RecreateWnd;
end;
end;
procedure TIconOptions.SetWrapText(Value: Boolean);
begin
if Value <> WrapText then
begin
FWrapText := Value;
FListView.RecreateWnd;
end;
end;
{ TCustomListView }
function DefaultListViewSort(Item1, Item2: TListItem;
lParam: Integer): Integer; stdcall;
begin
with Item1 do
if Assigned(ListView.OnCompare) then
ListView.OnCompare(ListView, Item1, Item2, lParam, Result)
else Result := lstrcmp(PChar(Item1.Caption), PChar(Item2.Caption));
end;
constructor TCustomListView.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
ControlStyle := ControlStyle - [csCaptureMouse] + [csDisplayDragImage];
Width := 250;
Height := 150;
BorderStyle := bsSingle;
ViewStyle := vsIcon;
ParentColor := False;
TabStop := True;
HideSelection := True;
ShowColumnHeaders := True;
ColumnClick := True;
FDragIndex := -1;
FListColumns := TListColumns.Create(Self);
FListItems := TListItems.Create(Self);
FIconOptions := TIconOptions.Create(Self);
FDragImage := TImageList.CreateSize(32, 32);
FEditInstance := MakeObjectInstance(EditWndProc);
FHeaderInstance := MakeObjectInstance(HeaderWndProc);
FLargeChangeLink := TChangeLink.Create;
FLargeChangeLink.OnChange := ImageListChange;
FSmallChangeLink := TChangeLink.Create;
FSmallChangeLink.OnChange := ImageListChange;
FStateChangeLink := TChangeLink.Create;
FStateChangeLink.OnChange := ImageListChange;
end;
destructor TCustomListView.Destroy;
begin
FDragImage.Free;
FListColumns.Free;
FListItems.Free;
FIconOptions.Free;
FMemStream.Free;
FreeObjectInstance(FEditInstance);
if FHeaderHandle <> 0 then
SetWindowLong(FHeaderHandle, GWL_WNDPROC, LongInt(FDefHeaderProc));
FreeObjectInstance(FHeaderInstance);
FLargeChangeLink.Free;
FSmallChangeLink.Free;
FStateChangeLink.Free;
inherited Destroy;
end;
procedure TCustomListView.CreateParams(var Params: TCreateParams);
const
BorderStyles: array[TBorderStyle] of Integer = (0, WS_BORDER);
EditStyles: array[Boolean] of Integer = (LVS_EDITLABELS, 0);
MultiSelections: array[Boolean] of Integer = (LVS_SINGLESEL, 0);
HideSelections: array[Boolean] of Integer = (LVS_SHOWSELALWAYS, 0);
Arrangements: array[TIconArrangement] of Integer = (LVS_ALIGNTOP,
LVS_ALIGNLEFT);
AutoArrange: array[Boolean] of Integer = (0, LVS_AUTOARRANGE);
WrapText: array[Boolean] of Integer = (LVS_NOLABELWRAP, 0);
ViewStyles: array[TViewStyle] of Integer = (LVS_ICON, LVS_SMALLICON,
LVS_LIST, LVS_REPORT);
ShowColumns: array[Boolean] of Integer = (LVS_NOCOLUMNHEADER, 0);
ColumnClicks: array[Boolean] of Integer = (LVS_NOSORTHEADER, 0);
begin
InitCommonControls;
inherited CreateParams(Params);
CreateSubClass(Params, WC_LISTVIEW);
with Params do
begin
Style := Style or WS_CLIPCHILDREN or ViewStyles[ViewStyle] or
BorderStyles[BorderStyle] or Arrangements[IconOptions.Arrangement] or
EditStyles[ReadOnly] or MultiSelections[MultiSelect] or
HideSelections[HideSelection] or
AutoArrange[IconOptions.AutoArrange] or
WrapText[IconOptions.WrapText] or
ShowColumns[ShowColumnHeaders] or
ColumnClicks[ColumnClick] or
LVS_SHAREIMAGELISTS;
if Ctl3D and (FBorderStyle = bsSingle) then
ExStyle := Params.ExStyle or WS_EX_CLIENTEDGE;
end;
end;
procedure TCustomListView.CreateWnd;
begin
inherited CreateWnd;
SetTextBKColor(Color);
SetTextColor(Font.Color);
SetAllocBy(AllocBy);
if FMemStream <> nil then
begin
Items.BeginUpdate;
try
Columns.Clear;
FMemStream.ReadComponentRes(Self);
FMemStream.Destroy;
FMemStream := nil;
Font := Font;
finally
Items.EndUpdate;
end;
end;
if (LargeImages <> nil) and LargeImages.HandleAllocated then
SetImageList(LargeImages.Handle, LVSIL_NORMAL);
if (SmallImages <> nil) and SmallImages.HandleAllocated then
SetImageList(SmallImages.Handle, LVSIL_SMALL);
if (StateImages <> nil) and StateImages.HandleAllocated then
SetImageList(StateImages.Handle, TVSIL_STATE);
end;
procedure TCustomListView.DestroyWnd;
begin
FMemStream := TMemoryStream.Create;
FMemStream.WriteComponentRes(ClassName, Self);
FMemStream.Position := 0;
inherited DestroyWnd;
end;
procedure TCustomListView.SetImageList(Value: HImageList; Flags: Integer);
begin
if HandleAllocated then ListView_SetImageList(Handle, Value, Flags);
end;
procedure TCustomListView.ImageListChange(Sender: TObject);
var
ImageHandle: HImageList;
begin
if HandleAllocated then
begin
ImageHandle := TImageList(Sender).Handle;
if Sender = LargeImages then SetImageList(ImageHandle, LVSIL_NORMAL)
else if Sender = SmallImages then SetImageList(ImageHandle, LVSIL_SMALL)
else if Sender = StateImages then SetImageList(ImageHandle, LVSIL_STATE);
end;
end;
procedure TCustomListView.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if Operation = opRemove then
begin
if AComponent = LargeImages then LargeImages := nil;
if AComponent = SmallImages then SmallImages := nil;
if AComponent = StateImages then StateImages := nil;
end;
end;
procedure TCustomListView.HeaderWndProc(var Message: TMessage);
begin
try
with Message do
begin
case Msg of
WM_NCHITTEST:
with TWMNCHitTest(Message) do
if csDesigning in ComponentState then
begin
Result := Windows.HTTRANSPARENT;
Exit;
end;
WM_NCDESTROY:
begin
Result := CallWindowProc(FDefHeaderProc, FHeaderHandle, Msg, WParam, LParam);
FHeaderHandle := 0;
FDefHeaderProc := nil;
Exit;
end;
end;
Result := CallWindowProc(FDefHeaderProc, FHeaderHandle, Msg, WParam, LParam);
end;
except
Application.HandleException(Self);
end;
end;
procedure TCustomListView.EditWndProc(var Message: TMessage);
begin
try
with Message do
begin
case Msg of
WM_KEYDOWN,
WM_SYSKEYDOWN: if DoKeyDown(TWMKey(Message)) then Exit;
WM_CHAR: if DoKeyPress(TWMKey(Message)) then Exit;
WM_KEYUP,
WM_SYSKEYUP: if DoKeyUp(TWMKey(Message)) then Exit;
CN_KEYDOWN,
CN_CHAR, CN_SYSKEYDOWN,
CN_SYSCHAR:
begin
WndProc(Message);
Exit;
end;
end;
Result := CallWindowProc(FDefEditProc, FEditHandle, Msg, WParam, LParam);
end;
except
Application.HandleException(Self);
end;
end;
procedure TCustomListView.UpdateItems(FirstIndex, LastIndex: Integer);
begin
ListView_RedrawItems(Handle, FirstIndex, LastIndex);
end;
procedure TCustomListView.SetBorderStyle(Value: TBorderStyle);
begin
if BorderStyle <> Value then
begin
FBorderStyle := Value;
RecreateWnd;
end;
end;
procedure TCustomListView.SetColumnClick(Value: Boolean);
begin
if ColumnClick <> Value then
begin
FColumnClick := Value;
RecreateWnd;
end;
end;
procedure TCustomListView.SetMultiSelect(Value: Boolean);
begin
if Value <> MultiSelect then
begin
FMultiSelect := Value;
RecreateWnd;
end;
end;
procedure TCustomListView.SetColumnHeaders(Value: Boolean);
begin
if Value <> ShowColumnHeaders then
begin
FShowColumnHeaders := Value;
RecreateWnd;
end;
end;
procedure TCustomListView.SetTextColor(Value: TColor);
begin
ListView_SetTextColor(Handle, ColorToRGB(Font.Color));
end;
procedure TCustomListView.SetTextBkColor(Value: TColor);
begin
ListView_SetTextBkColor(Handle, ColorToRGB(Color));
end;
procedure TCustomListView.SetAllocBy(Value: Integer);
begin
if AllocBy <> Value then
begin
FAllocBy := Value;
if HandleAllocated then ListView_SetItemCount(Handle, Value);
end;
end;
procedure TCustomListView.CMColorChanged(var Message: TMessage);
begin
inherited;
SetTextBkColor(Color);
end;
procedure TCustomListView.CMCtl3DChanged(var Message: TMessage);
begin
if FBorderStyle = bsSingle then RecreateWnd;
inherited;
end;
procedure TCustomListView.WMNotify(var Message: TWMNotify);
begin
inherited;
if ValidHeaderHandle then
with Message.NMHdr^ do
if (hWndFrom = FHeaderHandle) and (code = HDN_BEGINTRACK) then
with PHDNotify(Pointer(Message.NMHdr))^, PItem^ do
if (Mask and HDI_WIDTH) <> 0 then
Column[Item].Width := cxy;
end;
function TCustomListView.ColumnsShowing: Boolean;
begin
Result := (ViewStyle = vsReport);
end;
function TCustomListView.ValidHeaderHandle: Boolean;
begin
Result := FHeaderHandle <> 0;
end;
procedure TCustomListView.CMFontChanged(var Message: TMessage);
begin
inherited;
if HandleAllocated then
begin
SetTextColor(Font.Color);
if ValidHeaderHandle then
InvalidateRect(FHeaderHandle, nil, True);
end;
end;
procedure TCustomListView.SetHideSelection(Value: Boolean);
begin
if Value <> HideSelection then
begin
FHideSelection := Value;
RecreateWnd;
end;
end;
procedure TCustomListView.SetReadOnly(Value: Boolean);
begin
if Value <> ReadOnly then
begin
FReadOnly := Value;
RecreateWnd;
end;
end;
procedure TCustomListView.SetIconOptions(Value: TIconOptions);
begin
with FIconOptions do
begin
Arrangement := Value.Arrangement;
AutoArrange := Value.AutoArrange;
WrapText := Value.WrapText;
end;
end;
procedure TCustomListView.SetIconArrangement(Value: TIconArrangement);
const
Arrangements: array[TIconArrangement] of Integer = (LVS_ALIGNTOP,
LVS_ALIGNLEFT);
var
Style: Longint;
begin
if HandleAllocated then
begin
Style := GetWindowLong(Handle, GWL_STYLE);
Style := Style and (not LVS_ALIGNMASK);
Style := Style or Arrangements[Value];
SetWindowLong(Handle, GWL_STYLE, Style);
end;
end;
procedure TCustomListView.SetViewStyle(Value: TViewStyle);
const
ViewStyles: array[TViewStyle] of Integer = (LVS_ICON, LVS_SMALLICON,
LVS_LIST, LVS_REPORT);
var
Style: Longint;
begin
if Value <> FViewStyle then
begin
FViewStyle := Value;
if HandleAllocated then
begin
Style := GetWindowLong(Handle, GWL_STYLE);
Style := Style and (not LVS_TYPEMASK);
Style := Style or ViewStyles[FViewStyle];
SetWindowLong(Handle, GWL_STYLE, Style);
UpdateColumns;
case ViewStyle of
vsIcon,
vsSmallIcon:
if IconOptions.Arrangement = iaTop then
Arrange(arAlignTop) else
Arrange(arAlignLeft);
end;
end;
end;
end;
procedure TCustomListView.WMParentNotify(var Message: TWMParentNotify);
begin
with Message do
if (Event = WM_CREATE) and (FHeaderHandle = 0) then
begin
FHeaderHandle := ChildWnd;
FDefHeaderProc := Pointer(GetWindowLong(FHeaderHandle, GWL_WNDPROC));
SetWindowLong(FHeaderHandle, GWL_WNDPROC, LongInt(FHeaderInstance));
end;
inherited;
end;
function TCustomListView.GetItemIndex(Value: TListItem): Integer;
var
I: Integer;
begin
Result := -1;
for I := 0 to Items.Count - 1 do if Items[I] = Value then Break;
if I < Items.Count then Result := I;
end;
function TCustomListView.CreateListItem: TListItem;
begin
Result := TListItem.Create(Items);
end;
function TCustomListView.GetItem(Value: TLVItem): TListItem;
begin
with Value do
if (mask and LVIF_PARAM) <> 0 then Result := TListItem(lParam)
else Result := Items[IItem];
end;
function TCustomListView.GetSelCount: Integer;
begin
Result := ListView_GetSelectedCount(Handle);
end;
procedure TCustomListView.CNNotify(var Message: TWMNotify);
var
Item: TListItem;
I: Integer;
begin
with Message.NMHdr^ do
case code of
LVN_BEGINDRAG:
with PNMListView(Pointer(Message.NMHdr))^ do
FDragIndex := iItem;
LVN_DELETEITEM:
with PNMListView(Pointer(Message.NMHdr))^ do
Delete(TListItem(lParam));
LVN_DELETEALLITEMS:
for I := Items.Count - 1 downto 0 do Delete(Items[I]);
LVN_GETDISPINFO:
begin
Item := GetItem(PLVDispInfo(Pointer(Message.NMHdr))^.item);
with PLVDispInfo(Pointer(Message.NMHdr))^.item do
begin
if (mask and LVIF_TEXT) <> 0 then
if iSubItem = 0 then
StrPLCopy(pszText, Item.Caption, cchTextMax)
else
with Item.SubItems do
if iSubItem <= Count then
StrPLCopy(pszText, Strings[iSubItem - 1], cchTextMax)
else pszText[0] := #0;
if (mask and LVIF_IMAGE) <> 0 then iImage := Item.ImageIndex;
end;
end;
LVN_BEGINLABELEDIT:
begin
Item := GetItem(PLVDispInfo(Pointer(Message.NMHdr))^.item);
if not CanEdit(Item) then Message.Result := 1;
if Message.Result = 0 then
begin
FEditHandle := ListView_GetEditControl(Handle);
FDefEditProc := Pointer(GetWindowLong(FEditHandle, GWL_WNDPROC));
SetWindowLong(FEditHandle, GWL_WNDPROC, LongInt(FEditInstance));
end;
end;
LVN_ENDLABELEDIT:
with PLVDispInfo(Pointer(Message.NMHdr))^ do
if (item.pszText <> nil) and (item.IItem <> -1) then
Edit(item);
LVN_COLUMNCLICK:
with PNMListView(Pointer(Message.NMHdr))^ do
ColClick(Column[iSubItem]);
LVN_INSERTITEM:
with PNMListView(Pointer(Message.NMHdr))^ do
InsertItem(Items[iItem]);
LVN_ITEMCHANGING:
with PNMListView(Pointer(Message.NMHdr))^ do
if not CanChange(Items[iItem], uChanged) then Message.Result := 1;
LVN_ITEMCHANGED:
with PNMListView(Pointer(Message.NMHdr))^ do
Change(Items[iItem], uChanged);
NM_CLICK: FClicked := True;
NM_RCLICK: FRClicked := True;
end;
end;
procedure TCustomListView.ColClick(Column: TListColumn);
begin
if Assigned(FOnColumnClick) then FOnColumnClick(Self, Column);
end;
procedure TCustomListView.InsertItem(Item: TListItem);
begin
if Assigned(FOnInsert) then FOnInsert(Self, Item);
end;
function TCustomListView.CanChange(Item: TListItem; Change: Integer): Boolean;
var
ItemChange: TItemChange;
begin
Result := True;
case Change of
LVIF_TEXT: ItemChange := ctText;
LVIF_IMAGE: ItemChange := ctImage;
LVIF_STATE: ItemChange := ctState;
end;
if Assigned(FOnChanging) then FOnChanging(Self, Item, ItemChange, Result);
end;
procedure TCustomListView.Change(Item: TListItem; Change: Integer);
var
ItemChange: TItemChange;
begin
case Change of
LVIF_TEXT: ItemChange := ctText;
LVIF_IMAGE: ItemChange := ctImage;
LVIF_STATE: ItemChange := ctState;
end;
if Assigned(FOnChange) then FOnChange(Self, Item, ItemChange);
end;
procedure TCustomListView.Delete(Item: TListItem);
begin
if (Item <> nil) and not Item.FProcessedDeleting then
begin
if Assigned(FOnDeletion) then FOnDeletion(Self, Item);
Item.FProcessedDeleting := True;
Item.Delete;
end;
end;
function TCustomListView.CanEdit(Item: TListItem): Boolean;
begin
Result := True;
if Assigned(FOnEditing) then FOnEditing(Self, Item, Result);
end;
procedure TCustomListView.Edit(const Item: TLVItem);
var
S: string;
EditItem: TListItem;
begin
with Item do
begin
S := pszText;
EditItem := GetItem(Item);
if Assigned(FOnEdited) then FOnEdited(Self, EditItem, S);
if EditItem <> nil then EditItem.Caption := S;
end;
end;
function TCustomListView.IsEditing: Boolean;
begin
Result := ListView_GetEditControl(Handle) <> 0;
end;
function TCustomListView.GetDragImages: TCustomImageList;
begin
if SelCount = 1 then
Result := FDragImage else
Result := nil;
end;
procedure TCustomListView.WndProc(var Message: TMessage);
begin
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 if not (((Message.Msg = WM_PAINT) or (Message.Msg = WM_ERASEBKGND)) and
Items.FNoRedraw) then
inherited WndProc(Message);
end;
procedure TCustomListView.DoStartDrag(var DragObject: TDragObject);
var
P, P1: TPoint;
ImageHandle: HImageList;
DragItem: TListItem;
begin
inherited DoStartDrag(DragObject);
FLastDropTarget := nil;
GetCursorPos(P);
P := ScreenToClient(P);
if FDragIndex <> -1 then
DragItem := Items[FDragIndex]
else DragItem := nil;
FDragIndex := -1;
if DragItem = nil then
with P do DragItem := GetItemAt(X, Y);
if DragItem <> nil then
begin
ImageHandle := ListView_CreateDragImage(Handle, DragItem.Index, P1);
if ImageHandle <> 0 then
with FDragImage do
begin
Handle := ImageHandle;
with P, DragItem.DisplayRect(drBounds) do
SetDragImage(0, X - Left , Y - Top);
end;
end;
end;
procedure TCustomListView.DoEndDrag(Target: TObject; X, Y: Integer);
begin
inherited DoEndDrag(Target, X, Y);
FLastDropTarget := nil;
end;
procedure TCustomListView.CMDrag(var Message: TCMDrag);
begin
inherited;
if Message.Result <> 0 then
with Message, DragRec^ do
case DragMessage of
dmDragMove: with ScreenToClient(Pos) do DoDragOver(Source, X, Y);
dmDragLeave:
begin
TDragObject(Source).HideDragImage;
FLastDropTarget := DropTarget;
DropTarget := nil;
Update;
TDragObject(Source).ShowDragImage;
end;
dmDragDrop: FLastDropTarget := nil;
end;
end;
procedure TCustomListView.DoDragOver(Source: TDragObject; X, Y: Integer);
var
Item: TListItem;
Target: TListItem;
begin
Item := GetItemAt(X, Y);
if Item <> nil then
begin
Target := DropTarget;
if (Item <> Target) or (Item = FLastDropTarget) then
begin
FLastDropTarget := nil;
TDragObject(Source).HideDragImage;
if Target <> nil then
Target.DropTarget := False;
Item.DropTarget := True;
Update;
TDragObject(Source).ShowDragImage;
end;
end;
end;
procedure TCustomListView.SetItems(Value: TListItems);
begin
FListItems.Assign(Value);
end;
procedure TCustomListView.SetListColumns(Value: TListColumns);
begin
FListColumns.Assign(Value);
end;
function TCustomListView.CustomSort(SortProc: TLVCompare; lParam: Longint): Boolean;
begin
Result := False;
if HandleAllocated then
begin
if not Assigned(SortProc) then SortProc := @DefaultListViewSort;
Result := ListView_SortItems(Handle, SortProc, lParam);
end;
end;
function TCustomListView.AlphaSort: Boolean;
begin
if HandleAllocated then
Result := ListView_SortItems(Handle, @DefaultListViewSort, 0)
else Result := False;
end;
procedure TCustomListView.SetSortType(Value: TSortType);
begin
if SortType <> Value then
begin
FSortType := Value;
if ((SortType in [stData, stBoth]) and Assigned(OnCompare)) or
(SortType in [stText, stBoth]) then
AlphaSort;
end;
end;
function TCustomListView.GetVisibleRowCount: Integer;
begin
if ViewStyle in [vsReport, vsList] then
Result := ListView_GetCountPerPage(Handle)
else Result := 0;
end;
function TCustomListView.GetViewOrigin: TPoint;
begin
ListView_GetOrigin(Handle, Result);
end;
function TCustomListView.GetTopItem: TListItem;
var
Index: Integer;
begin
Result := nil;
if not (ViewStyle in [vsSmallIcon, vsIcon]) then
begin
Index := ListView_GetTopIndex(Handle);
if Index <> -1 then Result := Items[Index];
end;
end;
function TCustomListView.GetBoundingRect: TRect;
begin
ListView_GetViewRect(Handle, Result);
end;
procedure TCustomListView.Scroll(DX, DY: Integer);
begin
ListView_Scroll(Handle, DX, DY);
end;
procedure TCustomListView.SetLargeImages(Value: TImageList);
begin
if LargeImages <> nil then
LargeImages.UnRegisterChanges(FLargeChangeLink);
FLargeImages := Value;
if LargeImages <> nil then
begin
LargeImages.RegisterChanges(FLargeChangeLink);
SetImageList(LargeImages.Handle, LVSIL_NORMAL)
end
else SetImageList(0, LVSIL_NORMAL);
end;
procedure TCustomListView.SetSmallImages(Value: TImageList);
begin
if SmallImages <> nil then
SmallImages.UnRegisterChanges(FSmallChangeLink);
FSmallImages := Value;
if SmallImages <> nil then
begin
SmallImages.RegisterChanges(FSmallChangeLink);
SetImageList(SmallImages.Handle, LVSIL_SMALL)
end
else SetImageList(0, LVSIL_SMALL);
end;
procedure TCustomListView.SetStateImages(Value: TImageList);
begin
if StateImages <> nil then
StateImages.UnRegisterChanges(FStateChangeLink);
FStateImages := Value;
if StateImages <> nil then
begin
StateImages.RegisterChanges(FStateChangeLink);
SetImageList(StateImages.Handle, LVSIL_STATE)
end
else SetImageList(0, LVSIL_STATE);
end;
function TCustomListView.GetColumnFromIndex(Index: Integer): TListColumn;
begin
Result := FListColumns[Index];
end;
function TCustomListView.FindCaption(StartIndex: Integer; Value: string;
Partial, Inclusive, Wrap: Boolean): TListItem;
const
FullString: array[Boolean] of Integer = (0, LVFI_PARTIAL);
Wraps: array[Boolean] of Integer = (0, LVFI_WRAP);
var
Info: TLVFindInfo;
Index: Integer;
begin
with Info do
begin
flags := LVFI_STRING or FullString[Partial] or Wraps[Wrap];
psz := PChar(Value);
end;
if Inclusive then Dec(StartIndex);
Index := ListView_FindItem(Handle, StartIndex, Info);
if Index <> -1 then Result := Items[Index]
else Result := nil;
end;
function TCustomListView.FindData(StartIndex: Integer; Value: Pointer;
Inclusive, Wrap: Boolean): TListItem;
var
I: Integer;
begin
Result := nil;
if Inclusive then Dec(StartIndex);
for I := StartIndex + 1 to Items.Count - 1 do
if Items[I].Data = Value then Break;
if I <= Items.Count - 1 then Result := Items[I]
else if Wrap then
begin
if Inclusive then Inc(StartIndex);
for I := 0 to StartIndex - 1 do
if Items[I].Data = Value then Break;
if I <= StartIndex then Result := Items[I];
end;
end;
function TCustomListView.GetSelection: TListItem;
begin
Result := GetNextItem(nil, sdAll, [isSelected]);
end;
procedure TCustomListView.SetSelection(Value: TListItem);
var
I: Integer;
begin
if Value <> nil then Value.Selected := True
else begin
Value := Selected;
for I := 0 to SelCount - 1 do
if Value <> nil then
begin
Value.Selected := False;
Value := GetNextItem(Value, sdAll, [isSelected]);
end;
end;
end;
function TCustomListView.GetDropTarget: TListItem;
begin
Result := GetNextItem(nil, sdAll, [isDropHilited]);
if Result = nil then Result := FLastDropTarget;
end;
procedure TCustomListView.SetDropTarget(Value: TListItem);
begin
if HandleAllocated then
if Value <> nil then Value.DropTarget := True
else begin
Value := DropTarget;
if Value <> nil then Value.DropTarget := False;
end;
end;
function TCustomListView.GetFocused: TListItem;
begin
Result := GetNextItem(nil, sdAll, [isFocused]);
end;
procedure TCustomListView.SetFocused(Value: TListItem);
begin
if HandleAllocated then
if Value <> nil then Value.Focused := True
else begin
Value := ItemFocused;
if Value <> nil then Value.Focused := False;
end;
end;
function TCustomListView.GetNextItem(StartItem: TListItem;
Direction: TSearchDirection; States: TItemStates): TListItem;
var
Flags, Index: Integer;
begin
Result := nil;
if HandleAllocated then
begin
Flags := 0;
case Direction of
sdAbove: Flags := LVNI_ABOVE;
sdBelow: Flags := LVNI_BELOW;
sdLeft: Flags := LVNI_TOLEFT;
sdRight: Flags := LVNI_TORIGHT;
sdAll: Flags := LVNI_ALL;
end;
if StartItem <> nil then Index := StartItem.Index
else Index := -1;
if isCut in States then Flags := Flags or LVNI_CUT;
if isDropHilited in States then Flags := Flags or LVNI_DROPHILITED;
if isFocused in States then Flags := Flags or LVNI_FOCUSED;
if isSelected in States then Flags := Flags or LVNI_SELECTED;
Index := ListView_GetNextItem(Handle, Index, Flags);
if Index <> -1 then Result := Items[Index];
end;
end;
function TCustomListView.GetNearestItem(Point: TPoint;
Direction: TSearchDirection): TListItem;
const
Directions: array[TSearchDirection] of Integer = (VK_LEFT, VK_RIGHT,
VK_UP, VK_DOWN, 0);
var
Info: TLVFindInfo;
Index: Integer;
begin
with Info do
begin
flags := LVFI_NEARESTXY;
pt := Point;
vkDirection := Directions[Direction];
end;
Index := ListView_FindItem(Handle, -1, Info);
if Index <> -1 then Result := Items[Index]
else Result := nil;
end;
function TCustomListView.GetItemAt(X, Y: Integer): TListItem;
var
Info: TLVHitTestInfo;
var
Index: Integer;
begin
Result := nil;
if HandleAllocated then
begin
Info.pt := Point(X, Y);
Index := ListView_HitTest(Handle, Info);
if Index <> -1 then Result := Items[Index];
end;
end;
procedure TCustomListView.Arrange(Code: TListArrangement);
const
Codes: array[TListArrangement] of Longint = (LVA_ALIGNBOTTOM, LVA_ALIGNLEFT,
LVA_ALIGNRIGHT, LVA_ALIGNTOP, LVA_DEFAULT, LVA_SNAPTOGRID);
begin
ListView_Arrange(Handle, Codes[Code]);
end;
function TCustomListView.StringWidth(S: string): Integer;
begin
Result := ListView_GetStringWidth(Handle, PChar(S));
end;
procedure TCustomListView.UpdateColumns;
var
I: Integer;
begin
if HandleAllocated then
for I := 0 to Columns.Count - 1 do UpdateColumn(I);
end;
procedure TCustomListView.UpdateColumn(Index: Integer);
var
Column: TLVColumn;
begin
if HandleAllocated then
with Column, Columns.Items[Index] do
begin
mask := LVCF_TEXT or LVCF_FMT;
pszText := PChar(Caption);
if Index <> 0 then
case Alignment of
taLeftJustify: fmt := LVCFMT_LEFT;
taCenter: fmt := LVCFMT_CENTER;
taRightJustify: fmt := LVCFMT_RIGHT;
end
else fmt := LVCFMT_LEFT;
if WidthType > ColumnTextWidth then
begin
mask := mask or LVCF_WIDTH;
cx := FWidth;
ListView_SetColumn(Handle, Index, Column);
end
else begin
ListView_SetColumn(Handle, Index, Column);
if ViewStyle = vsList then
ListView_SetColumnWidth(Handle, -1, WidthType)
else if ViewStyle = vsReport then
ListView_SetColumnWidth(Handle, Index, WidthType);
end;
end;
end;
procedure TCustomListView.WMRButtonDown(var Message: TWMRButtonDown);
var
MousePos: TPoint;
begin
FRClicked := False;
inherited;
if FRClicked then
begin
GetCursorPos(MousePos);
with PointToSmallPoint(ScreenToClient(MousePos)) do
Perform(WM_RBUTTONUP, 0, MakeLong(X, Y));
end;
end;
procedure TCustomListView.WMLButtonDown(var Message: TWMLButtonDown);
var
Item: TListItem;
MousePos: TPoint;
ShiftState: TShiftState;
begin
SetFocus;
ShiftState := KeysToShiftState(Message.Keys);
FClicked := False;
FDragIndex := -1;
inherited;
if (DragMode = dmAutomatic) and MultiSelect then
begin
if not (ssShift in ShiftState) and not (ssCtrl in ShiftState) then
begin
if not FClicked then
begin
Item := GetItemAt(Message.XPos, Message.YPos);
if (Item <> nil) and Item.Selected then
begin
BeginDrag(False);
Exit;
end;
end;
end;
end;
if FClicked then
begin
GetCursorPos(MousePos);
with PointToSmallPoint(ScreenToClient(MousePos)) do
if not Dragging then Perform(WM_LBUTTONUP, 0, MakeLong(X, Y))
else SendMessage(GetCapture, WM_LBUTTONUP, 0, MakeLong(X, Y));
end
else if (DragMode = dmAutomatic) and not (MultiSelect and
((ssShift in ShiftState) or (ssCtrl in ShiftState))) then
begin
Item := GetItemAt(Message.XPos, Message.YPos);
if (Item <> nil) and Item.Selected then
BeginDrag(False);
end;
end;
function TCustomListView.GetSearchString: string;
var
Buffer: array[0..1023] of char;
begin
Result := '';
if HandleAllocated and ListView_GetISearchString(Handle, Buffer) then
Result := Buffer;
end;
end.