Pārlūkot izejas kodu

added TFresnelElement.insertBefore

mattias 4 nedēļas atpakaļ
vecāks
revīzija
c35a5bb417
1 mainītis faili ar 130 papildinājumiem un 32 dzēšanām
  1. 130 32
      src/base/fresnel.dom.pas

+ 130 - 32
src/base/fresnel.dom.pas

@@ -1314,6 +1314,7 @@ type
     FFont: IFresnelFont;
     FLayoutNode: TFresnelLayoutNode;
     FFontDesc: TFresnelFontDesc;
+    FNodeIndex: integer;
     FRendered: boolean;
     FScrollBarHorizontal: TPseudoElScrollBar;
     FScrollBarVertical: TPseudoElScrollBar;
@@ -1363,10 +1364,8 @@ type
     procedure SetCSSPseudoClass(Pseudo: TFresnelCSSPseudoClass; const AValue: boolean);
     class constructor InitFresnelElementClass;
     class destructor FinalFresnelElementClass;
-    procedure Notification(AComponent: TComponent; Operation: TOperation);
-      override;
     function CSSReadNextValue(const aValue: string; var p: integer): string; // read e.g. url("bla")
-    function CSSReadNextToken(const aValue: string; var p: integer): string; // read e.g. linear-gradient without the brackets
+    function CSSReadNextToken(const aValue: string; var p: integer): string; // read e.g. url of url(), without the brackets
     function GetDPI(IsHorizontal: boolean): TFresnelLength; virtual;
     procedure SetViewportConnected(AValue: boolean); virtual;
     function GetFont: IFresnelFont; virtual;
@@ -1397,6 +1396,7 @@ type
     function GetPath: string; virtual;
     function AcceptChildrenAtDesignTime: boolean; virtual;
     function Contains(aChild: TFresnelElement): boolean; overload;
+    function InsertBefore(NewChild, RefChild: TFresnelElement): TFresnelElement;
 
     // Can this widget handle focus ?
     class function HandleFocus : Boolean; virtual;
@@ -1413,6 +1413,7 @@ type
     property Parent: TFresnelElement read FParent write SetParent;
     property NodeCount: integer read GetNodeCount;
     property Nodes[Index: integer]: TFresnelElement read GetNodes; default;
+    property NodeIndex: integer read FNodeIndex;
     property PseudoNodeCount: integer read GetPeudoNodeCount;
     property PseudoNodes[Index: integer]: TPseudoElement read GetPseudoNodes;
     // CSS
@@ -1825,6 +1826,7 @@ type
     procedure ReleasePointerCapture(El: TFresnelElement; const aPointerId: TFreHandle); virtual; overload;
     procedure ReleasePointerCaptures(El: TFresnelElement); virtual;
     procedure WSMouseXY(WSData: TFresnelMouseEventInit; MouseEventId: TEventID); virtual;
+    procedure WriteTreeAndClasses; virtual;
     // Return true if default was prevented
     function WSKey(WSData: TFresnelKeyEventInit; KeyEventId: TEventID) : boolean; virtual;
     function WSInput(WSData: TFresnelInputEventInit) : boolean; virtual;
@@ -7692,6 +7694,24 @@ begin
   end;
 end;
 
+procedure TFresnelViewport.WriteTreeAndClasses;
+
+  procedure W(Prefix: string; El: TFresnelElement);
+  var
+    i: Integer;
+  begin
+    El.CSSClasses.Delimiter:=',';
+    writeln(Prefix,'Name="',El.Name,'":',El.ClassName,' Classes="',El.CSSClasses.DelimitedText,'"');
+    for i:=0 to El.NodeCount-1 do
+      W(Prefix+'  ',El.Nodes[i]);
+  end;
+
+begin
+  writeln('TFresnelViewport.WriteTreeAndClasses START');
+  W('',Self);
+  writeln('TFresnelViewport.WriteTreeAndClasses END');
+end;
+
 procedure TFresnelViewport.Bubble(El : TFresnelElement; aEvt : TFresnelEvent);
 
 begin
@@ -8046,34 +8066,46 @@ begin
 end;
 
 procedure TFresnelElement.SetParent(const AValue: TFresnelElement);
+var
+  List: TFPList;
+  IsPseudo: Boolean;
+  i: Integer;
 begin
   if FParent=AValue then Exit;
   if AValue=Self then
     raise Exception.Create('cycle');
 
+  IsPseudo:=fesPseudoElement in FStates;
   if FParent<>nil then
   begin
     ViewportConnected:=false;
     FResolver:=nil;
     FViewPort:=nil;
-    if fesPseudoElement in FStates then
-      Parent.FPseudoChildren.Remove(Self)
-    else begin
-      Parent.FChildren.Remove(Self);
+    if IsPseudo then
+      List:=Parent.FPseudoChildren
+    else
+      List:=Parent.FChildren;
+    List.Delete(FNodeIndex);
+    for i:=FNodeIndex to List.Count-1 do
+      TFresnelElement(List[i]).FNodeIndex:=i;
+    FNodeIndex:=-1;
+    if not IsPseudo then
       Parent.DomChanged;
-    end;
   end;
+
   FParent:=AValue;
+
   if FParent<>nil then
   begin
-    if fesPseudoElement in FStates then
-      Parent.FPseudoChildren.Add(Self)
+    if IsPseudo then
+      List:=Parent.FPseudoChildren
     else
