codetools: added unit groups graph

git-svn-id: trunk@40045 -
This commit is contained in:
mattias 2013-01-30 03:59:47 +00:00
parent 4b4469364c
commit f4074a842f
7 changed files with 857 additions and 641 deletions

1
.gitattributes vendored
View File

@ -639,6 +639,7 @@ components/codetools/codetoolsstructs.pas svneol=native#text/pascal
components/codetools/codetree.pas svneol=native#text/pascal
components/codetools/ctloadlaz.pas svneol=native#text/plain
components/codetools/ctunitgraph.pas svneol=native#text/plain
components/codetools/ctunitgroupgraph.pas svneol=native#text/plain
components/codetools/ctxmlfixfragment.pas svneol=native#text/plain
components/codetools/customcodetool.pas svneol=native#text/pascal
components/codetools/definetemplates.pas svneol=native#text/pascal

View File

@ -29,7 +29,7 @@
<License Value="GPL-2
"/>
<Version Major="1" Release="1"/>
<Files Count="59">
<Files Count="60">
<Item1>
<Filename Value="Makefile"/>
<Type Value="Text"/>
@ -267,6 +267,10 @@
<Filename Value="ctloadlaz.pas"/>
<UnitName Value="ctloadlaz"/>
</Item59>
<Item60>
<Filename Value="ctunitgroupgraph.pas"/>
<UnitName Value="ctunitgroupgraph"/>
</Item60>
</Files>
<LazDoc Paths="docs"/>
<i18n>

View File

@ -18,7 +18,8 @@ uses
PascalReaderTool, PPUCodeTools, PPUGraph, PPUParser, ResourceCodeTool,
SourceChanger, SourceLog, StdCodeTools, OtherIdentifierTree,
CodeToolsCfgScript, CTXMLFixFragment, CTUnitGraph, ChangeDeclarationTool,
CodeToolsFPCMsgs, UnitDictionary, ctloadlaz, LazarusPackageIntf;
CodeToolsFPCMsgs, UnitDictionary, ctloadlaz, CTUnitGroupGraph,
LazarusPackageIntf;
implementation

View File

@ -131,8 +131,8 @@ type
property TargetFilesTree: TAVLTree read FTargetFiles; // tree of TUGUnit sorted for Filename
property TargetAll: boolean read FTargetAll write FTargetAll;
property UnitClass: TUGUnitClass read FUnitClass;
property UsesClass: TUGUsesClass read FUsesClass;
property UnitClass: TUGUnitClass read FUnitClass write FUnitClass;
property UsesClass: TUGUsesClass read FUsesClass write FUsesClass;
end;
function CompareUGUnitFilenames(UGUnit1, UGUnit2: Pointer): integer;

View File

@ -0,0 +1,202 @@
{
***************************************************************************
* *
* This source is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This code is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* General Public License for more details. *
* *
* A copy of the GNU General Public License is available on the World *
* Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
* obtain it by writing to the Free Software Foundation, *
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
* *
***************************************************************************
Author: Mattias Gaertner
Abstract:
Functions and classes to build dependency graphs for groups of pascal units.
}
unit CTUnitGroupGraph;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, AVL_Tree, CTUnitGraph;
type
TUGGroup = class;
TUGGroups = class;
{ TUGGroupUnit }
TUGGroupUnit = class(TUGUnit)
public
Group: TUGGroup;
end;
TUGGroup = class
private
FGroups: TUGGroups;
FName: string;
FUnits: TAVLTree;
procedure SetName(AValue: string);
public
constructor Create(aName: string; TheGroups: TUGGroups);
destructor Destroy; override;
procedure Clear;
procedure AddUnit(anUnit: TUGGroupUnit);
procedure RemoveUnit(anUnit: TUGGroupUnit);
property Name: string read FName write SetName;
property Groups: TUGGroups read FGroups;
property Units: TAVLTree read FUnits; // tree of TUGGroupUnit sorted for Filename
end;
{ TUGGroups }
TUGGroups = class
private
fClearing: boolean;
FGroups: TAVLTree;
public
constructor Create(Graph: TUsesGraph);
destructor Destroy; override;
procedure Clear;
function GetGroup(Name: string; CreateIfNotExists: boolean): TUGGroup;
property Groups: TAVLTree read FGroups; // tree of TUGGroup sorted for Name
end;
function CompareUGGroupNames(UGGroup1, UGGroup2: Pointer): integer;
function CompareNameAndUGGroup(NameAnsistring, UGGroup: Pointer): integer;
implementation
function CompareUGGroupNames(UGGroup1, UGGroup2: Pointer): integer;
var
Group1: TUGGroup absolute UGGroup1;
Group2: TUGGroup absolute UGGroup2;
begin
Result:=SysUtils.CompareText(Group1.Name,Group2.Name);
end;
function CompareNameAndUGGroup(NameAnsistring, UGGroup: Pointer): integer;
var
Group: TUGGroup absolute UGGroup;
Name: String;
begin
Name:=AnsiString(NameAnsistring);
Result:=SysUtils.CompareText(Name,Group.Name);
end;
{ TUGGroups }
constructor TUGGroups.Create(Graph: TUsesGraph);
begin
FGroups:=TAVLTree.Create(@CompareUGGroupNames);
if (not Graph.UnitClass.InheritsFrom(TUGGroup))
and ((Graph.FilesTree.Count>0) or (Graph.QueuedFilesTree.Count>0)
or (Graph.TargetFilesTree.Count>0))
then
raise Exception.Create('TUGGroups.Create Create TUGGroups before adding units');
Graph.UnitClass:=TUGGroupUnit;
end;
destructor TUGGroups.Destroy;
begin
Clear;
FreeAndNil(FGroups);
inherited Destroy;
end;
procedure TUGGroups.Clear;
begin
fClearing:=true;
try
FGroups.FreeAndClear;
finally
fClearing:=false;
end;
end;
function TUGGroups.GetGroup(Name: string; CreateIfNotExists: boolean): TUGGroup;
var
Node: TAVLTreeNode;
begin
Node:=FGroups.FindKey(Pointer(Name),@CompareNameAndUGGroup);
if Node<>nil then begin
Result:=TUGGroup(Node.Data);
end else if CreateIfNotExists then begin
Result:=TUGGroup.Create(Name,Self);
FGroups.Add(Result);
end else
Result:=nil;
end;
{ TUGGroup }
procedure TUGGroup.SetName(AValue: string);
begin
if FName=AValue then Exit;
if Groups.GetGroup(AValue,false)<>nil then
raise Exception.Create('TUGGroup.SetName name already exists');
Groups.fGroups.Remove(Self);
FName:=AValue;
Groups.fGroups.Add(Self);
end;
constructor TUGGroup.Create(aName: string; TheGroups: TUGGroups);
begin
FGroups:=TheGroups;
FUnits:=TAVLTree.Create(@CompareUGUnitFilenames);
end;
destructor TUGGroup.Destroy;
begin
Clear;
if not Groups.fClearing then
Groups.FGroups.Remove(Self);
fGroups:=nil;
FreeAndNil(FUnits);
inherited Destroy;
end;
procedure TUGGroup.Clear;
var
Node: TAVLTreeNode;
begin
Node:=FUnits.FindLowest;
while Node<>nil do begin
TUGGroupUnit(Node.Data).Group:=nil;
Node:=FUnits.FindSuccessor(Node);
end;
FUnits.Clear;
end;
procedure TUGGroup.AddUnit(anUnit: TUGGroupUnit);
begin
if anUnit.Group<>nil then begin
anUnit.Group.FUnits.Remove(anUnit);
anUnit.Group:=nil;
end;
FUnits.Add(anUnit);
anUnit.Group:=Self;
end;
procedure TUGGroup.RemoveUnit(anUnit: TUGGroupUnit);
begin
if (anUnit.Group<>nil) and (anUnit.Group<>Self) then
raise Exception.Create('TUGGroup.RemoveUnit inconsistency');
FUnits.Remove(anUnit);
anUnit.Group:=nil;
end;
end.

