TSimpleGraph Issues (and wish list)

Please post bug reports, feature requests, or any question regarding the DELPHI AREA products here.

Re: TSimpleGraph Issues (and wish list)

Postby VJS » April 8th, 2013, 7:45 pm

Hello!
It will be perfect, if some video file can be played in TGraphObject.

Best regards,
VJS
VJS
Member
Member
 
Posts: 1
Joined: April 8th, 2013, 7:38 pm

Re: TSimpleGraph Issues (and wish list)

Postby HPW » May 11th, 2013, 7:14 pm

Hello Kambiz,

I update the neobook plugin to latest TSimpleGraph 2.9
There were also demand after a scripted full editing option in the neobook-plugin.
So I add script commands to do this in neobook instead of the original wizards of the simplegraph demo.

Thanks again for the product support.

Regards

Hans-Peter
Hans-Peter
HPW
Moderator
Moderator
 
Posts: 230
Joined: February 25th, 2006, 10:19 am
Location: Germany

Re: TSimpleGraph Issues (and wish list)

Postby Nout » August 25th, 2013, 12:23 pm

Wish list:
* Select a smaller object that resides under another larger object
* Rotate / Flip objects
* Text marker outside, next to and/or above the object
* Group/Ungroup objects
Nout
Member
Member
 
Posts: 1
Joined: August 25th, 2013, 12:17 pm

Re: TSimpleGraph Issues (and wish list)

Postby HPW » November 11th, 2013, 8:07 pm

Hello Kambiz,

I had an report about an error on reloading SGP file with embedded PNG-files.

http://www.neosoftware.com/community/vi ... #p11211853

" Error on reading TGraphStreamableObject.G.Background.Data: The file being readed is not a valid "Portable Network Graphics" image because it contains na invalid header. This file may be corrupted, try obtaining it again. "

What did I miss when adding PNG-support to SimpleGraph?
It was written before with SimpleGraph1.SaveToFile

Regards

Hans-Peter
Hans-Peter
HPW
Moderator
Moderator
 
Posts: 230
Joined: February 25th, 2006, 10:19 am
Location: Germany

Re: TSimpleGraph Issues (and wish list)

Postby HPW » November 12th, 2013, 5:34 pm

Hello,

Forget my last error post.
A fix in my PngLibrary for another plugin had a side-effect.
Problem solved.

Regards
Hans-Peter
HPW
Moderator
Moderator
 
Posts: 230
Joined: February 25th, 2006, 10:19 am
Location: Germany

Re: TSimpleGraph Issues (and wish list)

Postby Oleg » January 20th, 2014, 1:51 pm

Hello.
I've found (and fixed) one small bug in TSimpleGraph WrapText function. There was incorrect behavior in some cases (fist wrapped string portion sometimes dissappers).
Hope this will be useful.
Code: Select all
unit SimpleGraph;
...
function WrapText(Canvas: TCanvas; const Text: String; MaxWidth: Integer): String;
var
  DC: HDC;
  TextExtent: TSize;
  S, P, E: PChar;
  Line: String;
  IsFirstLine: Boolean;
