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); |