-      Parent.FChildren.Add(Self);
-    FreeNotification(FParent);
+      List:=Parent.FChildren;
+    FNodeIndex:=List.Count;
+    List.Add(Self);
     FResolver:=Parent.Resolver;
-    FViewPort:=Parent.FViewPort;
-    Parent.DomChanged;
+    FViewPort:=Parent.Viewport;
+    DomChanged;
   end;
 end;
 
@@ -8096,22 +8128,6 @@ begin
     FStyleElement:=Resolver.ParseInlineStyle(FStyle);
 end;
 
-procedure TFresnelElement.Notification(AComponent: TComponent;
-  Operation: TOperation);
-begin
-  inherited Notification(AComponent, Operation);
-  if AComponent=Self then exit;
-  if Operation=opRemove then
-  begin
-    if FParent=AComponent then
-      FParent:=nil;
-    if FChildren<>nil then
-      FChildren.Remove(AComponent);
-    if FPseudoChildren<>nil then
-      FPseudoChildren.Remove(AComponent);
-  end;
-end;
-
 function TFresnelElement.CSSReadNextValue(const aValue: string; var p: integer
   ): string;
 var
@@ -9878,6 +9894,7 @@ constructor TFresnelElement.Create(AOwner: TComponent);
 begin
   inherited Create(AOwner);
   FChildren:=TFPList.Create;
+  FNodeIndex:=-1;
   FPseudoChildren:=TFPList.Create;
   FCSSClasses:=TStringList.Create;
   FCSSClasses.Delimiter:=' ';
@@ -9889,6 +9906,8 @@ destructor TFresnelElement.Destroy;
 var
   i: Integer;
 begin
+  if FParent<>nil then
+    FParent.ChildDestroying(Self);
   Parent:=nil;
   Clear;
   for i:=PseudoNodeCount-1 downto 0 do
@@ -9899,8 +9918,6 @@ begin
   FreeAndNil(FCSSValues);
   FreeAndNil(FCSSClasses);
   FreeAndNil(FEventDispatcher);
-  if FParent<>nil then
-    FParent.ChildDestroying(Self);
 
   inherited Destroy;
 end;
@@ -9958,6 +9975,87 @@ begin
   Result:=false;
 end;
 
+function TFresnelElement.InsertBefore(NewChild, RefChild: TFresnelElement): TFresnelElement;
+var
+  List: TFPList;
+  FromIndex, ToIndex, i: Integer;
+  IsPseudo: Boolean;
+begin
+  Result:=NewChild;
+  if NewChild=nil then
+    raise EFresnel.Create('20250914123316');
+  IsPseudo:=fesPseudoElement in NewChild.FStates;
+  if IsPseudo then
+    List:=FPseudoChildren
+  else
+    List:=FChildren;
+  if RefChild<>nil then
+  begin
+    if RefChild.Parent<>Self then
+      raise EFresnel.Create('20250914125844');
+    if IsPseudo <> (fesPseudoElement in RefChild.FStates) then
+      raise EFresnel.Create('20250914124539');
+  end;
+
+  if NewChild.Parent=Self then
+  begin
+    // just change the NodeIndex
+    FromIndex:=NewChild.NodeIndex;
+    if RefChild<>nil then
+    begin
+      if RefChild=NewChild then
+        raise EFresnel.Create('20250914131753');
+      ToIndex:=RefChild.NodeIndex;
+      if ToIndex>FromIndex then dec(ToIndex);
+    end else begin
+      // move to end
+      ToIndex:=List.Count;
+    end;
+    //writeln('TFresnelElement.InsertBefore SAME PARENT Self=',Name,' NewChild=',NewChild.Name,' From=',NewChild.NodeIndex,' To=',ToIndex);
+    if FromIndex=ToIndex then
+      exit; // already there
+    if FromIndex>=0 then
+    begin
+      List.Move(FromIndex,ToIndex);
+      if FromIndex<ToIndex then
+        for i:=FromIndex to ToIndex do
+          TFresnelElement(List[i]).FNodeIndex:=i
+      else
+        for i:=ToIndex to FromIndex do
+          TFresnelElement(List[i]).FNodeIndex:=i;
+    end else begin
+      List.Insert(ToIndex,NewChild);
+      for i:=ToIndex to List.Count-1 do
+        TFresnelElement(List[i]).FNodeIndex:=i
+    end;
+  end else begin
+    // move to a new parent
+    //writeln('TFresnelElement.InsertBefore NEW PARENT Self=',Name,' NewChild=',NewChild.Name,' From=',NewChild.NodeIndex);
+    NewChild.Parent:=nil;
+
+    NewChild.FParent:=Self;
+    NewChild.FResolver:=Resolver;
+    NewChild.FViewPort:=ViewPort;
+
+    if RefChild<>nil then
+    begin
+      ToIndex:=RefChild.NodeIndex;
+      List.Insert(ToIndex,NewChild);
+      for i:=ToIndex to List.Count-1 do
+        TFresnelElement(List[i]).FNodeIndex:=i;
+    end
+    else begin
+      List:=FChildren;
+      NewChild.FNodeIndex:=List.Count;
+      List.Add(Self);
+    end;
+  end;
+
+  //writeln('TFresnelElement.InsertBefore Self=',Name,' NewChild=',NewChild.Name,' Index=',NewChild.NodeIndex);
+
+  DomChanged;
+end;
+
 class function TFresnelElement.HandleFocus: Boolean;
 begin
   Result:=False;