Replies: 2 comments 1 reply
-
I took some time to create a rather simple implementation of the aforementioned TSvgList component, using the TOwnedCollection class. I hope it will be of some use to you. unit Skia.SvgList;
interface
uses
System.SysUtils,
System.Classes,
System.Generics.Collections,
FMX.Utils,
FMX.Controls,
FMX.Types,
Skia,
Skia.FMX;
type
TSkSvgBrushList = class(TComponent)
private type
TSvgBrushItemClass = class of TSvgBrushItem;
TSvgBrushItem = class(TCollectionItem)
strict private
FSvgBrush: TSkSvgBrush;
procedure SetSvgBrush(const Value: TSkSvgBrush);
private
FName: String;
procedure SetName(const Value: String);
protected
function GetDisplayName: string; override;
published
constructor Create(Collection: TCollection); override;
destructor Destroy; override;
property SvgBrush: TSkSvgBrush read FSvgBrush write SetSvgBrush;
property Name: String read FName write SetName;
end;
TSvgBrushCollection = class(TOwnedCollection)
strict private[unsafe]
FOwner: TSkSvgBrushList;
FOnChange: TNotifyEvent;
function GetItem(AIndex: Integer): TSvgBrushItem;
procedure SetItem(AIndex: Integer; const AValue: TSvgBrushItem);
strict private
function IndexOf(const AName: string): Integer;
function GetItemByName(const AName: string): TSvgBrushItem;
protected
procedure Update(AItem: TCollectionItem); override;
public
constructor Create(AOwner: TPersistent; AItemClass: TSvgBrushItemClass);
function Add(const ABrush: TSkSvgBrush): TSvgBrushItem; overload;
function Insert(AIndex: Integer): TSvgBrushItem;
property ItemByName[const AName: string]: TSvgBrushItem read GetItemByName;
property Items[AIndex: Integer]: TSvgBrushItem read GetItem write SetItem; default;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
end;
private
FCollection: TSvgBrushCollection;
FOnChange: TNotifyEvent;
procedure SetCollection(const Value: TSvgBrushCollection);
private
procedure BrushChange(ASender: TObject);
public
constructor Create(Owner: TComponent); override;
destructor Destroy; override;
published
property SvgBrushList: TSvgBrushCollection read FCollection write SetCollection;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Skia', [TSkSvgBrushList]);
end;
{ TSkSvgBrushList.TSvgBrushList }
function TSkSvgBrushList.TSvgBrushCollection.Add(const ABrush: TSkSvgBrush): TSvgBrushItem;
begin
Result := TSvgBrushItem(inherited Add);
Result.SvgBrush := ABrush;
end;
constructor TSkSvgBrushList.TSvgBrushCollection.Create(AOwner: TPersistent; AItemClass: TSvgBrushItemClass);
begin
ValidateInheritance(AOwner, TSkSvgBrushList, False);
inherited Create(AOwner, AItemClass);
FOwner := TSkSvgBrushList(AOwner);
end;
function TSkSvgBrushList.TSvgBrushCollection.GetItem(AIndex: Integer): TSvgBrushItem;
begin
Result := TSvgBrushItem(inherited GetItem(AIndex));
end;
function TSkSvgBrushList.TSvgBrushCollection.GetItemByName(const AName: string): TSvgBrushItem;
var
LIndex: Integer;
begin
LIndex := IndexOf(AName);
if LIndex = -1 then
Result := nil
else
Result := Items[LIndex];
end;
function TSkSvgBrushList.TSvgBrushCollection.IndexOf(const AName: string): Integer;
var
I: Integer;
begin
Result := -1;
for I := 0 to Count - 1 do
if string.Compare(AName, Items[I].Name, [TCompareOption.coIgnoreCase]) = 0 then
begin
Result := I;
Break;
end;
end;
function TSkSvgBrushList.TSvgBrushCollection.Insert(AIndex: Integer): TSvgBrushItem;
begin
Result := TSvgBrushItem(inherited Insert(AIndex));
end;
procedure TSkSvgBrushList.TSvgBrushCollection.SetItem(AIndex: Integer; const AValue: TSvgBrushItem);
begin
inherited SetItem(AIndex, AValue);
end;
procedure TSkSvgBrushList.TSvgBrushCollection.Update(AItem: TCollectionItem);
begin
inherited;
if not(csDestroying in FOwner.ComponentState) then
begin
if Assigned(FOnChange) then
FOnChange(Self);
end;
end;
{ TSkSvgBrushList }
procedure TSkSvgBrushList.BrushChange(ASender: TObject);
begin
if Assigned(FOnChange) then
FOnChange(Self);
end;
constructor TSkSvgBrushList.Create(Owner: TComponent);
begin
inherited;
FCollection := TSvgBrushCollection.Create(Self, TSvgBrushItem);
FCollection.OnChange := BrushChange;
end;
destructor TSkSvgBrushList.Destroy;
begin
FCollection.Free;
inherited;
end;
procedure TSkSvgBrushList.SetCollection(const Value: TSvgBrushCollection);
begin
FCollection.Assign(Value);
end;
{ TNXTSvgBrushList.TSvgBrushItem }
constructor TSkSvgBrushList.TSvgBrushItem.Create(Collection: TCollection);
begin
inherited;
FSvgBrush := TSkSvgBrush.Create;
end;
destructor TSkSvgBrushList.TSvgBrushItem.Destroy;
begin
FSvgBrush.Free;
inherited;
end;
function TSkSvgBrushList.TSvgBrushItem.GetDisplayName: string;
begin
Result := Name;
if Result.IsEmpty then
Result := 'Item ' + Index.ToString;
end;
procedure TSkSvgBrushList.TSvgBrushItem.SetName(const Value: String);
begin
FName := Value;
end;
procedure TSkSvgBrushList.TSvgBrushItem.SetSvgBrush(const Value: TSkSvgBrush);
begin
FSvgBrush.Assign(Value);
end;
initialization
RegisterFmxClasses([TSkSvgBrushList, TSkSvgBrushList.TSvgBrushCollection, TSkSvgBrushList.TSvgBrushItem]);
end. |
Beta Was this translation helpful? Give feedback.
-
Hi @havrlisan, I really appreciate any suggestions, always welcome! I also thought about adding some components like a TSkBoxShadow (a fast shadow version), among others, but it would be a separate repository, because the focus of this repository is not to be a component library, but a Google Skia Wrapper, identical to the FMX and VCL. Over time, we noticed that some features were very interesting but difficult to use, such as animations, and that's why we created one or another control, just to make it easier to use. As much as the collection of SVGs is interesting, it would be more useful for the VCL (something like EtheaDev/SVGIconImageList does), because in FMX the correct thing is to add the SVGs inside the StyleBook. For example, create a style of a button with the icon in svg. Hence various forms could use it easily. Delphi's text editors really aren't very good. The performance of all the presented controls in general are not very good, but the worst are the issues, not only in relation to Right-To-Left, but also in relation to emojis, alignments, positioning of the caret, and they are not even related with rendering. I myself reported the issues to Embarcadero recently (although several of these were already known to Embarcadero). This is something that has nothing to do with Skia4Delphi, and I don't think it's a good idea to create such a complex control that already exists in the IDE, but which just lacks fixes that have even been reported. Regarding the performance of the displayed controls, I have some ideas for a caching system in Skia's rendering that could improve the performance of all the controls in general. But it's still just an idea, something we might be able to implement in the future. |
Beta Was this translation helpful? Give feedback.
-
I've been watching your project for some time now, and I absolutely love it. You write such clean and readable code, and I really hope you'll continue in those steps. I'm implementing your library in my projects and noticed that it may be a good idea to expand your component list.
For example, FireMonkey's TEdit has very poor performance on mobile platforms and lacks many features, one of which is support for RTL writing. I believe that a TSkEdit, with TSkStyleTextObject, would be a great addition to have. Considering you mastered multiple decorations in TSkLabel with TWordsCollection, a TSkMemo might not be a bad idea as well.
I consider those two to be the most mainstream controls besides TLabel that would be difficult to implement, but definitely nice to have.
Besides them, a TSvgList came across my mind, which would really be just a container for TSkSvgBrush (in FMX, that would be the TImageList).
Again, I love your work and hope you continue to work on it at the same pace. Thanks for creating this library!
Beta Was this translation helpful? Give feedback.
All reactions