|
From: Stefan M. <ste...@po...> - 2005-02-23 11:49:29
|
Hey,
=20
Since we're throwing code around, I thought I'd join in on the fun :)
Here's my code for the BezierLink, it does however have a "problem":
I don't know how to implement the DrawText for this thing, where =
*should* we put the text, any ideas?
=20
As you can see I've renamed TSimpleGraph to TExtGraph, I think that'll =
be a good thing for the next release.
=20
Cheers,
Stefan
=20
=20
TMarkerType =3D (mtNone, mtSizeW, mtSizeE, mtSizeN, mtSizeS, mtSizeNW,
mtSizeNE, mtSizeSW, mtSizeSE, mtMove, mtMoveStrartPt, mtMoveEndPt,
mtSelect, mtStretchBezier); (* SM - added mtStretchBezier for =
TBezierLink *)
=20
TGraphMouseState =3D (gsNone, gsMoveResizeNode, gsSelectRect, =
gsMoveLink, gsStretchBezier);
(* SM - added gsStretchBezier for TBezierLink *)
=20
TBezierLink =3D class(TGraphLink)
class procedure DrawDraft(Canvas: TCanvas; const ARect: TRect); =
override; =20
procedure DrawBody(Canvas: TCanvas); override;
protected
function FindMarkerAt(X, Y: Integer): TMarkerType; override;
procedure DrawMarkers(Canvas: TCanvas); override;
private
fPointsAltered : Boolean;
public
points: array [0..3] of TPoint;
NumLine: integer;
lpPoints: array of TPoint;
lpTypes: array of Byte;
DraggingPoint: integer;
function ContainsPoint(X, Y: Integer): Boolean; override;
destructor Destroy; override;
end;
=20
{ TBezierLink }
function TBezierLink.ContainsPoint(X, Y: Integer): Boolean;
var
Margin: Integer;
R: TRect;
i: integer;
begin
Result :=3D False;
if Showing and (FromNode <> nil) and (ToNode <> nil) then begin
if (TextRegion <> 0) and PtInRegion(TextRegion, X, Y) then
Result :=3D True
else begin
if Selected then begin
for i :=3D 1 to 2 do begin
with points[i] do SetRect(r, X, Y, X, Y);
InflateRect(r, Owner.MarkerSize, Owner.MarkerSize);
Result :=3D PtInRect(r, Point(X,Y));
if result then Exit;
end;
end;
for i :=3D 1 to NumLine-1 do begin
Margin :=3D Pen.Width + Owner.MarkerSize;
Margin :=3D Margin div 2;
R :=3D MakeRect(Point(lppoints[i-1].x, lppoints[i-1].y), =
Point(lppoints[i].x, lppoints[i].y));
InflateRect(R, Margin, Margin);
Result :=3D PtInRect(R, Point(X, Y));
if Result then Break;
end;
end;
end;
end;
=20
destructor TBezierLink.Destroy;
begin
SetLength(lpPoints, 0);
SetLength(lpTypes, 0);
inherited;
end;
procedure TBezierLink.DrawBody(Canvas: TCanvas);
var
i: integer;
// r: TRect;
// Margin: Integer;
begin
with StartPt do Canvas.MoveTo(X, Y);
if (points[0].x <> StartPt.x) or=20
(points[0].y <> StartPt.y) or=20
(points[3].x <> EndPt.x) or=20
(points[3].y <> EndPt.y) then begin
points[0] :=3D StartPt;
if not fPointsAltered then points[1] :=3D Point(StartPt.x, EndPt.Y);
if not fPointsAltered then points[2] :=3D Point(EndPt.x, StartPt.y);
points[3] :=3D EndPt;
end;
BeginPath(Canvas.Handle);
PolyBezier(Canvas.Handle, Points, 4);
EndPath(Canvas.Handle);
FlattenPath(Canvas.Handle);
NumLine :=3D getpath(Canvas.Handle, lpPoints, lpTypes, 0);
setlength(lppoints, NumLine);
setlength(lptypes, NumLine);
GetPath(Canvas.Handle, lppoints[0], lptypes[0], NumLine);
for i :=3D 0 to NumLine-1 do begin
case lpTypes[i] of
PT_MOVETO: Canvas.MoveTo(lppoints[i].x, lppoints[i].y);
PT_LINETO: Canvas.LineTo(lppoints[i].x, lppoints[i].y);
end;
end;
// Shows the Rectangles which are used in ContainsPoint():
// for i :=3D 1 to NumLine-1 do begin
// Margin :=3D Pen.Width + Owner.MarkerSize;
// Margin :=3D Margin div 2;
// R :=3D MakeRect(Point(lppoints[i-1].x, lppoints[i-1].y), =
Point(lppoints[i].x, lppoints[i].y));
// InflateRect(R, Margin, Margin);
// Canvas.Rectangle(R);
// end;
end;
=20
class procedure TBezierLink.DrawDraft(Canvas: TCanvas; const ARect: =
TRect);
var
i: integer;
points: array [0..3] of TPoint;
NumLine: integer;
lpPoints: array of TPoint;
lpTypes: array of Byte;
begin
Canvas.MoveTo(Arect.TopLeft.X, Arect.TopLeft.Y);
if (points[0].x <> Arect.TopLeft.X) or=20
(points[0].y <> Arect.TopLeft.Y) or=20
(points[3].x <> Arect.BottomRight.x) or=20
(points[3].y <> Arect.BottomRight.y) then begin
points[0] :=3D Arect.TopLeft;
points[1] :=3D Point(Arect.TopLeft.x, Arect.BottomRight.Y);
points[2] :=3D Point(Arect.BottomRight.x, Arect.TopLeft.y);
points[3] :=3D Arect.BottomRight;
end;
BeginPath(Canvas.Handle);
PolyBezier(Canvas.Handle, Points, 4);
EndPath(Canvas.Handle);
FlattenPath(Canvas.Handle);
NumLine :=3D getpath(Canvas.Handle, lpPoints, lpTypes, 0);
setlength(lppoints, NumLine);
setlength(lptypes, NumLine);
GetPath(Canvas.Handle, lppoints[0], lptypes[0], NumLine);
for i :=3D 0 to NumLine-1 do begin
case lpTypes[i] of
PT_MOVETO: Canvas.MoveTo(lppoints[i].x, lppoints[i].y);
PT_LINETO: Canvas.LineTo(lppoints[i].x, lppoints[i].y);
end;
end;
end;
=20
procedure TBezierLink.DrawMarkers(Canvas: TCanvas);
var
i: integer;
r: TRect;
begin
inherited;
if Selected then begin
for i :=3D 1 to 2 do begin
with points[i] do SetRect(r, X, Y, X, Y);
InflateRect(r, Owner.MarkerSize, Owner.MarkerSize);
Canvas.FrameRect(r);
end;
end;
end;
=20
function TBezierLink.FindMarkerAt(X, Y: Integer): TMarkerType;
var
Marker: TMarkerType;
Pt: TPoint;
i: integer;
r: TRect;
begin
Result :=3D mtNone;
if Showing then begin
if Selected then begin
Pt :=3D Point(X, Y);
for Marker :=3D mtMoveStrartPt to mtMoveEndPt do begin
if PtInRect(MarkerRect(Marker), Pt) then begin
Result :=3D Marker;
Exit;
end;
end;
for i :=3D 1 to 2 do begin
with points[i] do SetRect(r, X, Y, X, Y);
InflateRect(r, Owner.MarkerSize, Owner.MarkerSize);
if PtInRect(r, Pt) then begin
Result :=3D mtStretchBezier;
DraggingPoint :=3D i;
Exit;
end;
end;
end;
if ContainsPoint(X, Y, true) then
Result :=3D mtSelect;
end;
end;
=20
{ / TBezierLink }
=20
procedure TExtGraph.MouseDown(Button: TMouseButton; Shift: TShiftState; =
X, Y: Integer);
var
Pt: TPoint;
begin
...
// A Link is under cursor
else
begin
if (Button =3D mbLeft) and not=20
(ssDouble in Shift) and=20
(MarkerAtCursor in [mtMoveEndPt, mtMoveStrartPt]) then begin
if MarkerAtCursor =3D mtMoveEndPt then
StartPoint :=3D TGraphLink(ObjectAtCursor).FromNode.Center
else
StartPoint :=3D TGraphLink(ObjectAtCursor).ToNode.Center;
StopPoint :=3D Pt;
State :=3D gsMoveLink;
Linking :=3D True;
end;
if (Button =3D mbLeft) and not=20
(ssDouble in Shift) and=20
(MarkerAtCursor in [mtStretchBezier]) then
State :=3D gsStretchBezier;
end;
end;
...
procedure TExtGraph.MouseMove(Shift: TShiftState; X, Y: Integer);
const
FreezeTopMarkers =3D [mtMove, mtSizeNW, mtSizeN, mtSizeNE];
FreezeLeftMarkers =3D [mtMove, mtSizeNW, mtSizeW, mtSizeSW];
var
...
BezierAtCursor: TBezierLink;
begin
...
else if State =3D gsStretchBezier then begin
BezierAtCursor :=3D TBezierLink(ObjectAtCursor);
BezierAtCursor.fPointsAltered :=3D True;
BezierAtCursor.points[BezierAtCursor.DraggingPoint] :=3D =
Point(X,Y);
BezierAtCursor.DrawBody(Canvas);
Invalidate;
end
...
end;
=20
initialization
...
TExtGraph.Register(TBezierLink);
finalization
...
TExtGraph.Unregister(TBezierLink);
|