0

I would like to define descendants of TPath class for SVG shapes that I use regularly, to register them on the palette instead of having to paste in the object inspector long SVG path strings.

this would also have the advantage of being able to, by changing a single string somewhere, impact all my objects of type TSVGxxx without having to run after them and edit each one after the other.

The first step was done:

TSVGsomeshape = class (TPath)

and in the Loaded:

Data.Data := 'an SVG path';

The problem: when this path gets too long, Delphi's string literal limitation forces me to break it down and concatenate its bits. Which I would like to avoid.

Resources come to mind. the idea: put all SVG paths into some RC file (simple paste of path as-is, no concatenation hassle), which in turns compiles and generates a RES file.

However, it seems that with paths being loaded as resources, I lose the ability to see those paths when dropping my TSVGxxx at design-time, which sort of defeats the purpose.

Am i over-complicating things, and is there a more simple approach to all of this?

edit 1:

In VCL, the main way of using resources was to add the {$R } rc or res file (I still prefer using the RC one and have it compiled every time, and ignore the generated res from version control).

I would consider for this a single resource file "svg.rc / res", which contains multiple text-only entries describing the path section only of each SVG.

LoadFromStream the resource into a string list, and feed it to the "Data" property, pretty straightforward.

Admittedly, I don't recall ever having done so in a control at design time. This is the first difficulty encountered using resources approach: getting "resource not found".

Is doing so at design time generally doable?

The second difficulty I suppose is more related to FMX, due to the multitude approaches to add resources (deployment menu, resources and images menu, standard {$R } approach). All of which also yielded resource not found at runtime.

I've used the Deployment menu for loading custom fonts, but not multi-key rc files. How could this be done?

Thanks

PS: i also had a look at SKIA4Delphi, and while great, may be overkill for the simple SVG paths that I am interested in (and also a Google dependency)

Note on tags: while the question does mention SVG and TPath, the problem at its core concerns neither of them, and as such, SVG and FMX tags are omitted.

Khorkhe
  • 1,024
  • 1
  • 11
  • 26
  • 2
    That's not a `String` limitation, it's a [limitation of literals](https://stackoverflow.com/q/8767899/4299358) - those are 2 things and once you can tell them apart you'll understand why the limits (2 GiB versus 255) differ so much. Just reconsider if your personal taste ("_I would like to avoid_") has the proper priority. – AmigoJack Oct 03 '21 at 05:06
  • edited the answer to clarify 'literal'. – Khorkhe Oct 03 '21 at 05:09
  • 1
    you may call it "personal taste", but concatenating 10-15 lines of strings is a hassle, and by far not an elegant solution. hence why some languages support multi-line strings. Since Delphi does not offer those, the point of this question is to find another way to avoid such concatenation. – Khorkhe Oct 03 '21 at 05:15
  • 2
    Resources are a perfectly reasonable way to do this. What's stopping you? – David Heffernan Oct 03 '21 at 08:03
  • David, added an edit in the question body with more details of what I've tried using resources, and the difficulties encountered – Khorkhe Oct 03 '21 at 12:02
  • Take a look at components that contain a lists of objects that are then referenced in other components. One example would be an image list. The data for images/strings are streamed in the DFM. – Brian Oct 03 '21 at 12:44
  • @Khorkhe resources work just fine at design time, when used correctly. So presumably you are not, but you didn't show any of your code. The most common mistake I see is using the wrong `HInstance` to load them. An alternative to using `.rc`/`.res` files is to use `ResourceString`s instead and let the compiler handle the resources for you. – Remy Lebeau Oct 03 '21 at 17:51
  • @RemyLebeau you're right, seems I had done something wrong. Tried again, it worked both at design-time and on-device, maybe the location of the res file must be in the project dir (not sure if search paths apply to res files) – Khorkhe Oct 05 '21 at 07:50

1 Answers1

0

it ended up working out as per the comments above.

  • placed the res file in the package's directory (previously had it in search path).
  • pointed to the res file using {$R myres.res}
  • loaded the resource string as RC_DATA, not sure if i should have used plain text instead (the resource editor restricted namings to numbers when using string tables)
function TSVGPlus.LoadSVGpath: string;
var RS: TResourceStream;
    SL: TSTringList;
begin
  RS := TResourceStream.Create(FindClassHInstance(Self.ClassType), 'PLUS', RT_RCDATA);
  SL := TStringList.Create;
  try
    SL.LoadFromStream(RS);
    Result := SL.Text;
  finally
    SL.Free;
    RS.Free;
  end;
end;
  • rebuilding the package, the plus shows up at design time
  • no additional deployment was needed to get the plus sign showing at runtime, be it on Windows or on Android
Khorkhe
  • 1,024
  • 1
  • 11
  • 26
  • 1
    Inside a component, you should not be using the global `HInstance`. Use [`FindClassHInstance(Self.ClassType)`](https://docwiki.embarcadero.com/Libraries/en/System.FindClassHInstance) instead. – Remy Lebeau Oct 05 '21 at 14:31
  • thanks for the always helpful comments. answer edited to reflect your correction. – Khorkhe Oct 05 '21 at 18:08