begin
  Result := '';
  DC := Canvas.Handle;
  IsFirstLine := True;
  P := PChar(Text);
  while P^ = ' ' do
    Inc(P);
  while P^ <> #0 do
  begin
    S := P;
    E := nil;
    while (P^ <> #0) and (P^ <> #13) and (P^ <> #10) do
    begin
      GetTextExtentPoint32(DC, S, P - S + 1, TextExtent);
      if (TextExtent.CX > MaxWidth) and (E <> nil) then
      begin
        if (P^ <> ' ') and (P^ <> ^I) then
        begin
          while (E >= S) do
            case E^ of
              '.', ',', ';', '?', '!', '-', ':',
              ')', ']', '}', '>', '/', '\', ' ':
                break;
            else
              Dec(E);
            end;
          if E < S then
            E := P - 1;
        end;
        Break;
      end;
      E := P;
      Inc(P);
    end;
    if E <> nil then
    begin
// fix start
      while (E >= S) and (E^{was: P^} = ' ') do
// fix finish
        Dec(E);
    end;
    if E <> nil then
      SetString(Line, S, E - S + 1)
    else
      SetLength(Line, 0);
    if (P^ = #13) or (P^ = #10) then
    begin
      Inc(P);
      if (P^ <> (P - 1)^) and ((P^ = #13) or (P^ = #10)) then
        Inc(P);
      if P^ = #0 then
        Line := Line + #13#10;
    end
    else if P^ <> ' ' then
      P := E + 1;
    while P^ = ' ' do
      Inc(P);
    if IsFirstLine then
    begin
      Result := Line;
      IsFirstLine := False;
    end
    else
      Result := Result + #13#10 + Line;
  end;
end;

P.S.: Thank you for this perfect component!
Oleg
Member
Member
 
Posts: 1
Joined: January 30th, 2013, 11:44 am

Re: TSimpleGraph Issues (and wish list)

Postby Kambiz » January 25th, 2014, 11:13 am

Thank for the bug-fix!

I just released an update with your fix.
Kambiz
User avatar
Kambiz
Administrator
Administrator
 
Posts: 2408
Joined: March 7th, 2003, 7:10 pm

Re: TSimpleGraph Issues (and wish list)

Postby HPW » February 24th, 2014, 6:33 pm

Also thank you both for the bug-fix!
I have released the update to hpwSimpleGraph.

Regards
Hans-Peter
HPW
Moderator
Moderator
 
Posts: 230
Joined: February 25th, 2006, 10:19 am
Location: Germany

Re: TSimpleGraph Issues (and wish list)

Postby dsimun » August 1st, 2014, 8:37 pm

If someone needs it: how to put SimpleGraph drawing into the RTF file:

I create new function in the public part:

function TSimpleGraph.GetAsMetafileHex(out MfWidth, MfHeight: integer): string;
var
Metafile: TMetafile;
MS : TMemoryStream;
i : integer;
b : byte;
begin
Metafile := GetAsMetafile(0, Objects);
MS := TMemoryStream.Create;
result := '';
try
Metafile.SaveToStream(MS);
MS.Position := 0;
for i := 0 to MS.Size - 1 do begin
MS.Read(b,1);
result := result + IntToHex(b, 2);
end;
MfWidth := Metafile.Width;
MfHeight := Metafile.Height;
finally
MS.Free;
Metafile.Free;
end;
end;

Then, in my application I create this string:

s := P.SimpleGraph.GetAsMetafileHex(MfW,MfH);
s := '{\pict\wmetafile8\picw' + IntToStr(MfW * 20) + '\pich' + IntToStr(MfH * 20) + ' ' + s + ' }';

and put it into the RTF code, and that's it.
dsimun
Active Member
Active Member
 
Posts: 5
Joined: August 1st, 2014, 8:32 pm

Re: TSimpleGraph Issues (and wish list)

Postby dsimun » August 14th, 2014, 7:55 pm

Anybody knows or have solution how to export/save drawing from TSimpleGraph to SVG (Scalable Vector Graphics)?
dsimun
Active Member
Active Member
 
Posts: 5
Joined: August 1st, 2014, 8:32 pm

Re: TSimpleGraph Issues (and wish list)

Postby Kambiz » September 21st, 2014, 9:16 am

dsimun,

Thanks for the code for embedding graph into an RTF document.

Here is a project that may help you on saving graph as SVG:
http://extgraph.sourceforge.net/
Kambiz
User avatar
Kambiz
Administrator
Administrator
 
Posts: 2408
Joined: March 7th, 2003, 7:10 pm

Re: TSimpleGraph Issues (and wish list)

Postby dsimun » January 2nd, 2015, 11:26 pm

Dear Kambiz,

First, happy new year! All the best to you.

And second, naturally, TSimpleGraph again :)
Actually, Bezier links! I try to add an bezier type of link in you great control and the first step was easy. I add the new class:

Code: Select all
  TGraphLinkBezier = class(TGraphLink)
  protected
    procedure DrawBody(Canvas: TCanvas); override;
  end;

Code: Select all
procedure TGraphLinkBezier.DrawBody(Canvas: TCanvas);
var
  OldPenStyle: TPenStyle;
  OldBrushStyle: TBrushStyle;
  ModifiedPolyline: TPoints;
  Angle: Double;
  PtRect: TRect;
begin
  ModifiedPolyline := nil;
  if PointCount = 1 then
  begin
    PtRect := MakeSquare(Points[0], Pen.Width div 2);
    while not IsRectEmpty(PtRect) do
    begin
      Canvas.Ellipse(PtRect.Left, PtRect.Top, PtRect.Right, PtRect.Bottom);
      InflateRect(PtRect, -1, -1);
    end;
  end
  else if PointCount >= 2 then
  begin
    if (BeginStyle <> lsNone) or (EndStyle <> lsNone) then
    begin
      OldPenStyle := Canvas.Pen.Style;
      Canvas.Pen.Style := psSolid;
      try
        if BeginStyle <> lsNone then
        begin
          if ModifiedPolyline = nil then
            ModifiedPolyline := Copy(Polyline, 0, PointCount);
          Angle := LineSlopeAngle(fPoints[1], fPoints[0]);
          ModifiedPolyline[0] := DrawPointStyle(Canvas, fPoints[0],
            Angle, BeginStyle, BeginSize);
        end;
        if EndStyle <> lsNone then
        begin
          if ModifiedPolyline = nil then
            ModifiedPolyline := Copy(Polyline, 0, PointCount);
          Angle := LineSlopeAngle(fPoints[PointCount - 2], fPoints[PointCount - 1]);
          ModifiedPolyline[PointCount - 1] := DrawPointStyle(Canvas, fPoints[PointCount - 1],
            Angle, EndStyle, EndSize);;
        end;
      finally
        Canvas.Pen.Style := OldPenStyle;
      end;
    end;
    OldBrushStyle := Canvas.Brush.Style;
    try
      Canvas.Brush.Style := bsClear;
      if ModifiedPolyline <> nil then
        [b]Canvas.PolyBezier(ModifiedPolyline)[/b]  // Canvas.Polyline(ModifiedPolyline)
      else
        [b]Canvas.PolyBezier(Polyline)[/b];  // Canvas.Polyline(Polyline);
    finally
      Canvas.Brush.Style := OldBrushStyle;
    end;
  end;
  ModifiedPolyline := nil;
end;

In initialization I add:
TSimpleGraph.Register(TGraphLinkBezier);

When called from main program:
SimpleGraph.DefaultLinkClass := TGraphLinkBezier;
SimpleGraph.CommandMode := cmInsertLink;

And it seems to work :)
BUT there are some issues you can help me to solve for sure.

First. the bezier link is displayed only if there are exactly two breaking points. Now I have to add them manually. The question is: how to generate this two points immediately after creating the link, before it is displayed?

Second: when pointing with mouse pointer it points on the (unvisible) linear lines (polyline)It's not so bad but if there is a solution to point to the visible bezier line, it would be much better :)

Third, when caption is added to the link, it follows the parts of the polyline. I'll try to draw text following the bezier line. Do you have any suggestion?
Last edited by dsimun on January 3rd, 2015, 1:31 pm, edited 1 time in total.
dsimun
Active Member
Active Member
 
Posts: 5
Joined: August 1st, 2014, 8:32 pm

Re: TSimpleGraph Issues (and wish list)

Postby dsimun » January 3rd, 2015, 1:29 pm

First question seems to be solved (sourceforge, EVSSimpleGraph):

Code: Select all
  TGraphLinkBezier = class(TGraphLink)
  protected
    FCreateByMouse : Boolean;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; const Pt: TPoint); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; const Pt: TPoint); override;
    procedure DrawBody(Canvas: TCanvas); override;
  end;


