148 lines
4.1 KiB
ObjectPascal
148 lines
4.1 KiB
ObjectPascal
unit Myc.Fmx.AstEditor.Handlers;
|
|
|
|
interface
|
|
|
|
uses
|
|
System.SysUtils,
|
|
System.Generics.Collections,
|
|
System.UITypes,
|
|
Myc.Ast.Nodes,
|
|
Myc.Ast.Identities,
|
|
Myc.Fmx.AstEditor.Render,
|
|
Myc.Fmx.AstEditor.Node;
|
|
|
|
type
|
|
// --- Abstract List Base ---
|
|
// Implements IReorderable to support drag & drop reordering within the virtual tree.
|
|
// Now operates on the untyped ITupleNode.
|
|
TNodeListHandler = class(TBaseNodeHandler<ITupleNode>, IReorderable)
|
|
protected
|
|
FChildNodes: TList<TAstViewNode>;
|
|
function GetOrientation: TLayoutOrientation; virtual; abstract;
|
|
function GetAlignment: TLayoutAlignment; virtual;
|
|
public
|
|
constructor Create(const ANode: ITupleNode);
|
|
destructor Destroy; override;
|
|
procedure BuildUI(OwnerNode: TAstViewNode); override;
|
|
function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; abstract;
|
|
|
|
// IReorderable Implementation
|
|
function CanDrag(Child: TVisualNode): Boolean;
|
|
procedure MoveChild(SourceIndex, TargetIndex: Integer);
|
|
end;
|
|
|
|
implementation
|
|
|
|
{ TNodeListHandler }
|
|
|
|
constructor TNodeListHandler.Create(const ANode: ITupleNode);
|
|
begin
|
|
inherited Create(ANode);
|
|
FChildNodes := TList<TAstViewNode>.Create;
|
|
end;
|
|
|
|
destructor TNodeListHandler.Destroy;
|
|
begin
|
|
FChildNodes.Free;
|
|
inherited;
|
|
end;
|
|
|
|
function TNodeListHandler.GetAlignment: TLayoutAlignment;
|
|
begin
|
|
Result := TLayoutAlignment.laCenter;
|
|
end;
|
|
|
|
procedure TNodeListHandler.BuildUI(OwnerNode: TAstViewNode);
|
|
var
|
|
visu: IAstVisualizer;
|
|
i: Integer;
|
|
childView: TAstViewNode;
|
|
openTok, closeTok, sep: string;
|
|
listId: IListIdentity;
|
|
elements: TArray<IAstNode>;
|
|
begin
|
|
if (FNode.Identity <> nil) and (FNode.Identity.Kind = ikList) then
|
|
begin
|
|
listId := FNode.Identity.AsList;
|
|
openTok := listId.OpenToken;
|
|
closeTok := listId.CloseToken;
|
|
sep := listId.Separator;
|
|
end
|
|
else
|
|
begin
|
|
openTok := '';
|
|
closeTok := '';
|
|
sep := ' ';
|
|
end;
|
|
|
|
visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth);
|
|
|
|
// No BeginUpdate/EndUpdate needed for TVisualNode, just property setting
|
|
OwnerNode.Frameless := True;
|
|
OwnerNode.Orientation := GetOrientation;
|
|
OwnerNode.Alignment := GetAlignment;
|
|
|
|
if openTok <> '' then
|
|
OwnerNode.AddLabel(OwnerNode, openTok);
|
|
|
|
// Optimization: Access Elements array directly from ITupleNode
|
|
elements := FNode.Elements;
|
|
|
|
for i := 0 to High(elements) do
|
|
begin
|
|
childView := visu.CallAccept(elements[i]);
|
|
FChildNodes.Add(childView);
|
|
|
|
if (i < High(elements)) and (sep <> '') and (sep <> ' ') then
|
|
OwnerNode.AddLabel(OwnerNode, sep);
|
|
end;
|
|
|
|
if closeTok <> '' then
|
|
OwnerNode.AddLabel(OwnerNode, closeTok);
|
|
|
|
if Length(elements) = 0 then
|
|
begin
|
|
if (openTok = '') and (closeTok = '') then
|
|
begin
|
|
var lbl := OwnerNode.AddLabel(OwnerNode, 'ø');
|
|
lbl.Opacity := 0.5;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// IReorderable Implementation
|
|
|
|
function TNodeListHandler.CanDrag(Child: TVisualNode): Boolean;
|
|
begin
|
|
// Only allow dragging if the child is one of our managed ViewNodes
|
|
if Child is TAstViewNode then
|
|
Result := FChildNodes.Contains(TAstViewNode(Child))
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
procedure TNodeListHandler.MoveChild(SourceIndex, TargetIndex: Integer);
|
|
var
|
|
item: TAstViewNode;
|
|
begin
|
|
if (SourceIndex < 0) or (SourceIndex >= FChildNodes.Count) then
|
|
Exit;
|
|
if (TargetIndex < 0) or (TargetIndex > FChildNodes.Count) then
|
|
Exit;
|
|
|
|
// Adjust target index if moving downwards (since removing source shifts indices)
|
|
if SourceIndex < TargetIndex then
|
|
Dec(TargetIndex);
|
|
|
|
if SourceIndex = TargetIndex then
|
|
Exit;
|
|
|
|
item := FChildNodes[SourceIndex];
|
|
FChildNodes.Delete(SourceIndex);
|
|
FChildNodes.Insert(TargetIndex, item);
|
|
|
|
// The visual order update happens via the controller's compilation cycle
|
|
end;
|
|
|
|
end.
|