View File

@ -30,7 +30,8 @@ unit CodyCtrls;
interface
uses
Classes, SysUtils, ComCtrls, Controls;
types, math, contnrs, Classes, SysUtils, FPCanvas,
LazLogger, ComCtrls, Controls, Graphics, LCLType;
type
@ -41,8 +42,195 @@ type
procedure FreeNodeData;
end;
const
FullCircle16 = 360*16;
DefaultCategoryGapDegree16 = 0.02*FullCircle16;
DefaultFirstCategoryDegree16 = 0;
DefaultCategoryMinSize = 1.0;
DefaultItemSize = 1.0;
type
TCustomCircleDiagramControl = class;
TCircleDiagramCategory = class;
{ TCircleDiagramItem }
TCircleDiagramItem = class(TPersistent)
private
FCaption: TCaption;
FCategory: TCircleDiagramCategory;
FEndDegree16: single;
FSize: single;
FStartDegree16: single;
procedure SetCaption(AValue: TCaption);
procedure SetSize(AValue: single);
procedure UpdateLayout;
public
constructor Create(TheCategory: TCircleDiagramCategory);
destructor Destroy; override;
property Category: TCircleDiagramCategory read FCategory;
property Caption: TCaption read FCaption write SetCaption;
property Size: single read FSize write SetSize default DefaultItemSize; // scaled to fit
property StartDegree16: single read FStartDegree16; // 360*16 = one full circle, 0 at 3o'clock
property EndDegree16: single read FEndDegree16; // 360*16 = one full circle, 0 at 3o'clock
end;
{ TCircleDiagramCategory }
TCircleDiagramCategory = class(TPersistent)
private
FCaption: TCaption;
FColor: TColor;
FDiagram: TCustomCircleDiagramControl;
FEndDegree16: single;
FMinSize: single;
fItems: TObjectList; // list of TCircleDiagramItem
FSize: single;
FStartDegree16: single;
function GetItems(Index: integer): TCircleDiagramItem;
procedure SetCaption(AValue: TCaption);
procedure SetColor(AValue: TColor);
procedure SetMinSize(AValue: single);
procedure UpdateLayout;
procedure Invalidate;
procedure InternalRemoveItem(Item: TCircleDiagramItem);
public
constructor Create(TheDiagram: TCustomCircleDiagramControl);
destructor Destroy; override;
function InsertItem(Index: integer; aCaption: string): TCircleDiagramItem;
function AddItem(aCaption: string): TCircleDiagramItem;
property Diagram: TCustomCircleDiagramControl read FDiagram;
property Caption: TCaption read FCaption write SetCaption;
property MinSize: single read FMinSize write SetMinSize default DefaultCategoryMinSize; // scaled to fit
function Count: integer;
property Items[Index: integer]: TCircleDiagramItem read GetItems; default;
property Color: TColor read FColor write SetColor;
property Size: single read FSize;
property StartDegree16: single read FStartDegree16; // 360*16 = one full circle, 0 at 3o'clock
property EndDegree16: single read FEndDegree16; // 360*16 = one full circle, 0 at 3o'clock
end;
TCircleDiagramCtrlFlag = (
cdcNeedUpdateLayout
);
TCircleDiagramCtrlFlags = set of TCircleDiagramCtrlFlag;
{ TCustomCircleDiagramControl }
TCustomCircleDiagramControl = class(TCustomControl)
private
FCategoryGapDegree16: single;
FCenter: TPoint;
FCenterCaption: TCaption;
FCenterCaptionRect: TRect;
FFirstCategoryDegree16: single;
fCategories: TObjectList; // list of TCircleDiagramCategory
FInnerRadius: single;
FOuterRadius: single;
fUpdateLock: integer;
fFlags: TCircleDiagramCtrlFlags;
function GetCategories(Index: integer): TCircleDiagramCategory;
procedure SetCategoryGapDegree16(AValue: single);
procedure SetCenterCaption(AValue: TCaption);
procedure SetFirstCategoryDegree16(AValue: single);
procedure InternalRemoveCategory(Category: TCircleDiagramCategory);
protected
//procedure WMVScroll(var Msg: TLMScroll); message LM_VSCROLL;
//procedure WMMouseWheel(var Message: TLMMouseEvent); message LM_MOUSEWHEEL;
procedure CreateWnd; override;
procedure UpdateScrollBar;
procedure DoSetBounds(ALeft, ATop, AWidth, AHeight: integer); override;
//procedure MouseDown(Button:TMouseButton; Shift:TShiftState; X,Y:integer); override;
//procedure MouseMove(Shift:TShiftState; X,Y:integer); override;
//procedure MouseUp(Button:TMouseButton; Shift:TShiftState; X,Y:integer); override;
//procedure KeyDown(var Key: Word; Shift: TShiftState); override;
//procedure HandleStandardKeys(var Key: Word; Shift: TShiftState); virtual;
//procedure HandleKeyUp(var Key: Word; Shift: TShiftState); virtual;
procedure Paint; override;
procedure DrawCategory(i: integer);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property CenterCaption: TCaption read FCenterCaption write SetCenterCaption;
procedure Clear;
procedure BeginUpdate; virtual;
procedure EndUpdate; virtual;
procedure UpdateLayout;
procedure EraseBackground({%H-}DC: HDC); override;
function InsertCategory(Index: integer; aCaption: TCaption): TCircleDiagramCategory;
function AddCategory(aCaption: TCaption): TCircleDiagramCategory;
function IndexOfCategory(aCaption: TCaption): integer;
function FindCategory(aCaption: TCaption): TCircleDiagramCategory;
property CategoryGapDegree16: single read FCategoryGapDegree16 write SetCategoryGapDegree16 default DefaultCategoryGapDegree16; // 360*16 = one full circle, 0 at 3o'clock
property FirstCategoryDegree16: single read FFirstCategoryDegree16 write SetFirstCategoryDegree16 default DefaultFirstCategoryDegree16; // 360*16 = one full circle, 0 at 3o'clock
function CategoryCount: integer;
property Categories[Index: integer]: TCircleDiagramCategory read GetCategories; default;
property Color default clWhite;
// computed values
property CenterCaptionRect: TRect read FCenterCaptionRect;
property Center: TPoint read FCenter;
property InnerRadius: single read FInnerRadius;
property OuterRadius: single read FOuterRadius;
// debugging
procedure WriteDebugReport(Msg: string);
end;
{ TCircleDiagramControl }
TCircleDiagramControl = class(TCustomCircleDiagramControl)
published
property Align;
property Anchors;
property BorderSpacing;
property BorderStyle;
property BorderWidth;
property Color;
property Constraints;
property DragKind;
property DragCursor;
property DragMode;
property Enabled;
property Font;
property ParentColor default False;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property TabOrder;
property TabStop default True;
property Tag;
property Visible;
property OnClick;
property OnContextPopup;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnMouseDown;
property OnMouseEnter;
property OnMouseLeave;
property OnMouseMove;
property OnMouseUp;
property OnShowHint;
property OnStartDrag;
property OnUTF8KeyPress;
end;
procedure FreeTVNodeData(TV: TCustomTreeView);
procedure RingSector(Canvas: TFPCustomCanvas; x1, y1, x2, y2: integer;
InnerSize: single; StartAngle16, EndAngle16: integer); overload;
procedure RingSector(Canvas: TFPCustomCanvas; x1, y1, x2, y2,
InnerSize, StartAngle, EndAngle: single); overload;
implementation
procedure FreeTVNodeData(TV: TCustomTreeView);
@ -61,6 +249,53 @@ begin
TV.EndUpdate;
end;
procedure RingSector(Canvas: TFPCustomCanvas; x1, y1, x2, y2: integer;
InnerSize: single; StartAngle16, EndAngle16: integer);
begin
RingSector(Canvas,single(x1),single(y1),single(x2),single(y2),InnerSize,
single(StartAngle16)/16,single(EndAngle16)/16);
end;
procedure RingSector(Canvas: TFPCustomCanvas; x1, y1, x2, y2, InnerSize, StartAngle,
EndAngle: single);
var
OuterCnt: integer;
centerx, centery: single;
i: Integer;
Ang: single;
OuterRadiusX, OuterRadiusY, InnerRadiusX, InnerRadiusY: single;
Points: array of TPoint;
j: Integer;
begin
OuterCnt:=Round(SQRT((Abs(x2-x1)+Abs(y2-y1))*Abs(EndAngle-StartAngle)/FullCircle16)+0.5);
centerx:=(x1+x2)/2;
centery:=(y1+y2)/2;
OuterRadiusX:=(x2-x1)/2;
OuterRadiusY:=(y2-y1)/2;
InnerRadiusX:=OuterRadiusX*InnerSize;
InnerRadiusY:=OuterRadiusY*InnerSize;
SetLength(Points,OuterCnt*2+2);
j:=0;
// outer arc
for i:=0 to OuterCnt do begin
Ang:=StartAngle+((EndAngle-StartAngle)/OuterCnt)*single(i);
Ang:=(Ang/FullCircle16)*2*pi;
Points[j].x:=round(centerx+cos(Ang)*OuterRadiusX);
Points[j].y:=round(centery-sin(Ang)*OuterRadiusY);
inc(j);
end;
// inner arc
for i:=OuterCnt downto 0 do begin
Ang:=StartAngle+((EndAngle-StartAngle)/OuterCnt)*single(i);
Ang:=(Ang/FullCircle16)*2*pi;
Points[j].x:=round(centerx+cos(Ang)*InnerRadiusX);
Points[j].y:=round(centery-sin(Ang)*InnerRadiusY);
inc(j);
end;
Canvas.Polygon(Points);
SetLength(Points,0);
end;
{ TCodyTreeView }
procedure TCodyTreeView.FreeNodeData;
@ -68,5 +303,403 @@ begin
FreeTVNodeData(Self);
end;
{ TCustomCircleDiagramControl }
procedure TCustomCircleDiagramControl.SetCategoryGapDegree16(AValue: single);
begin
if AValue<0 then AValue:=0;
if AValue>0.3 then AValue:=0.3;
if FCategoryGapDegree16=AValue then Exit;
FCategoryGapDegree16:=AValue;
UpdateLayout;
end;
function TCustomCircleDiagramControl.GetCategories(Index: integer
): TCircleDiagramCategory;
begin
Result:=TCircleDiagramCategory(fCategories[Index]);
end;
procedure TCustomCircleDiagramControl.SetCenterCaption(AValue: TCaption);
begin
if FCenterCaption=AValue then Exit;
FCenterCaption:=AValue;
UpdateLayout;
end;
procedure TCustomCircleDiagramControl.SetFirstCategoryDegree16(AValue: single);
begin
if FFirstCategoryDegree16=AValue then Exit;
FFirstCategoryDegree16:=AValue;
UpdateLayout;
end;
procedure TCustomCircleDiagramControl.InternalRemoveCategory(
Category: TCircleDiagramCategory);
begin
fCategories.Remove(Category);
UpdateLayout;
end;
procedure TCustomCircleDiagramControl.CreateWnd;
begin
inherited CreateWnd;
UpdateScrollBar;
end;
procedure TCustomCircleDiagramControl.UpdateScrollBar;
begin
end;
procedure TCustomCircleDiagramControl.DoSetBounds(ALeft, ATop, AWidth,
AHeight: integer);
begin
inherited DoSetBounds(ALeft, ATop, AWidth, AHeight);
UpdateScrollBar;
end;
procedure TCustomCircleDiagramControl.Paint;
var
i: Integer;
begin
inherited Paint;
if cdcNeedUpdateLayout in fFlags then
UpdateLayout;
// background
Canvas.Brush.Style:=bsSolid;
Canvas.Brush.Color:=Color;
Canvas.FillRect(ClientRect);
Canvas.Brush.Color:=clRed;
// draw categories
for i:=0 to CategoryCount-1 do
DrawCategory(i);
// center caption
Canvas.Brush.Style:=bsSolid;
Canvas.Brush.Color:=clNone;
Canvas.TextOut(FCenterCaptionRect.Left,FCenterCaptionRect.Top,CenterCaption);
end;
procedure TCustomCircleDiagramControl.DrawCategory(i: integer);
var
Cat: TCircleDiagramCategory;
begin
Cat:=Categories[i];
Canvas.Brush.Color:=Cat.Color;
RingSector(Canvas,Center.X-OuterRadius,Center.Y-OuterRadius,
Center.X+OuterRadius,Center.Y+OuterRadius,
single(InnerRadius)/single(OuterRadius),
Cat.StartDegree16,Cat.EndDegree16);
end;
constructor TCustomCircleDiagramControl.Create(AOwner: TComponent);
begin
BeginUpdate;
try
inherited Create(AOwner);
fCategories:=TObjectList.create(true);
FFirstCategoryDegree16:=DefaultFirstCategoryDegree16;
FCategoryGapDegree16:=DefaultCategoryGapDegree16;
Color:=clWhite;
finally
EndUpdate;
end;
end;
destructor TCustomCircleDiagramControl.Destroy;
begin
BeginUpdate; // disable updates
FreeAndNil(fCategories);
inherited Destroy;
end;
procedure TCustomCircleDiagramControl.Clear;
begin
BeginUpdate;
try
while CategoryCount>0 do
Categories[0].Free;
finally
EndUpdate;
end;
end;
procedure TCustomCircleDiagramControl.BeginUpdate;
begin
inc(fUpdateLock);
end;
procedure TCustomCircleDiagramControl.EndUpdate;
begin
if fUpdateLock=0 then
raise Exception.Create('TCustomCircleDiagramControl.EndUpdate');
dec(fUpdateLock);
if fUpdateLock=0 then begin
if cdcNeedUpdateLayout in fFlags then
UpdateLayout;
end;
end;
procedure TCustomCircleDiagramControl.UpdateLayout;
var
aSize: TSize;
aCategory: TCircleDiagramCategory;
i: Integer;
j: Integer;
TotalSize: Single;
CurCategoryDegree: Single;
GapDegree: Single;
TotalItemDegree: Single;
Item: TCircleDiagramItem;
CurItemDegree: Single;
begin
if (fUpdateLock>0) or (not IsVisible) or (not HandleAllocated) then begin
Include(fFlags,cdcNeedUpdateLayout);
exit;
end;
Exclude(fFlags,cdcNeedUpdateLayout);
// center caption
FCenter:=Point(ClientWidth div 2,ClientHeight div 2);
aSize:=Canvas.TextExtent(CenterCaption);
FCenterCaptionRect:=Bounds(FCenter.X-(aSize.cx div 2),FCenter.Y-(aSize.cy div 2)
,aSize.cx,aSize.cy);
// radius
fInnerRadius:=0.25*Min(ClientWidth,ClientHeight);
fOuterRadius:=1.1*InnerRadius;
// degrees
TotalSize:=0.0;
CurCategoryDegree:=FirstCategoryDegree16;
if CategoryCount>0 then begin
// calculate TotalSize
for i:=0 to CategoryCount-1 do begin
aCategory:=Categories[i];
aCategory.FSize:=0;
for j:=0 to aCategory.Count-1 do
aCategory.FSize+=aCategory[j].Size;
aCategory.FSize:=Max(aCategory.FSize,aCategory.MinSize);
TotalSize+=aCategory.FSize;
end;
// calculate degrees
GapDegree:=Min(CategoryGapDegree16,(0.8/CategoryCount)*FullCircle16);
TotalItemDegree:=FullCircle16-(GapDegree*CategoryCount);
for i:=0 to CategoryCount-1 do begin
aCategory:=Categories[i];
aCategory.FStartDegree16:=CurCategoryDegree;
if TotalSize>0 then
CurCategoryDegree+=TotalItemDegree*aCategory.Size/TotalSize;
aCategory.FEndDegree16:=CurCategoryDegree;
// item degrees
CurItemDegree:=aCategory.StartDegree16;
for j:=0 to aCategory.Count-1 do begin
Item:=aCategory[j];
Item.FStartDegree16:=CurItemDegree;
if aCategory.Size>0 then
CurItemDegree+=(aCategory.EndDegree16-aCategory.StartDegree16)*Item.Size/aCategory.Size;
Item.FEndDegree16:=CurItemDegree;
end;
CurCategoryDegree+=GapDegree;
end;
end;
WriteDebugReport('TCustomCircleDiagramControl.UpdateLayout');
end;
procedure TCustomCircleDiagramControl.EraseBackground(DC: HDC);
begin
// do not erase background, Paint will paint the whole area
end;
function TCustomCircleDiagramControl.InsertCategory(Index: integer;
aCaption: TCaption): TCircleDiagramCategory;
begin
Result:=TCircleDiagramCategory.Create(Self);
Result.Caption:=aCaption;
fCategories.Insert(Index,Result);
end;
function TCustomCircleDiagramControl.AddCategory(aCaption: TCaption
): TCircleDiagramCategory;
begin
Result:=InsertCategory(CategoryCount,aCaption);
end;
function TCustomCircleDiagramControl.IndexOfCategory(aCaption: TCaption
): integer;
begin
Result:=CategoryCount-1;
while Result>=0 do begin
if Categories[Result].Caption=aCaption then exit;
dec(Result);
end;
end;
function TCustomCircleDiagramControl.FindCategory(aCaption: TCaption
): TCircleDiagramCategory;
var
i: Integer;
begin
i:=IndexOfCategory(aCaption);
if i>=0 then
Result:=Categories[i]
else
Result:=nil;
end;
function TCustomCircleDiagramControl.CategoryCount: integer;
begin
Result:=fCategories.Count;
end;
procedure TCustomCircleDiagramControl.WriteDebugReport(Msg: string);
var
aCat: TCircleDiagramCategory;
i: Integer;
j: Integer;
Item: TCircleDiagramItem;
begin
DebugLn([Msg,' CategoryCount=',CategoryCount]);
for i:=0 to CategoryCount-1 do begin
aCat:=Categories[i];
debugln([' Category: ',i,'/',CategoryCount,' ',aCat.Caption,
' MinSize=',aCat.MinSize,
' Size=',aCat.Size,
' Start=',round(aCat.StartDegree16),' End=',round(aCat.EndDegree16)]);
for j:=0 to aCat.Count-1 do begin
Item:=aCat.Items[j];
debugln([' Item: ',j,'/',aCat.Count,' ',Item.Caption,
' Size=',Item.Size,
' Start=',round(Item.StartDegree16),
' End=',round(Item.EndDegree16)]);
end;
end;
end;
{ TCircleDiagramCategory }
procedure TCircleDiagramCategory.SetCaption(AValue: TCaption);
begin
if FCaption=AValue then Exit;
FCaption:=AValue;
end;
procedure TCircleDiagramCategory.SetColor(AValue: TColor);
begin
if FColor=AValue then Exit;
FColor:=AValue;
Invalidate;
end;
function TCircleDiagramCategory.GetItems(Index: integer): TCircleDiagramItem;
begin
Result:=TCircleDiagramItem(fItems[Index]);
end;
procedure TCircleDiagramCategory.SetMinSize(AValue: single);
begin
if AValue<0 then AValue:=0;
if FMinSize=AValue then Exit;
FMinSize:=AValue;
UpdateLayout;
end;
procedure TCircleDiagramCategory.UpdateLayout;
begin
if Diagram<>nil then
Diagram.UpdateLayout;
end;
procedure TCircleDiagramCategory.Invalidate;
begin
if Diagram<>nil then
Diagram.Invalidate;
end;
procedure TCircleDiagramCategory.InternalRemoveItem(Item: TCircleDiagramItem);
begin
fItems.Remove(Item);
UpdateLayout;
end;
constructor TCircleDiagramCategory.Create(
TheDiagram: TCustomCircleDiagramControl);
begin
FDiagram:=TheDiagram;
fItems:=TObjectList.Create(true);
FMinSize:=DefaultCategoryMinSize;
end;
destructor TCircleDiagramCategory.Destroy;
begin
if Diagram<>nil then
Diagram.InternalRemoveCategory(Self);
FreeAndNil(fItems);
inherited Destroy;
end;
function TCircleDiagramCategory.InsertItem(Index: integer; aCaption: string
): TCircleDiagramItem;
begin
Result:=TCircleDiagramItem.Create(Self);
Result.Caption:=aCaption;
fItems.Insert(Index,Result);
end;
function TCircleDiagramCategory.AddItem(aCaption: string): TCircleDiagramItem;
begin
Result:=InsertItem(Count,aCaption);
end;
function TCircleDiagramCategory.Count: integer;
begin
Result:=fItems.Count;
end;
{ TCircleDiagramItem }
procedure TCircleDiagramItem.SetCaption(AValue: TCaption);
begin
if FCaption=AValue then Exit;
FCaption:=AValue;
UpdateLayout;
end;
procedure TCircleDiagramItem.SetSize(AValue: single);
begin
if AValue<0 then AValue:=0;
if FSize=AValue then Exit;
FSize:=AValue;
UpdateLayout;
end;
procedure TCircleDiagramItem.UpdateLayout;
begin
if Category<>nil then
Category.UpdateLayout;
end;
constructor TCircleDiagramItem.Create(TheCategory: TCircleDiagramCategory);
begin
FCategory:=TheCategory;
FSize:=DefaultItemSize;
end;
destructor TCircleDiagramItem.Destroy;
begin
if Category<>nil then
Category.InternalRemoveItem(Self);
inherited Destroy;
end;
end.

View File

@ -5,198 +5,18 @@ unit CodyUnitDepWnd;
interface
uses
Classes, SysUtils, types, math, typinfo, AVL_Tree, contnrs, FPCanvas,
FileUtil, lazutf8classes, LazLogger, TreeFilterEdit, CTUnitGraph,
CodeToolManager, DefineTemplates, Forms, Controls, Graphics, Dialogs,
ExtCtrls, Buttons, ComCtrls, LCLType, LazIDEIntf, ProjectIntf, IDEWindowIntf;
Classes, SysUtils, typinfo, AVL_Tree, FPCanvas,
FileUtil, lazutf8classes, LazLogger,
TreeFilterEdit, Forms, Controls, Graphics, Dialogs, ExtCtrls, Buttons,
ComCtrls, LCLType,
LazIDEIntf, ProjectIntf, IDEWindowIntf,
CTUnitGraph, CodeToolManager, DefineTemplates, CTUnitGroupGraph,
CodyCtrls;
resourcestring
a='';
rsSelectAUnit = 'Select an unit';
rsClose = 'Close';
const
FullCircle16 = 360*16;
DefaultCategoryGapDegree16 = 0.02*FullCircle16;
DefaultFirstCategoryDegree16 = 0;
DefaultCategoryMinSize = 1.0;
DefaultItemSize = 1.0;
type
TCustomCircleDiagramControl = class;
TCircleDiagramCategory = class;
{ TCircleDiagramItem }
TCircleDiagramItem = class(TPersistent)
private
FCaption: TCaption;
FCategory: TCircleDiagramCategory;
FEndDegree16: single;
FSize: single;
FStartDegree16: single;
procedure SetCaption(AValue: TCaption);
procedure SetSize(AValue: single);
procedure UpdateLayout;
public
constructor Create(TheCategory: TCircleDiagramCategory);
destructor Destroy; override;
property Category: TCircleDiagramCategory read FCategory;
property Caption: TCaption read FCaption write SetCaption;
property Size: single read FSize write SetSize default DefaultItemSize; // scaled to fit
property StartDegree16: single read FStartDegree16; // 360*16 = one full circle, 0 at 3o'clock
property EndDegree16: single read FEndDegree16; // 360*16 = one full circle, 0 at 3o'clock
end;
{ TCircleDiagramCategory }
TCircleDiagramCategory = class(TPersistent)
private
FCaption: TCaption;
FColor: TColor;
FDiagram: TCustomCircleDiagramControl;
FEndDegree16: single;
FMinSize: single;
fItems: TObjectList; // list of TCircleDiagramItem
FSize: single;
FStartDegree16: single;
function GetItems(Index: integer): TCircleDiagramItem;
procedure SetCaption(AValue: TCaption);
procedure SetColor(AValue: TColor);
procedure SetMinSize(AValue: single);
procedure UpdateLayout;
procedure Invalidate;
procedure InternalRemoveItem(Item: TCircleDiagramItem);
public
constructor Create(TheDiagram: TCustomCircleDiagramControl);
destructor Destroy; override;
function InsertItem(Index: integer; aCaption: string): TCircleDiagramItem;
function AddItem(aCaption: string): TCircleDiagramItem;
property Diagram: TCustomCircleDiagramControl read FDiagram;
property Caption: TCaption read FCaption write SetCaption;
property MinSize: single read FMinSize write SetMinSize default DefaultCategoryMinSize; // scaled to fit
function Count: integer;
property Items[Index: integer]: TCircleDiagramItem read GetItems; default;
property Color: TColor read FColor write SetColor;
property Size: single read FSize;
property StartDegree16: single read FStartDegree16; // 360*16 = one full circle, 0 at 3o'clock
property EndDegree16: single read FEndDegree16; // 360*16 = one full circle, 0 at 3o'clock
end;
TCircleDiagramCtrlFlag = (
cdcNeedUpdateLayout
);
TCircleDiagramCtrlFlags = set of TCircleDiagramCtrlFlag;
{ TCustomCircleDiagramControl }
TCustomCircleDiagramControl = class(TCustomControl)
private
FCategoryGapDegree16: single;
FCenter: TPoint;
FCenterCaption: TCaption;
FCenterCaptionRect: TRect;
FFirstCategoryDegree16: single;
fCategories: TObjectList; // list of TCircleDiagramCategory
FInnerRadius: single;
FOuterRadius: single;
fUpdateLock: integer;
fFlags: TCircleDiagramCtrlFlags;
function GetCategories(Index: integer): TCircleDiagramCategory;
procedure SetCategoryGapDegree16(AValue: single);
procedure SetCenterCaption(AValue: TCaption);
procedure SetFirstCategoryDegree16(AValue: single);
procedure InternalRemoveCategory(Category: TCircleDiagramCategory);
protected
//procedure WMVScroll(var Msg: TLMScroll); message LM_VSCROLL;
//procedure WMMouseWheel(var Message: TLMMouseEvent); message LM_MOUSEWHEEL;
procedure CreateWnd; override;
procedure UpdateScrollBar;
procedure DoSetBounds(ALeft, ATop, AWidth, AHeight: integer); override;
//procedure MouseDown(Button:TMouseButton; Shift:TShiftState; X,Y:integer); override;
//procedure MouseMove(Shift:TShiftState; X,Y:integer); override;
//procedure MouseUp(Button:TMouseButton; Shift:TShiftState; X,Y:integer); override;
//procedure KeyDown(var Key: Word; Shift: TShiftState); override;
//procedure HandleStandardKeys(var Key: Word; Shift: TShiftState); virtual;
//procedure HandleKeyUp(var Key: Word; Shift: TShiftState); virtual;
procedure Paint; override;
procedure DrawCategory(i: integer);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property CenterCaption: TCaption read FCenterCaption write SetCenterCaption;
procedure Clear;
procedure BeginUpdate; virtual;
procedure EndUpdate; virtual;
procedure UpdateLayout;
procedure EraseBackground({%H-}DC: HDC); override;
function InsertCategory(Index: integer; aCaption: TCaption): TCircleDiagramCategory;
function AddCategory(aCaption: TCaption): TCircleDiagramCategory;
function IndexOfCategory(aCaption: TCaption): integer;
function FindCategory(aCaption: TCaption): TCircleDiagramCategory;
property CategoryGapDegree16: single read FCategoryGapDegree16 write SetCategoryGapDegree16 default DefaultCategoryGapDegree16; // 360*16 = one full circle, 0 at 3o'clock
property FirstCategoryDegree16: single read FFirstCategoryDegree16 write SetFirstCategoryDegree16 default DefaultFirstCategoryDegree16; // 360*16 = one full circle, 0 at 3o'clock
function CategoryCount: integer;
property Categories[Index: integer]: TCircleDiagramCategory read GetCategories; default;
property Color default clWhite;
// computed values
property CenterCaptionRect: TRect read FCenterCaptionRect;
property Center: TPoint read FCenter;
property InnerRadius: single read FInnerRadius;
property OuterRadius: single read FOuterRadius;
// debugging
procedure WriteDebugReport(Msg: string);
end;
{ TCircleDiagramControl }
TCircleDiagramControl = class(TCustomCircleDiagramControl)
published
property Align;
property Anchors;
property BorderSpacing;
property BorderStyle;
property BorderWidth;
property Color;
property Constraints;
property DragKind;
property DragCursor;
property DragMode;
property Enabled;
property Font;
property ParentColor default False;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property TabOrder;
property TabStop default True;
property Tag;
property Visible;
property OnClick;
property OnContextPopup;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnMouseDown;
property OnMouseEnter;
property OnMouseLeave;
property OnMouseMove;
property OnMouseUp;
property OnShowHint;
property OnStartDrag;
property OnUTF8KeyPress;
end;
TUDDUsesType = (
uddutInterfaceUses,
uddutImplementationUses,
@ -227,6 +47,7 @@ type
FCurrentUnit: TUGUnit;
FIdleConnected: boolean;
FUsesGraph: TUsesGraph;
FGroups: TUGGroups;
fCircleCategories: array[TUDDUsesType] of TCircleDiagramCategory;
procedure SetCurrentUnit(AValue: TUGUnit);
procedure SetIdleConnected(AValue: boolean);
@ -240,6 +61,7 @@ type
CurUnitDiagram: TCircleDiagramControl;
property IdleConnected: boolean read FIdleConnected write SetIdleConnected;
property UsesGraph: TUsesGraph read FUsesGraph;
property Groups: TUGGroups read FGroups;
property CurrentUnit: TUGUnit read FCurrentUnit write SetCurrentUnit;
end;
@ -248,10 +70,6 @@ var
procedure ShowUnitDependenciesDialog(Sender: TObject);
procedure RingSector(Canvas: TFPCustomCanvas; x1, y1, x2, y2: integer;
InnerSize: single; StartAngle16, EndAngle16: integer); overload;
procedure RingSector(Canvas: TFPCustomCanvas; x1, y1, x2, y2, InnerSize, StartAngle, EndAngle: single); overload;
function dbgs(t: TUDDUsesType): string; overload;
implementation
@ -268,456 +86,11 @@ begin
end;
end;
procedure RingSector(Canvas: TFPCustomCanvas; x1, y1, x2, y2: integer;
InnerSize: single; StartAngle16, EndAngle16: integer);
begin
RingSector(Canvas,single(x1),single(y1),single(x2),single(y2),InnerSize,
single(StartAngle16)/16,single(EndAngle16)/16);
end;
procedure RingSector(Canvas: TFPCustomCanvas; x1, y1, x2, y2, InnerSize, StartAngle,
EndAngle: single);
var
OuterCnt: integer;
centerx, centery: single;
i: Integer;
Ang: single;
OuterRadiusX, OuterRadiusY, InnerRadiusX, InnerRadiusY: single;
Points: array of TPoint;
j: Integer;
begin
OuterCnt:=Round(SQRT((Abs(x2-x1)+Abs(y2-y1))*Abs(EndAngle-StartAngle)/FullCircle16)+0.5);
centerx:=(x1+x2)/2;
centery:=(y1+y2)/2;
OuterRadiusX:=(x2-x1)/2;
OuterRadiusY:=(y2-y1)/2;
InnerRadiusX:=OuterRadiusX*InnerSize;
InnerRadiusY:=OuterRadiusY*InnerSize;
SetLength(Points,OuterCnt*2+2);
j:=0;
// outer arc
for i:=0 to OuterCnt do begin
Ang:=StartAngle+((EndAngle-StartAngle)/OuterCnt)*single(i);
Ang:=(Ang/FullCircle16)*2*pi;
Points[j].x:=round(centerx+cos(Ang)*OuterRadiusX);
Points[j].y:=round(centery-sin(Ang)*OuterRadiusY);
inc(j);
end;
// inner arc
for i:=OuterCnt downto 0 do begin
Ang:=StartAngle+((EndAngle-StartAngle)/OuterCnt)*single(i);
Ang:=(Ang/FullCircle16)*2*pi;
Points[j].x:=round(centerx+cos(Ang)*InnerRadiusX);
Points[j].y:=round(centery-sin(Ang)*InnerRadiusY);
inc(j);
end;
Canvas.Polygon(Points);
SetLength(Points,0);
end;
function dbgs(t: TUDDUsesType): string;
begin
Result:=GetEnumName(typeinfo(TUDDUsesType),ord(t));
end;
{ TCustomCircleDiagramControl }
procedure TCustomCircleDiagramControl.SetCategoryGapDegree16(AValue: single);
begin
if AValue<0 then AValue:=0;
if AValue>0.3 then AValue:=0.3;
if FCategoryGapDegree16=AValue then Exit;
FCategoryGapDegree16:=AValue;
UpdateLayout;
end;
function TCustomCircleDiagramControl.GetCategories(Index: integer
): TCircleDiagramCategory;
begin
Result:=TCircleDiagramCategory(fCategories[Index]);
end;
procedure TCustomCircleDiagramControl.SetCenterCaption(AValue: TCaption);
begin
if FCenterCaption=AValue then Exit;
FCenterCaption:=AValue;
UpdateLayout;
end;
procedure TCustomCircleDiagramControl.SetFirstCategoryDegree16(AValue: single);
begin
if FFirstCategoryDegree16=AValue then Exit;
FFirstCategoryDegree16:=AValue;
UpdateLayout;
end;
procedure TCustomCircleDiagramControl.InternalRemoveCategory(
Category: TCircleDiagramCategory);
begin
fCategories.Remove(Category);
UpdateLayout;
end;
procedure TCustomCircleDiagramControl.CreateWnd;
begin
inherited CreateWnd;
UpdateScrollBar;
end;
procedure TCustomCircleDiagramControl.UpdateScrollBar;
begin
end;
procedure TCustomCircleDiagramControl.DoSetBounds(ALeft, ATop, AWidth,
AHeight: integer);
begin
inherited DoSetBounds(ALeft, ATop, AWidth, AHeight);
UpdateScrollBar;
end;
procedure TCustomCircleDiagramControl.Paint;
var
i: Integer;
begin
inherited Paint;
if cdcNeedUpdateLayout in fFlags then
UpdateLayout;
// background
Canvas.Brush.Style:=bsSolid;
Canvas.Brush.Color:=Color;
Canvas.FillRect(ClientRect);
Canvas.Brush.Color:=clRed;
// draw categories
for i:=0 to CategoryCount-1 do
DrawCategory(i);
// center caption
Canvas.Brush.Style:=bsSolid;
Canvas.Brush.Color:=clNone;
Canvas.TextOut(FCenterCaptionRect.Left,FCenterCaptionRect.Top,CenterCaption);
end;
procedure TCustomCircleDiagramControl.DrawCategory(i: integer);
var
Cat: TCircleDiagramCategory;
begin
Cat:=Categories[i];
Canvas.Brush.Color:=Cat.Color;
RingSector(Canvas,Center.X-OuterRadius,Center.Y-OuterRadius,
Center.X+OuterRadius,Center.Y+OuterRadius,
single(InnerRadius)/single(OuterRadius),
Cat.StartDegree16,Cat.EndDegree16);
end;
constructor TCustomCircleDiagramControl.Create(AOwner: TComponent);
begin
BeginUpdate;
try
inherited Create(AOwner);
fCategories:=TObjectList.create(true);
FFirstCategoryDegree16:=DefaultFirstCategoryDegree16;
FCategoryGapDegree16:=DefaultCategoryGapDegree16;
Color:=clWhite;
finally
EndUpdate;
end;
end;
destructor TCustomCircleDiagramControl.Destroy;
begin
BeginUpdate; // disable updates
FreeAndNil(fCategories);
inherited Destroy;
end;
procedure TCustomCircleDiagramControl.Clear;
begin
BeginUpdate;
try
while CategoryCount>0 do
Categories[0].Free;
finally
EndUpdate;
end;
end;
procedure TCustomCircleDiagramControl.BeginUpdate;
begin
inc(fUpdateLock);
end;
procedure TCustomCircleDiagramControl.EndUpdate;
begin
if fUpdateLock=0 then
raise Exception.Create('TCustomCircleDiagramControl.EndUpdate');
dec(fUpdateLock);
if fUpdateLock=0 then begin
if cdcNeedUpdateLayout in fFlags then
UpdateLayout;
end;
end;
procedure TCustomCircleDiagramControl.UpdateLayout;
var
aSize: TSize;
aCategory: TCircleDiagramCategory;
i: Integer;
j: Integer;
TotalSize: Single;
CurCategoryDegree: Single;
GapDegree: Single;
TotalItemDegree: Single;
Item: TCircleDiagramItem;
CurItemDegree: Single;
begin
if (fUpdateLock>0) or (not IsVisible) or (not HandleAllocated) then begin
Include(fFlags,cdcNeedUpdateLayout);
exit;
end;
Exclude(fFlags,cdcNeedUpdateLayout);
// center caption
FCenter:=Point(ClientWidth div 2,ClientHeight div 2);
aSize:=Canvas.TextExtent(CenterCaption);
FCenterCaptionRect:=Bounds(FCenter.X-(aSize.cx div 2),FCenter.Y-(aSize.cy div 2)
,aSize.cx,aSize.cy);
// radius
fInnerRadius:=0.25*Min(ClientWidth,ClientHeight);
fOuterRadius:=1.1*InnerRadius;
// degrees
TotalSize:=0.0;
CurCategoryDegree:=FirstCategoryDegree16;
if CategoryCount>0 then begin
// calculate TotalSize
for i:=0 to CategoryCount-1 do begin
aCategory:=Categories[i];
aCategory.FSize:=0;
for j:=0 to aCategory.Count-1 do
aCategory.FSize+=aCategory[j].Size;
aCategory.FSize:=Max(aCategory.FSize,aCategory.MinSize);
TotalSize+=aCategory.FSize;
end;
// calculate degrees
GapDegree:=Min(CategoryGapDegree16,(0.8/CategoryCount)*FullCircle16);
TotalItemDegree:=FullCircle16-(GapDegree*CategoryCount);
for i:=0 to CategoryCount-1 do begin
aCategory:=Categories[i];
aCategory.FStartDegree16:=CurCategoryDegree;
if TotalSize>0 then
CurCategoryDegree+=TotalItemDegree*aCategory.Size/TotalSize;
aCategory.FEndDegree16:=CurCategoryDegree;
// item degrees
CurItemDegree:=aCategory.StartDegree16;
for j:=0 to aCategory.Count-1 do begin
Item:=aCategory[j];
Item.FStartDegree16:=CurItemDegree;
if aCategory.Size>0 then
CurItemDegree+=(aCategory.EndDegree16-aCategory.StartDegree16)*Item.Size/aCategory.Size;
Item.FEndDegree16:=CurItemDegree;
end;
CurCategoryDegree+=GapDegree;
end;
end;
WriteDebugReport('TCustomCircleDiagramControl.UpdateLayout');
end;
procedure TCustomCircleDiagramControl.EraseBackground(DC: HDC);
begin
// do not erase background, Paint will paint the whole area
end;
function TCustomCircleDiagramControl.InsertCategory(Index: integer;
aCaption: TCaption): TCircleDiagramCategory;
begin
Result:=TCircleDiagramCategory.Create(Self);
Result.Caption:=aCaption;
fCategories.Insert(Index,Result);
end;
function TCustomCircleDiagramControl.AddCategory(aCaption: TCaption
): TCircleDiagramCategory;
begin
Result:=InsertCategory(CategoryCount,aCaption);
end;
function TCustomCircleDiagramControl.IndexOfCategory(aCaption: TCaption
): integer;
begin
Result:=CategoryCount-1;
while Result>=0 do begin
if Categories[Result].Caption=aCaption then exit;
dec(Result);
end;
end;
function TCustomCircleDiagramControl.FindCategory(aCaption: TCaption
): TCircleDiagramCategory;
var
i: Integer;
begin
i:=IndexOfCategory(aCaption);
if i>=0 then
Result:=Categories[i]
else
Result:=nil;
end;
function TCustomCircleDiagramControl.CategoryCount: integer;
begin
Result:=fCategories.Count;
end;
procedure TCustomCircleDiagramControl.WriteDebugReport(Msg: string);
var
aCat: TCircleDiagramCategory;
i: Integer;
j: Integer;
Item: TCircleDiagramItem;
begin
debugln([Msg,' CategoryCount=',CategoryCount]);
for i:=0 to CategoryCount-1 do begin
aCat:=Categories[i];
debugln([' Category: ',i,'/',CategoryCount,' ',aCat.Caption,
' MinSize=',aCat.MinSize,
' Size=',aCat.Size,
' Start=',round(aCat.StartDegree16),' End=',round(aCat.EndDegree16)]);
for j:=0 to aCat.Count-1 do begin
Item:=aCat.Items[j];
debugln([' Item: ',j,'/',aCat.Count,' ',Item.Caption,
' Size=',Item.Size,
' Start=',round(Item.StartDegree16),
' End=',round(Item.EndDegree16)]);
end;
end;
end;
{ TCircleDiagramCategory }
procedure TCircleDiagramCategory.SetCaption(AValue: TCaption);
begin
if FCaption=AValue then Exit;
FCaption:=AValue;
end;
procedure TCircleDiagramCategory.SetColor(AValue: TColor);
begin
if FColor=AValue then Exit;
FColor:=AValue;
Invalidate;
end;
function TCircleDiagramCategory.GetItems(Index: integer): TCircleDiagramItem;
begin
Result:=TCircleDiagramItem(fItems[Index]);
end;
procedure TCircleDiagramCategory.SetMinSize(AValue: single);
begin
if AValue<0 then AValue:=0;
if FMinSize=AValue then Exit;
FMinSize:=AValue;
UpdateLayout;
end;
procedure TCircleDiagramCategory.UpdateLayout;
begin
if Diagram<>nil then
Diagram.UpdateLayout;
end;
procedure TCircleDiagramCategory.Invalidate;
begin
if Diagram<>nil then
Diagram.Invalidate;
end;
procedure TCircleDiagramCategory.InternalRemoveItem(Item: TCircleDiagramItem);
begin
fItems.Remove(Item);
UpdateLayout;
end;
constructor TCircleDiagramCategory.Create(
TheDiagram: TCustomCircleDiagramControl);
begin
FDiagram:=TheDiagram;
fItems:=TObjectList.Create(true);
FMinSize:=DefaultCategoryMinSize;
end;
destructor TCircleDiagramCategory.Destroy;
begin
if Diagram<>nil then
Diagram.InternalRemoveCategory(Self);
FreeAndNil(fItems);
inherited Destroy;
end;
function TCircleDiagramCategory.InsertItem(Index: integer; aCaption: string
): TCircleDiagramItem;
begin
Result:=TCircleDiagramItem.Create(Self);
Result.Caption:=aCaption;
fItems.Insert(Index,Result);
end;
function TCircleDiagramCategory.AddItem(aCaption: string): TCircleDiagramItem;
begin
Result:=InsertItem(Count,aCaption);
end;
function TCircleDiagramCategory.Count: integer;
begin
Result:=fItems.Count;
end;
{ TCircleDiagramItem }
procedure TCircleDiagramItem.SetCaption(AValue: TCaption);
begin
if FCaption=AValue then Exit;
FCaption:=AValue;
UpdateLayout;
end;
procedure TCircleDiagramItem.SetSize(AValue: single);
begin
if AValue<0 then AValue:=0;
if FSize=AValue then Exit;
FSize:=AValue;
UpdateLayout;
end;
procedure TCircleDiagramItem.UpdateLayout;
begin
if Category<>nil then
Category.UpdateLayout;
end;
constructor TCircleDiagramItem.Create(TheCategory: TCircleDiagramCategory);
begin
FCategory:=TheCategory;
FSize:=DefaultItemSize;
end;
destructor TCircleDiagramItem.Destroy;
begin
if Category<>nil then
Category.InternalRemoveItem(Self);
inherited Destroy;
end;
{ TUnitDependenciesDialog }
procedure TUnitDependenciesDialog.CloseBitBtnClick(Sender: TObject);
@ -745,6 +118,7 @@ end;
procedure TUnitDependenciesDialog.FormCreate(Sender: TObject);
begin
FUsesGraph:=CodeToolBoss.CreateUsesGraph;
FGroups:=TUGGroups.Create(FUsesGraph);
ProgressBar1.Style:=pbstMarquee;
AddStartAndTargetUnits;
@ -776,6 +150,7 @@ end;
procedure TUnitDependenciesDialog.FormDestroy(Sender: TObject);
begin
IdleConnected:=false;
FreeAndNil(FGroups);
FreeAndNil(FUsesGraph);
end;