📄 treechildmanagers.pas
字号:
{**********************************************}
{ TTree Component Library }
{ Several "Child Align Manager" components. }
{ Copyright (c) 2001-2002 by David Berneda }
{**********************************************}
{$I TeeDefs.inc}
{$I TeeDefs.inc}
unit TreeChildManagers;
interface
// This unit contains classes that derive from TeeTree "TChildManager" class.
//
// This classes perform automatic positioning of children nodes.
//
Uses {$IFNDEF LINUX}
Windows,
{$ENDIF}
{$IFDEF CLX}
QGraphics,
{$ELSE}
Graphics,
{$ENDIF}
TeeTree, Classes;
type
TTreeExplorerAlignRight=class(TTreeExplorerAlignChild)
public
Constructor Create;
Function CalcXYCross(ANode,AParent:TTreeNodeShape):TPoint; override;
Function XPosition(ANode:TTreeNodeShape):Integer; override;
end;
TTreeCircularAlignChild=class(TChildManager)
private
FOffset : Integer;
FTotalAngle : Integer;
FXRadius : Integer;
FYRadius : Integer;
FYOffset : Integer;
FXOffset : Integer;
Function AngleNode(ANode:TTreeNodeShape):Double;
public
Constructor Create;
Function CalcXYCross(ANode,AParent:TTreeNodeShape):TPoint; override;
Function DrawConnection(AConnection:TTreeConnection):Boolean; override;
Function XPosition(ANode:TTreeNodeShape):Integer; override;
Function YPosition(ANode:TTreeNodeShape; ABrotherIndex:Integer):Integer; override;
property AngleOffset:Integer read FOffset write FOffset default 0;
property TotalAngle:Integer read FTotalAngle write FTotalAngle default 360;
property XOffset:Integer read FXOffset write FXOffset default 0;
property XRadius:Integer read FXRadius write FXRadius default 100;
property YOffset:Integer read FYOffset write FYOffset default 0;
property YRadius:Integer read FYRadius write FYRadius default 100;
end;
TTreeSideAlignChild=class(TChildManager)
private
FCrossMargin : Integer;
FHorizMargin : Integer;
FToShapeOffset : Integer;
FVertMargin : Integer;
public
Constructor Create; virtual;
property CrossMargin:Integer read FCrossMargin write FCrossMargin;
property HorizMargin:Integer read FHorizMargin write FHorizMargin;
property ToShapeOffset:Integer read FToShapeOffset write FToShapeOffset;
property VertMargin:Integer read FVertMargin write FVertMargin;
end;
TTreeTopBottomAlignChild=class(TTreeSideAlignChild)
public
Constructor Create; override;
Function CalcXYCross(ANode,AParent:TTreeNodeShape):TPoint; override;
Function DrawConnection(AConnection:TTreeConnection):Boolean; override;
Function XPosition(ANode:TTreeNodeShape):Integer; override;
Function YPosition(ANode:TTreeNodeShape; ABrotherIndex:Integer):Integer; override;
end;
TTreeLeftRightAlignChild=class(TTreeSideAlignChild)
public
Constructor Create; override;
Function CalcXYCross(ANode,AParent:TTreeNodeShape):TPoint; override;
Function DrawConnection(AConnection:TTreeConnection):Boolean; override;
Function XPosition(ANode:TTreeNodeShape):Integer; override;
Function YPosition(ANode:TTreeNodeShape; ABrotherIndex:Integer):Integer; override;
end;
TTreeListViewAlignChild=class(TChildManager)
private
RowCount : Integer;
RowHeight : Integer;
FHorizMargin : Integer;
FVertMargin : Integer;
IHeight : Integer;
IWidth : Integer;
Procedure CalculateSizes(ANode:TTreeNodeShape);
procedure SetVertMargin(const Value: Integer);
procedure SetHorizMargin(const Value: Integer);
public
ColWidth : Integer;
Constructor Create; virtual;
Function CalcXYCross(ANode,AParent:TTreeNodeShape):TPoint; override;
Function DrawConnection(AConnection:TTreeConnection):Boolean; override;
property HorizMargin:Integer read FHorizMargin write SetHorizMargin
default 5;
Function XPosition(ANode:TTreeNodeShape):Integer; override;
Function YPosition(ANode:TTreeNodeShape; ABrotherIndex:Integer):Integer; override;
property VertMargin:Integer read FVertMargin write SetVertMargin
default 2;
end;
implementation
Uses TeCanvas;
{ TTreeExplorerAlignRight }
constructor TTreeExplorerAlignRight.Create;
begin
inherited;
ArrowToAngle:=180;
end;
function TTreeExplorerAlignRight.CalcXYCross(ANode,
AParent: TTreeNodeShape): TPoint;
// Returns true if parent node has an automatic connection to node.
Function AutoConnection:Boolean;
var tmp : TTreeConnection;
begin
tmp:=AParent.Connections.ToShape(ANode);
result:=Assigned(tmp) and (tmp.Style=csAuto);
end;
var t : Integer;
tmp : Integer;
begin
with ANode do
result.Y:=((Y0+Y1) div 2)+Tree.ChartBounds.Top; // YCenter
if Assigned(AParent) then
begin
With AParent do
begin
if ANode.AutoPosition.Left or AutoConnection then // optimized.
begin
result.X:=4+1+X1+Tree.ChartBounds.Left+2*TeePictureHorizMargin;
exit;
end;
end;
end
else
if ANode.AutoPosition.Left then
With ANode.Tree.Roots do
begin
t:=IndexOf(ANode);
if (t>0) and (Items[t-1].AutoPosition.Left) then // is not the first root
begin
result.X:=CalcXYCross(Items[t-1],nil).X; // return previous root cross-box
exit;
end;
end;
With ANode.Tree.CrossBox do
if Visible then tmp:=Size div 2
else tmp:=0;
result.X:=ANode.AdjustedRectangle.Right+CrossMargin+tmp;
end;
function TTreeExplorerAlignRight.XPosition(ANode: TTreeNodeShape): Integer;
var tmp : Integer;
begin
With ANode do
if Assigned(Parent) then // child node
begin
// indent X from parent
if Tree.ShowImages and (Parent.GetPicture.Width=0) and
(ANode.GetPicture.Width>0) then
result:=Parent.X1-HorizMargin-ANode.GetPicture.Width-TeePictureHorizMargin
else
result:=Parent.X1-HorizMargin;
Dec(result,Width);
end
else
begin
tmp:=Tree.Roots.IndexOf(ANode);
if (tmp=0) or (not Tree.Roots[tmp-1].AutoPosition.Left) then // first tree root
begin
result:=Tree.ClientWidth-2-Width;
if Tree.ShowImages and (ANode.GetPicture.Width>0) then
Dec(result,ANode.GetPicture.Width+TeePictureHorizMargin);
if AnyRootShouldDrawCross(ANode.Tree) then
Dec(result,Tree.CrossBox.Size+CrossMargin+2);
end
else result:=Tree.Roots[tmp-1].X0; // same X as previous root
end;
end;
{ TTreeCircularAlignChild }
function TTreeCircularAlignChild.CalcXYCross(ANode,
AParent: TTreeNodeShape): TPoint;
var tmp : Integer;
begin
With ANode.Tree.CrossBox do
if Visible then tmp:=Size div 2
else tmp:=0;
result.X:=ANode.AdjustedRectangle.Left-TeeCrossBoxHorizMargin-tmp;;
result.Y:=ANode.Y0+(ANode.Height div 2);
end;
type TTreeConnectionAccess=class(TTreeConnection);
Constructor TTreeCircularAlignChild.Create;
begin
inherited;
FXRadius:=100;
FYRadius:=100;
FTotalAngle:=360;
end;
function TTreeCircularAlignChild.DrawConnection(
AConnection: TTreeConnection): Boolean;
begin
result:=True;
AConnection.Style:=csLine;
TTreeConnectionAccess(AConnection).InternalDraw;
end;
Function TTreeCircularAlignChild.AngleNode(ANode:TTreeNodeShape):Double;
begin
result:=TeePiStep*(FOffset+(FTotalAngle*ANode.BrotherIndex/ANode.Parent.Count));
end;
function TTreeCircularAlignChild.XPosition(ANode: TTreeNodeShape): Integer;
begin
with ANode do
if Assigned(Parent) then
begin
result:=FXOffset+Parent.XCenter+
Round(FXRadius*Sin(AngleNode(ANode)))-(Width div 2);
end
else result:=X0;
end;
function TTreeCircularAlignChild.YPosition(ANode: TTreeNodeShape;
ABrotherIndex: Integer): Integer;
begin
with ANode do
if Assigned(Parent) then
begin
result:=FYOffset+Parent.YCenter+
Round(FYRadius*Cos(AngleNode(ANode)))-(Height div 2);
end
else result:=Y0;
end;
{ TTreeTopBottomAlignChild }
function TTreeTopBottomAlignChild.CalcXYCross(ANode,
AParent: TTreeNodeShape): TPoint;
begin
result.X:=ANode.XCenter;
result.Y:=ANode.Y1+CrossMargin;
end;
constructor TTreeTopBottomAlignChild.Create;
begin
inherited;
FVertMargin:=32;
FHorizMargin:=8;
end;
function TTreeTopBottomAlignChild.DrawConnection(
AConnection: TTreeConnection): Boolean;
begin
result:=True;
with TTreeConnectionAccess(AConnection) do
begin
with Points do
if Count=0 then
begin
Clear;
Add(cpsFromPercent,50,cpsFromPercent,100);
Add(cpsPrevious,0,cpsPrevious,FVertMargin div 2);
Add(cpsToPercent,50,cpsPrevious,0);
Add(cpsPrevious,0,cpsToRel,FToShapeOffset);
end
else
if Count>3 then
Item[3].YValue:=FToShapeOffset;
InternalDraw;
end;
end;
function TTreeTopBottomAlignChild.XPosition(ANode: TTreeNodeShape): Integer;
var t : Integer;
tmp : Integer;
begin
with ANode do
if Assigned(Parent) then
begin
tmp:=0;
for t:=0 to Parent.Count-1 do
Inc(tmp,Parent.Children[t].Width);
Inc(tmp,FHorizMargin*(Parent.Count-1));
result:=Parent.XCenter-(tmp div 2);
for t:=0 to BrotherIndex-1 do
Inc(result,Parent.Children[t].Width+FHorizMargin);
end
else
result:=X0;
end;
function TTreeTopBottomAlignChild.YPosition(ANode: TTreeNodeShape;
ABrotherIndex: Integer): Integer;
begin
with ANode do
if Assigned(Parent) then result:=Parent.Y1+FVertMargin
else result:=Y0;
end;
{ TTreeLeftRightAlignChild }
Constructor TTreeLeftRightAlignChild.Create;
begin
inherited;
FVertMargin:=8;
FHorizMargin:=32;
end;
function TTreeLeftRightAlignChild.CalcXYCross(ANode,
AParent: TTreeNodeShape): TPoint;
begin
result.X:=ANode.X1+CrossMargin;
result.Y:=ANode.YCenter;
end;
function TTreeLeftRightAlignChild.DrawConnection(
AConnection: TTreeConnection): Boolean;
begin
result:=True;
with TTreeConnectionAccess(AConnection) do
begin
with Points do
if Count=0 then
begin
Clear;
Add(cpsFromPercent,100,cpsFromPercent,50);
Add(cpsPrevious,FHorizMargin div 2,cpsPrevious,0);
Add(cpsPrevious,0,cpsToPercent,50);
Add(cpsToRel,FToShapeOffset,cpsPrevious,0);
end
else
if Count>3 then
Item[3].XValue:=FToShapeOffset;
InternalDraw;
end;
end;
function TTreeLeftRightAlignChild.XPosition(
ANode: TTreeNodeShape): Integer;
begin
with ANode do
if Assigned(Parent) then result:=Parent.X1+FHorizMargin
else result:=X0;
end;
function TTreeLeftRightAlignChild.YPosition(ANode: TTreeNodeShape;
ABrotherIndex: Integer): Integer;
var t : Integer;
tmp : Integer;
begin
with ANode do
if Assigned(Parent) then
begin
tmp:=0;
for t:=0 to Parent.Count-1 do
Inc(tmp,Parent.Children[t].Height);
Inc(tmp,FVertMargin*(Parent.Count-1));
result:=Parent.YCenter-(tmp div 2);
for t:=0 to BrotherIndex-1 do
Inc(result,Parent.Children[t].Height+FVertMargin);
end
else
result:=Y0;
end;
{ TTreeSideAlignChild }
constructor TTreeSideAlignChild.Create;
begin
inherited;
FCrossMargin:=8;
FToShapeOffset:=-4;
end;
{ TTreeListViewAlignChild }
function TTreeListViewAlignChild.CalcXYCross(ANode,
AParent: TTreeNodeShape): TPoint;
begin
result.X:=ANode.X0;
result.Y:=ANode.Y0;
end;
function TTreeListViewAlignChild.DrawConnection(
AConnection: TTreeConnection): Boolean;
begin
result:=True; // keep drawing nodes, but do not draw connections
end;
Procedure TTreeListViewAlignChild.CalculateSizes(ANode:TTreeNodeShape);
begin
with ANode.Tree do
if (IHeight<>ChartHeight) or (IWidth<>ChartWidth) then
begin
IHeight:=ChartHeight;
IWidth:=ChartWidth;
RowHeight:=ANode.Height+FVertMargin;
RowCount:=Trunc(IHeight/RowHeight);
// check if horiz.scroll bar *will* be visible...
if not HorzScrollBar.Visible then
with Roots do
if XPosition(Last)+Last.Width>IWidth then
Dec(RowCount);
end;
end;
function TTreeListViewAlignChild.XPosition(ANode: TTreeNodeShape): Integer;
Function ImageWidthColumn(Col:Integer):Integer;
var t : Integer;
tmp : Integer;
tmpW : Integer;
begin
result:=0;
if ANode.Tree.ShowImages then
for t:=0 to RowCount-1 do
begin
tmp:=t+(Col*RowCount);
if tmp<ANode.Tree.Roots.Count then
begin
with ANode.Tree.Roots[tmp] do
if ImageAlignment=iaAutomatic then
begin
tmpW:=GetPicture.Width;
if tmpW>result then result:=tmpW;
end
end
else
break;
end;
end;
Function ColumnWidth(Col:Integer):Integer;
var tmp : Integer;
t : Integer;
begin
result:=0;
for t:=0 to RowCount-1 do
begin
with ANode.Tree.Roots[t+(Col*RowCount)] do tmp:=Width;
if tmp>result then result:=tmp;
end;
Inc(result,ImageWidthColumn(Col)+TeePictureHorizMargin+FHorizMargin);
end;
var tmpCol : Integer;
t : Integer;
begin
CalculateSizes(ANode);
if Assigned(ANode.Parent) then result:=ANode.X0
else
begin
tmpCol:=ANode.Tree.Roots.IndexOf(ANode) div RowCount;
result:=ImageWidthColumn(tmpCol)+TeePictureHorizMargin+FHorizMargin;
if ColWidth=0 then // automatic column width
for t:=0 to tmpCol-1 do
Inc(result,ColumnWidth(t))
else
Inc(result,ColWidth*tmpCol); // fixed column width
end;
end;
function TTreeListViewAlignChild.YPosition(ANode: TTreeNodeShape;
ABrotherIndex: Integer): Integer;
var tmp : Integer;
begin
CalculateSizes(ANode);
if Assigned(ANode.Parent) then result:=ANode.Y0
else
begin
tmp:=ANode.Tree.Roots.IndexOf(ANode);
result:=RowHeight*(tmp mod RowCount);
end;
end;
constructor TTreeListViewAlignChild.Create;
begin
inherited;
FVertMargin:=2;
FHorizMargin:=5;
end;
procedure TTreeListViewAlignChild.SetVertMargin(const Value: Integer);
begin
FVertMargin:=Value;
IHeight:=0;
end;
procedure TTreeListViewAlignChild.SetHorizMargin(const Value: Integer);
begin
FHorizMargin:=Value;
IHeight:=0;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -