mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-11-24 15:10:13 +01:00
cody: lvlgraph: highlight node under mouse
git-svn-id: trunk@40311 -
This commit is contained in:
parent
bec25eb2c8
commit
9895968bea
@ -230,19 +230,6 @@ type
|
|||||||
property OnUTF8KeyPress;
|
property OnUTF8KeyPress;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
const
|
|
||||||
DefaultLvlGraphNodeWith = 10;
|
|
||||||
DefaultLvlGraphNodeCaptionScale = 0.7;
|
|
||||||
|
|
||||||
type
|
|
||||||
TLvlGraphCtrlOption = (
|
|
||||||
lgoAutoLayout
|
|
||||||
);
|
|
||||||
TLvlGraphCtrlOptions = set of TLvlGraphCtrlOption;
|
|
||||||
TOnLvlGraphStructureChanged = procedure(Sender, Element: TObject; Operation: TOperation) of object;
|
|
||||||
|
|
||||||
const
|
|
||||||
DefaultLvlGraphCtrlOptions = [lgoAutoLayout];
|
|
||||||
type
|
type
|
||||||
TLvlGraph = class;
|
TLvlGraph = class;
|
||||||
TLvlGraphEdge = class;
|
TLvlGraphEdge = class;
|
||||||
@ -343,6 +330,9 @@ type
|
|||||||
end;
|
end;
|
||||||
TLvlGraphLevelClass = class of TLvlGraphLevel;
|
TLvlGraphLevelClass = class of TLvlGraphLevel;
|
||||||
|
|
||||||
|
TOnLvlGraphStructureChanged = procedure(Sender, Element: TObject;
|
||||||
|
Operation: TOperation) of object;
|
||||||
|
|
||||||
{ TLvlGraph }
|
{ TLvlGraph }
|
||||||
|
|
||||||
TLvlGraph = class(TPersistent)
|
TLvlGraph = class(TPersistent)
|
||||||
@ -403,6 +393,21 @@ type
|
|||||||
procedure ConsistencyCheck(WithBackEdge: boolean);
|
procedure ConsistencyCheck(WithBackEdge: boolean);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
const
|
||||||
|
DefaultLvlGraphNodeWith = 10;
|
||||||
|
DefaultLvlGraphNodeCaptionScale = 0.7;
|
||||||
|
|
||||||
|
type
|
||||||
|
TLvlGraphCtrlOption = (
|
||||||
|
lgoAutoLayout, // automatic graph layout after graph was changed
|
||||||
|
lgoHighlightNodeOnMouse // when mouse over node highlight node and its edges
|
||||||
|
);
|
||||||
|
TLvlGraphCtrlOptions = set of TLvlGraphCtrlOption;
|
||||||
|
|
||||||
|
const
|
||||||
|
DefaultLvlGraphCtrlOptions = [lgoAutoLayout,lgoHighlightNodeOnMouse];
|
||||||
|
|
||||||
|
type
|
||||||
TLvlGraphControlFlag = (
|
TLvlGraphControlFlag = (
|
||||||
lgcNeedInvalidate,
|
lgcNeedInvalidate,
|
||||||
lgcNeedAutoLayout,
|
lgcNeedAutoLayout,
|
||||||
@ -415,11 +420,15 @@ type
|
|||||||
TCustomLvlGraphControl = class(TCustomControl)
|
TCustomLvlGraphControl = class(TCustomControl)
|
||||||
private
|
private
|
||||||
FGraph: TLvlGraph;
|
FGraph: TLvlGraph;
|
||||||
|
FMouseOverNode: TLvlGraphNode;
|
||||||
FNodeCaptionScale: single;
|
FNodeCaptionScale: single;
|
||||||
FNodeWidth: integer;
|
FNodeWidth: integer;
|
||||||
FOptions: TLvlGraphCtrlOptions;
|
FOptions: TLvlGraphCtrlOptions;
|
||||||
fUpdateLock: integer;
|
fUpdateLock: integer;
|
||||||
FFlags: TLvlGraphControlFlags;
|
FFlags: TLvlGraphControlFlags;
|
||||||
|
procedure DrawEdges(Highlighted: boolean);
|
||||||
|
procedure DrawNodes;
|
||||||
|
procedure SetMouseOverNode(AValue: TLvlGraphNode);
|
||||||
procedure SetNodeWidth(AValue: integer);
|
procedure SetNodeWidth(AValue: integer);
|
||||||
procedure SetOptions(AValue: TLvlGraphCtrlOptions);
|
procedure SetOptions(AValue: TLvlGraphCtrlOptions);
|
||||||
protected
|
protected
|
||||||
@ -427,6 +436,7 @@ type
|
|||||||
procedure GraphStructureChanged(Sender, Element: TObject; {%H-}Operation: TOperation); virtual;
|
procedure GraphStructureChanged(Sender, Element: TObject; {%H-}Operation: TOperation); virtual;
|
||||||
procedure DoSetBounds(ALeft, ATop, AWidth, AHeight: integer); override;
|
procedure DoSetBounds(ALeft, ATop, AWidth, AHeight: integer); override;
|
||||||
procedure Paint; override;
|
procedure Paint; override;
|
||||||
|
procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
|
||||||
public
|
public
|
||||||
constructor Create(AOwner: TComponent); override;
|
constructor Create(AOwner: TComponent); override;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
@ -436,7 +446,9 @@ type
|
|||||||
procedure Invalidate; override;
|
procedure Invalidate; override;
|
||||||
procedure BeginUpdate;
|
procedure BeginUpdate;
|
||||||
procedure EndUpdate;
|
procedure EndUpdate;
|
||||||
|
function GetNodeAt(X,Y: integer): TLvlGraphNode;
|
||||||
property NodeWidth: integer read FNodeWidth write SetNodeWidth default DefaultLvlGraphNodeWith;
|
property NodeWidth: integer read FNodeWidth write SetNodeWidth default DefaultLvlGraphNodeWith;
|
||||||
|
property MouseOverNode: TLvlGraphNode read FMouseOverNode write SetMouseOverNode;
|
||||||
property Options: TLvlGraphCtrlOptions read FOptions write SetOptions default DefaultLvlGraphCtrlOptions;
|
property Options: TLvlGraphCtrlOptions read FOptions write SetOptions default DefaultLvlGraphCtrlOptions;
|
||||||
property NodeCaptionScale: single read FNodeCaptionScale write FNodeCaptionScale default DefaultLvlGraphNodeCaptionScale;
|
property NodeCaptionScale: single read FNodeCaptionScale write FNodeCaptionScale default DefaultLvlGraphNodeCaptionScale;
|
||||||
end;
|
end;
|
||||||
@ -733,6 +745,8 @@ procedure TCustomLvlGraphControl.GraphStructureChanged(Sender,
|
|||||||
begin
|
begin
|
||||||
if ((Element is TLvlGraphNode)
|
if ((Element is TLvlGraphNode)
|
||||||
or (Element is TLvlGraphEdge)) then begin
|
or (Element is TLvlGraphEdge)) then begin
|
||||||
|
if FMouseOverNode=Element then
|
||||||
|
FMouseOverNode:=nil;
|
||||||
debugln(['TCustomLvlGraphControl.GraphStructureChanged ']);
|
debugln(['TCustomLvlGraphControl.GraphStructureChanged ']);
|
||||||
if lgoAutoLayout in FOptions then
|
if lgoAutoLayout in FOptions then
|
||||||
Include(FFlags,lgcNeedAutoLayout);
|
Include(FFlags,lgcNeedAutoLayout);
|
||||||
@ -746,6 +760,73 @@ begin
|
|||||||
Invalidate;
|
Invalidate;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TCustomLvlGraphControl.SetMouseOverNode(AValue: TLvlGraphNode);
|
||||||
|
begin
|
||||||
|
if FMouseOverNode=AValue then Exit;
|
||||||
|
FMouseOverNode:=AValue;
|
||||||
|
Invalidate;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCustomLvlGraphControl.DrawEdges(Highlighted: boolean);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
Level: TLvlGraphLevel;
|
||||||
|
j: Integer;
|
||||||
|
Node: TLvlGraphNode;
|
||||||
|
k: Integer;
|
||||||
|
Edge: TLvlGraphEdge;
|
||||||
|
TargetNode: TLvlGraphNode;
|
||||||
|
NodeHighlighted: Boolean;
|
||||||
|
begin
|
||||||
|
for i:=0 to Graph.LevelCount-1 do begin
|
||||||
|
Level:=Graph.Levels[i];
|
||||||
|
for j:=0 to Level.Count-1 do begin
|
||||||
|
Node:=Level.Nodes[j];
|
||||||
|
for k:=0 to Node.OutEdgeCount-1 do begin
|
||||||
|
Edge:=Node.OutEdges[k];
|
||||||
|
TargetNode:=Edge.Target;
|
||||||
|
NodeHighlighted:=(Node=MouseOverNode) or (TargetNode=MouseOverNode);
|
||||||
|
if NodeHighlighted<>Highlighted then continue;
|
||||||
|
if TargetNode.Level.Index>Level.Index then begin
|
||||||
|
// normal dependency
|
||||||
|
if NodeHighlighted then
|
||||||
|
Canvas.Pen.Color:=clGray
|
||||||
|
else
|
||||||
|
Canvas.Pen.Color:=clSilver;
|
||||||
|
Canvas.Line(Level.DrawPosition+NodeWidth, Node.DrawCenter,
|
||||||
|
TargetNode.Level.DrawPosition, TargetNode.DrawCenter);
|
||||||
|
end else begin
|
||||||
|
// cycle dependency
|
||||||
|
Canvas.Pen.Color:=clRed;
|
||||||
|
Canvas.Line(Level.DrawPosition, Node.DrawCenter,
|
||||||
|
TargetNode.Level.DrawPosition+NodeWidth, TargetNode.DrawCenter);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TCustomLvlGraphControl.DrawNodes;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
Level: TLvlGraphLevel;
|
||||||
|
j: Integer;
|
||||||
|
Node: TLvlGraphNode;
|
||||||
|
begin
|
||||||
|
Canvas.Brush.Style:=bsSolid;
|
||||||
|
for i:=0 to Graph.LevelCount-1 do begin
|
||||||
|
Level:=Graph.Levels[i];
|
||||||
|
for j:=0 to Level.Count-1 do begin
|
||||||
|
Node:=Level.Nodes[j];
|
||||||
|
//debugln(['TCustomLvlGraphControl.Paint ',Node.Caption,' ',dbgs(FPColorToTColor(Node.Color)),' Level.DrawPosition=',Level.DrawPosition,' Node.DrawPosition=',Node.DrawPosition,' ',Node.DrawPositionEnd]);
|
||||||
|
Canvas.Brush.Color:=FPColorToTColor(Node.Color);
|
||||||
|
Canvas.Pen.Color:=Darker(Canvas.Brush.Color);
|
||||||
|
Canvas.Rectangle(Level.DrawPosition, Node.DrawPosition,
|
||||||
|
Level.DrawPosition+NodeWidth, Node.DrawPositionEnd);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TCustomLvlGraphControl.SetOptions(AValue: TLvlGraphCtrlOptions);
|
procedure TCustomLvlGraphControl.SetOptions(AValue: TLvlGraphCtrlOptions);
|
||||||
begin
|
begin
|
||||||
if FOptions=AValue then Exit;
|
if FOptions=AValue then Exit;
|
||||||
@ -766,10 +847,7 @@ var
|
|||||||
Level: TLvlGraphLevel;
|
Level: TLvlGraphLevel;
|
||||||
j: Integer;
|
j: Integer;
|
||||||
Node: TLvlGraphNode;
|
Node: TLvlGraphNode;
|
||||||
k: Integer;
|
|
||||||
Edge: TLvlGraphEdge;
|
|
||||||
begin
|
begin
|
||||||
debugln(['TCustomLvlGraphControl.Paint ']);
|
|
||||||
inherited Paint;
|
inherited Paint;
|
||||||
|
|
||||||
Canvas.Font.Assign(Font);
|
Canvas.Font.Assign(Font);
|
||||||
@ -797,41 +875,10 @@ begin
|
|||||||
Canvas.TextOut((ClientWidth-w) div 2,round(0.25*TxtH),Caption);
|
Canvas.TextOut((ClientWidth-w) div 2,round(0.25*TxtH),Caption);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// draw edges
|
// draw edges and nodes
|
||||||
for i:=0 to Graph.LevelCount-1 do begin
|
DrawEdges(false); // draw normal edges
|
||||||
Level:=Graph.Levels[i];
|
DrawEdges(true); // draw highlighted edges
|
||||||
for j:=0 to Level.Count-1 do begin
|
DrawNodes;
|
||||||
Node:=Level.Nodes[j];
|
|
||||||
for k:=0 to Node.OutEdgeCount-1 do begin
|
|
||||||
Edge:=Node.OutEdges[k];
|
|
||||||
if Edge.Target.Level.Index>Level.Index then begin
|
|
||||||
// normal dependency
|
|
||||||
Canvas.Pen.Color:=clSilver;
|
|
||||||
Canvas.Line(Level.DrawPosition+NodeWidth,Node.DrawCenter,
|
|
||||||
Edge.Target.Level.DrawPosition,Edge.Target.DrawCenter);
|
|
||||||
end else begin
|
|
||||||
// cycle dependency
|
|
||||||
Canvas.Pen.Color:=clRed;
|
|
||||||
Canvas.Line(Level.DrawPosition,Node.DrawCenter,
|
|
||||||
Edge.Target.Level.DrawPosition+NodeWidth,Edge.Target.DrawCenter);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// draw nodes
|
|
||||||
Canvas.Brush.Style:=bsSolid;
|
|
||||||
for i:=0 to Graph.LevelCount-1 do begin
|
|
||||||
Level:=Graph.Levels[i];
|
|
||||||
for j:=0 to Level.Count-1 do begin
|
|
||||||
Node:=Level.Nodes[j];
|
|
||||||
//debugln(['TCustomLvlGraphControl.Paint ',Node.Caption,' ',dbgs(FPColorToTColor(Node.Color)),' Level.DrawPosition=',Level.DrawPosition,' Node.DrawPosition=',Node.DrawPosition,' ',Node.DrawPositionEnd]);
|
|
||||||
Canvas.Brush.Color:=FPColorToTColor(Node.Color);
|
|
||||||
Canvas.Pen.Color:=Darker(Canvas.Brush.Color);
|
|
||||||
Canvas.Rectangle(Level.DrawPosition,Node.DrawPosition,
|
|
||||||
Level.DrawPosition+NodeWidth,Node.DrawPositionEnd);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// draw captions
|
// draw captions
|
||||||
Canvas.Brush.Style:=bsClear;
|
Canvas.Brush.Style:=bsClear;
|
||||||
@ -847,6 +894,12 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TCustomLvlGraphControl.MouseMove(Shift: TShiftState; X, Y: Integer);
|
||||||
|
begin
|
||||||
|
inherited MouseMove(Shift, X, Y);
|
||||||
|
MouseOverNode:=GetNodeAt(X,Y);
|
||||||
|
end;
|
||||||
|
|
||||||
constructor TCustomLvlGraphControl.Create(AOwner: TComponent);
|
constructor TCustomLvlGraphControl.Create(AOwner: TComponent);
|
||||||
begin
|
begin
|
||||||
inherited Create(AOwner);
|
inherited Create(AOwner);
|
||||||
@ -961,6 +1014,26 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TCustomLvlGraphControl.GetNodeAt(X, Y: integer): TLvlGraphNode;
|
||||||
|
var
|
||||||
|
l: Integer;
|
||||||
|
Level: TLvlGraphLevel;
|
||||||
|
n: Integer;
|
||||||
|
Node: TLvlGraphNode;
|
||||||
|
begin
|
||||||
|
Result:=nil;
|
||||||
|
// check in reverse painting order
|
||||||
|
for l:=Graph.LevelCount-1 downto 0 do begin
|
||||||
|
Level:=Graph.Levels[l];
|
||||||
|
if (x<Level.DrawPosition) or (x>=Level.DrawPosition+NodeWidth) then continue;
|
||||||
|
for n:=Level.Count-1 downto 0 do begin
|
||||||
|
Node:=Level.Nodes[n];
|
||||||
|
if (y<Node.DrawPosition) or (y>=Node.DrawPositionEnd) then continue;
|
||||||
|
exit(Node);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
||||||
{ TGraphLevelerNode - used by TLvlGraph.UpdateLevels }
|
{ TGraphLevelerNode - used by TLvlGraph.UpdateLevels }
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user