and

Code: Select all
procedure TGraphLinkBezier.MouseDown(Button: TMouseButton; Shift: TShiftState;
  const Pt: TPoint);
begin
  inherited;
  if Owner.CommandMode = cmInsertLink then
    FCreateByMouse := True;
end;

procedure TGraphLinkBezier.MouseUp(Button: TMouseButton; Shift: TShiftState;
  const Pt: TPoint);
var
  StartPt, EndPt, MidPt1, MidPt2 : TPoint;
begin
  inherited;
  if not FCreateByMouse then exit;
  if Assigned(Source) and (EqualPoint(Points[0], fSource.FixHookAnchor)) then
    StartPt := Points[1]
  else
    StartPt := points[0];
  if Assigned(Target) and (PointsEqual(Points[PointCount -1],fTarget.FixHookAnchor)) then
    EndPt := Points[PointCount -2]
  else
    EndPt := Points[PointCount -1];
  MidPt1.X := (EndPT.X - StartPt.X) div 4;
  MidPt1.Y := (EndPT.Y - StartPt.Y) div 4;
  Midpt2.X := EndPt.X - MidPt1.X;
  MidPt2.Y := EndPt.Y - MidPt1.Y;
  MidPt1.X := StartPt.X + MidPt1.X;
  MidPt1.Y := StartPt.Y + MidPt1.Y;
  InsertPoint(1, MidPt1);
  InsertPoint(2, MidPt2);
  FCreateByMouse := False;
end;


Kambiz, is this the right way?
dsimun
Active Member
Active Member
 
Posts: 5
Joined: August 1st, 2014, 8:32 pm

Re: TSimpleGraph Issues (and wish list)

Postby dsimun » January 6th, 2015, 12:02 am

I use almost all solutions from project EVSSimpleGraph:

Code: Select all
  TGraphLinkBezier = class(TGraphLink)
  protected
    FBezierPolyline : TPoints;
    FCreateByMouse : Boolean;
    function IndexOfNearestLine(const Pt: TPoint; Neighborhood: Integer): Integer; override;
    function RelativeHookAnchor(RefPt: TPoint): TPoint; override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; const Pt: TPoint); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; const Pt: TPoint); override;
    procedure Changed(Flags: TGraphChangeFlags); override;
    procedure DrawBody(Canvas: TCanvas); override;
    function QueryHitTest(const Pt: TPoint): DWORD; override;
    procedure DrawHighlight(Canvas: TCanvas); override;
  end;


Code: Select all
procedure TGraphLinkBezier.Changed(Flags: TGraphChangeFlags);
begin
  inherited;
  if gcView in Flags  then
    FBezierPolyline := GetBezierPolyline(Polyline);
end;

procedure TGraphLinkBezier.DrawBody(Canvas: TCanvas);
var
  OldPenStyle: TPenStyle;
  OldBrushStyle: TBrushStyle;
  ModifiedPolyline: TPoints;
  Angle: Double;
  PtRect: TRect;
  Cntr : Integer;
  BckPen : TPen;
begin
  ModifiedPolyline := nil;
  if PointCount = 1 then
  begin
    PtRect := MakeSquare(Points[0], Pen.Width div 2);
    while not IsRectEmpty(PtRect) do
    begin
      Canvas.Ellipse(PtRect.Left, PtRect.Top, PtRect.Right, PtRect.Bottom);
      InflateRect(PtRect, -1, -1);
    end;
  end
  else if PointCount >= 2 then
  begin
    if (BeginStyle <> lsNone) or (EndStyle <> lsNone) then
    begin
      OldPenStyle := Canvas.Pen.Style;
      Canvas.Pen.Style := psSolid;
      try
        if BeginStyle <> lsNone then
        begin
          if ModifiedPolyline = nil then
            ModifiedPolyline := Copy(Polyline, 0, PointCount);
          Angle := LineSlopeAngle(fPoints[1], fPoints[0]);
          ModifiedPolyline[0] := DrawPointStyle(Canvas, fPoints[0],
            Angle, BeginStyle, BeginSize);
        end;
        if EndStyle <> lsNone then
        begin
          if ModifiedPolyline = nil then
            ModifiedPolyline := Copy(Polyline, 0, PointCount);
          Angle := LineSlopeAngle(fPoints[PointCount - 2], fPoints[PointCount - 1]);
          ModifiedPolyline[PointCount - 1] := DrawPointStyle(Canvas, fPoints[PointCount - 1],
            Angle, EndStyle, EndSize);;
        end;
      finally
        Canvas.Pen.Style := OldPenStyle;
      end;
    end;
    OldBrushStyle := Canvas.Brush.Style;
    BckPen := TPen.Create;
    BckPen.Assign(Canvas.Pen);
    try
      Canvas.Brush.Style := bsClear;
      // crtanje tangenti ako je selektirano
      if Selected {and ( not Dragging) }then
      begin
        OldPenStyle := Canvas.Pen.Style;
        try
          Canvas.Pen.Style := psDash;
          Canvas.Pen.Width := 1;
          PtRect.TopLeft := Points[0];
          PtRect.BottomRight := Points[1];
          Canvas.MoveTo(PtRect.Left,PtRect.Top);
          Canvas.LineTo(PtRect.Right,PtRect.Bottom);
          PtRect.TopLeft := Points[PointCount -2];
          PtRect.BottomRight := Points[PointCount -1];
          Canvas.MoveTo(PtRect.Left,PtRect.Top);
          Canvas.LineTo(PtRect.Right,PtRect.Bottom);
          Cntr := 2;
          while Cntr < PointCount - 3 do
          begin
            Canvas.MoveTo(Points[Cntr].X, Points[Cntr].Y);
            Canvas.LineTo(Points[Cntr+1].X, Points[Cntr+1].Y);
            Inc(Cntr, 1);
          end;
        finally
          Canvas.Pen.Style := OldPenStyle;
        end;
      end;
      Canvas.Pen.Width := BckPen.Width;
      if ModifiedPolyline <> nil then begin
        Canvas.PolyBezier(ModifiedPolyline);
      end else begin
        Canvas.PolyBezier(Polyline);
      end;
    finally
      Canvas.Brush.Style := OldBrushStyle;
      Canvas.Pen.Assign(BckPen);
      BckPen.Free;
    end;
  end;
  ModifiedPolyline := nil;
end;

procedure TGraphLinkBezier.DrawHighlight(Canvas: TCanvas);
var
  PtRect: TRect;
  First, Last: Integer;
begin
  if PointCount > 1 then
  begin
    if (MovingPoint >= 0) and (MovingPoint < PointCount) then
    begin
      if MovingPoint > 0 then
        First := MovingPoint - 1
      else
        First := MovingPoint;
      if MovingPoint < PointCount - 1 then
        Last := MovingPoint + 1
      else
        Last := MovingPoint;
      Canvas.PolyBezier(Copy(Polyline, First, Last - First + 1));
    end
    else
      Canvas.PolyBezier(Polyline)
  end
  else if PointCount = 1 then
  begin
    PtRect := MakeSquare(Points[0], Canvas.Pen.Width);
    Canvas.Ellipse(PtRect.Left, PtRect.Top, PtRect.Right, PtRect.Bottom);
  end;
end;

function TGraphLinkBezier.IndexOfNearestLine(const Pt: TPoint;
  Neighborhood: Integer): Integer;
var
  I: integer;
  NearestDistance: double;
  Distance: double;
begin
  Result := -1;
  NearestDistance := MaxDouble;
  for I := 0 to Length(FBezierPolyline) - 2 do
  begin
    Distance := DistanceToLine(FBezierPolyline[I], FBezierPolyline[I + 1], Pt);
    if (Trunc(Distance) <= Neighborhood) and (Distance < NearestDistance) then
    begin
      NearestDistance := Distance;
      Result := I;
    end;
  end;
end;

procedure TGraphLinkBezier.MouseDown(Button: TMouseButton; Shift: TShiftState;
  const Pt: TPoint);
begin
  inherited;
  if Owner.CommandMode = cmInsertLink then
    FCreateByMouse := True;
end;

procedure TGraphLinkBezier.MouseUp(Button: TMouseButton; Shift: TShiftState;
  const Pt: TPoint);
var
  StartPt, EndPt, MidPt1, MidPt2 : TPoint;
begin
  inherited;
  if not FCreateByMouse then exit;
  if Assigned(Source) and (EqualPoint(Points[0], fSource.FixHookAnchor)) then
    StartPt := Points[1]
  else
    StartPt := points[0];
  if Assigned(Target) and (PointsEqual(Points[PointCount -1],fTarget.FixHookAnchor)) then
    EndPt := Points[PointCount -2]
  else
    EndPt := Points[PointCount -1];
  MidPt1.X := (EndPT.X - StartPt.X) div 4;
  MidPt1.Y := (EndPT.Y - StartPt.Y) div 4;
  Midpt2.X := EndPt.X - MidPt1.X;
  MidPt2.Y := EndPt.Y - MidPt1.Y;
  MidPt1.X := StartPt.X + MidPt1.X;
  MidPt1.Y := StartPt.Y + MidPt1.Y;
  InsertPoint(1, MidPt1);
  InsertPoint(2, MidPt2);
  FCreateByMouse := False;
end;

function TGraphLinkBezier.QueryHitTest(const Pt: TPoint): DWORD;
var
  Neighborhood : Integer;
  Cntr         : Integer;
  PtCount      : Integer;
begin
  Neighborhood := NeighborhoodRadius;
  for Cntr := PointCount - 1 downto 0 do
    if PtInRect(MakeSquare(Points[Cntr], Neighborhood), Pt) then
    begin
      if Selected then
        Result := GHT_POINT or (Cntr shl 16)
      else
        Result := GHT_CLIENT;
      Exit;
    end;
  PtCount := Length(FBezierPolyline);
  for Cntr := 0 to PtCount - 2 do
  begin
    if DistanceToLine(FBezierPolyline[Cntr], FBezierPolyline[Cntr + 1], Pt) <= Neighborhood then
    begin
      if Selected then
        Result := GHT_LINE or (Cntr shl 16) or GHT_CLIENT
      else
        Result := GHT_CLIENT;
      Exit;
    end;
  end;
  if (TextRegion <> 0) and (goShowCaption in Options) and PtInRegion(TextRegion, Pt.X, Pt.Y) then
    Result := GHT_CAPTION or GHT_CLIENT
  else
    Result := GHT_NOWHERE;
end;

function TGraphLinkBezier.RelativeHookAnchor(RefPt: TPoint): TPoint;
  function ValidAnchor(Index: integer): boolean;
  var
    GraphObject: TGraphObject;
  begin
    GraphObject := HookedObjectOf(Index);
    Result := not Assigned(GraphObject) or GraphObject.IsLink;
  end;
var
  Pt: TPoint;
  Line: integer;
  Index: integer;
begin
  Line := IndexOfNearestLine(RefPt, MaxInt);
  if Line >= 0 then
  begin
    Pt := NearestPointOnLine(FBezierPolyline[Line], FBezierPolyline[Line + 1], RefPt);
    Index := IndexOfPoint(Pt, NeighborhoodRadius);
    if Index < 0 then
      Result := Pt
    else if ValidAnchor(Index) then
      Result := FBezierPolyline[Index]
    else
    begin
      if (Index = 0) and ValidAnchor(Index + 1) then
        Result := FBezierPolyline[Index + 1]
      else if (Index = Length(FBezierPolyline) - 1) and ValidAnchor(Index - 1) then
        Result := FBezierPolyline[Index - 1]
      else
        Result := FixHookAnchor;
    end;
  end
  else if PointCount = 1 then
    Result := fPoints[0]
  else
    Result := RefPt;
end;


There are two issues:
1. how to prevent adding breakpoints to bezier link?
2. writing text (I have an idea)

Kambiz, do you have any suggestion or comment?
dsimun
Active Member
Active Member
 
Posts: 5
Joined: August 1st, 2014, 8:32 pm

Re: TSimpleGraph Issues (and wish list)

Postby Mirage » January 9th, 2015, 10:53 am

Hello everyone
I know simplegraph from 10/2005. it s a great compenant.
I want to thanks Mr Kambiz, lbc, kokkoras and everyone.
I use it from 2005 to now 2015.

Thank you
User avatar
Mirage
Junior Member
Junior Member
 
Posts: 44
Joined: October 26th, 2005, 11:41 am

PreviousNext

Return to DELPHI AREA Products

Who is online

Users browsing this forum: No registered users and 2 guests