diff --git a/ASTPlayground/ASTPlayground.delphilsp.json b/ASTPlayground/ASTPlayground.delphilsp.json index 4db5302..8a61baf 100644 --- a/ASTPlayground/ASTPlayground.delphilsp.json +++ b/ASTPlayground/ASTPlayground.delphilsp.json @@ -1 +1 @@ -{ "settings": { "project": "file:///T%3A/Myc/ASTPlayground/ASTPlayground.dpr", "dllname": "dcc64370.dll", "dccOptions": "-$O- -$W+ --inline:off -$R+ -$Q+ --no-config -Q -TX.exe -AGenerics.Collections=System.Generics.Collections;Generics.Defaults=System.Generics.Defaults;WinTypes=Winapi.Windows;WinProcs=Winapi.Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE -DDEBUG;;FRAMEWORK_FMX -E.\\Win64\\Debug -I\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\debug\\DE\";\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\debug\";\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\\DE\";T:\\Myc\\Src\\Data;T:\\Myc\\Src\\AST;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\";C:\\Users\\Brummel\\Documents\\Embarcadero\\Studio\\37.0\\Imports\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\Imports\";C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\include\";S:\\sc_famos_src\\svn_vcl\\Virtual-TreeView\\Source;S:\\sc_famos_src\\svn_vcl\\cpxedits;S:\\sc_famos_src\\svn_vcl\\dzChart;S:\\sc_famos_src\\svn_vcl\\eaeditor;S:\\sc_famos_src\\svn_vcl\\FamosEvents;S:\\sc_famos_src\\svn_vcl\\HTML_Viewer\\source;S:\\sc_famos_src\\svn_vcl\\Myc_ChartEdit;S:\\sc_famos_src\\svn_vcl\\Myc_HemiDrag;S:\\sc_famos_src\\svn_vcl\\Myc_SplitControl;S:\\sc_famos_src\\svn_vcl\\plotter;S:\\sc_famos_src\\svn_vcl\\SimpleIPC;S:\\sc_famos_src\\svn_vcl\\SynEdit-master\\Source;S:\\sc_famos_src\\svn_vcl\\ValEdits;S:\\sc_famos_src\\svn_vcl\\ZipMaster;S:\\sc_famos_src\\svn_common\\Myc_VecMath;\"C:\\Program Files (x86)\\DevExpress VCL\\Library\\RS28\\Win64\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCommon Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressGDI+ Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLibrary\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\XP Theme Manager\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLayout Control\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressPageControl\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressEditors Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDocking Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressBars\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressOfficeCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressMemData\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDataController\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressNavBar\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressSkins Library\\Sources\";S:\\3rdParty\\FastMM5;C:\\Users\\Brummel\\AppData\\Local\\Programs\\TestInsight\\Source;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\source\\DUnitX\" -LEC:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Bpl\\Win64 -LNC:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64 -NU.\\Win64\\Debug -NSWinapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;System;Xml;Data;Datasnap;Web;Soap; -OT:\\Myc\\Src\\Data;T:\\Myc\\Src\\AST;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\";C:\\Users\\Brummel\\Documents\\Embarcadero\\Studio\\37.0\\Imports\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\Imports\";C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\include\";S:\\sc_famos_src\\svn_vcl\\Virtual-TreeView\\Source;S:\\sc_famos_src\\svn_vcl\\cpxedits;S:\\sc_famos_src\\svn_vcl\\dzChart;S:\\sc_famos_src\\svn_vcl\\eaeditor;S:\\sc_famos_src\\svn_vcl\\FamosEvents;S:\\sc_famos_src\\svn_vcl\\HTML_Viewer\\source;S:\\sc_famos_src\\svn_vcl\\Myc_ChartEdit;S:\\sc_famos_src\\svn_vcl\\Myc_HemiDrag;S:\\sc_famos_src\\svn_vcl\\Myc_SplitControl;S:\\sc_famos_src\\svn_vcl\\plotter;S:\\sc_famos_src\\svn_vcl\\SimpleIPC;S:\\sc_famos_src\\svn_vcl\\SynEdit-master\\Source;S:\\sc_famos_src\\svn_vcl\\ValEdits;S:\\sc_famos_src\\svn_vcl\\ZipMaster;S:\\sc_famos_src\\svn_common\\Myc_VecMath;\"C:\\Program Files (x86)\\DevExpress VCL\\Library\\RS28\\Win64\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCommon Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressGDI+ Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLibrary\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\XP Theme Manager\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLayout Control\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressPageControl\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressEditors Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDocking Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressBars\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressOfficeCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressMemData\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDataController\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressNavBar\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressSkins Library\\Sources\";S:\\3rdParty\\FastMM5;C:\\Users\\Brummel\\AppData\\Local\\Programs\\TestInsight\\Source;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\source\\DUnitX\" -R\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\\DE\";T:\\Myc\\Src\\Data;T:\\Myc\\Src\\AST;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\";C:\\Users\\Brummel\\Documents\\Embarcadero\\Studio\\37.0\\Imports\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\Imports\";C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\include\";S:\\sc_famos_src\\svn_vcl\\Virtual-TreeView\\Source;S:\\sc_famos_src\\svn_vcl\\cpxedits;S:\\sc_famos_src\\svn_vcl\\dzChart;S:\\sc_famos_src\\svn_vcl\\eaeditor;S:\\sc_famos_src\\svn_vcl\\FamosEvents;S:\\sc_famos_src\\svn_vcl\\HTML_Viewer\\source;S:\\sc_famos_src\\svn_vcl\\Myc_ChartEdit;S:\\sc_famos_src\\svn_vcl\\Myc_HemiDrag;S:\\sc_famos_src\\svn_vcl\\Myc_SplitControl;S:\\sc_famos_src\\svn_vcl\\plotter;S:\\sc_famos_src\\svn_vcl\\SimpleIPC;S:\\sc_famos_src\\svn_vcl\\SynEdit-master\\Source;S:\\sc_famos_src\\svn_vcl\\ValEdits;S:\\sc_famos_src\\svn_vcl\\ZipMaster;S:\\sc_famos_src\\svn_common\\Myc_VecMath;\"C:\\Program Files (x86)\\DevExpress VCL\\Library\\RS28\\Win64\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCommon Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressGDI+ Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLibrary\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\XP Theme Manager\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLayout Control\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressPageControl\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressEditors Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDocking Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressBars\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressOfficeCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressMemData\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDataController\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressNavBar\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressSkins Library\\Sources\";S:\\3rdParty\\FastMM5;C:\\Users\\Brummel\\AppData\\Local\\Programs\\TestInsight\\Source;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\source\\DUnitX\" -U\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\debug\\DE\";\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\debug\";\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\\DE\";T:\\Myc\\Src\\Data;T:\\Myc\\Src\\AST;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\";C:\\Users\\Brummel\\Documents\\Embarcadero\\Studio\\37.0\\Imports\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\Imports\";C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\include\";S:\\sc_famos_src\\svn_vcl\\Virtual-TreeView\\Source;S:\\sc_famos_src\\svn_vcl\\cpxedits;S:\\sc_famos_src\\svn_vcl\\dzChart;S:\\sc_famos_src\\svn_vcl\\eaeditor;S:\\sc_famos_src\\svn_vcl\\FamosEvents;S:\\sc_famos_src\\svn_vcl\\HTML_Viewer\\source;S:\\sc_famos_src\\svn_vcl\\Myc_ChartEdit;S:\\sc_famos_src\\svn_vcl\\Myc_HemiDrag;S:\\sc_famos_src\\svn_vcl\\Myc_SplitControl;S:\\sc_famos_src\\svn_vcl\\plotter;S:\\sc_famos_src\\svn_vcl\\SimpleIPC;S:\\sc_famos_src\\svn_vcl\\SynEdit-master\\Source;S:\\sc_famos_src\\svn_vcl\\ValEdits;S:\\sc_famos_src\\svn_vcl\\ZipMaster;S:\\sc_famos_src\\svn_common\\Myc_VecMath;\"C:\\Program Files (x86)\\DevExpress VCL\\Library\\RS28\\Win64\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCommon Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressGDI+ Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLibrary\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\XP Theme Manager\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLayout Control\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressPageControl\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressEditors Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDocking Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressBars\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressOfficeCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressMemData\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDataController\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressNavBar\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressSkins Library\\Sources\";S:\\3rdParty\\FastMM5;C:\\Users\\Brummel\\AppData\\Local\\Programs\\TestInsight\\Source;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\source\\DUnitX\" -V -VN -VR -NBC:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64 -NHC:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\hpp\\Win64 -NO.\\Win64\\Debug -LU" , "projectFiles":[ { "name": "MainForm", "file": "file:///T%3A/Myc/ASTPlayground/MainForm.pas" }, { "name": "Myc.Ast.Nodes", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Nodes.pas" }, { "name": "Myc.Ast.Scope", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Scope.pas" }, { "name": "Myc.Data.Value", "file": "file:///T%3A/Myc/ASTPlayground/Myc.Data.Value.pas" }, { "name": "Myc.Ast.Visitor", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Visitor.pas" }, { "name": "Myc.Ast.RTL", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.RTL.pas" }, { "name": "Myc.Ast.Dumper", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Dumper.pas" }, { "name": "Myc.Ast.RTL.Core", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.RTL.Core.pas" }, { "name": "Myc.Utils", "file": "file:///T%3A/Myc/Src/Myc.Utils.pas" }, { "name": "Myc.Ast.Script", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Script.pas" }, { "name": "Myc.Ast.Types", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Types.pas" }, { "name": "Myc.Data.Keyword", "file": "file:///T%3A/Myc/Src/Data/Myc.Data.Keyword.pas" }, { "name": "Myc.Ast.Compiler.TCO", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.TCO.pas" }, { "name": "Myc.Ast.Compiler.Binder", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.Binder.pas" }, { "name": "Myc.Ast.Compiler.Lowering", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.Lowering.pas" }, { "name": "Myc.Ast.Compiler.TypeChecker", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.TypeChecker.pas" }, { "name": "Myc.Ast.Compiler.Macros", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.Macros.pas" }, { "name": "Myc.Ast.Compiler.Specializer", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.Specializer.pas" }, { "name": "Myc.Ast.Environment", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Environment.pas" }, { "name": "Myc.Ast.Debugger", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Debugger.pas" }, { "name": "Myc.Ast.Analysis.Purity", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Analysis.Purity.pas" }, { "name": "Myc.Ast.Identities", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Identities.pas" }, { "name": "Myc.Fmx.AstEditor.Handlers", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Handlers.pas" }, { "name": "Myc.Fmx.AstEditor.Visualizer", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Visualizer.pas" }, { "name": "Myc.Fmx.AstEditor.Workspace", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Workspace.pas" }, { "name": "Myc.Fmx.AstEditor.Layout", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Layout.pas" }, { "name": "Myc.Fmx.AstEditor.Node", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Node.pas" }, { "name": "Myc.Fmx.AstEditor", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.pas" }, { "name": "Unit1", "file": "file:///T%3A/Myc/ASTPlayground/Unit1.pas" } ] , "includeDCUsInUsesCompletion": true, "enableKeyWordCompletion": false, "browsingPaths": [ "file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/OCX/Servers","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/VCL","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/rtl/common","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/RTL/SYS","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/rtl/win","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/rtl/win/winrt","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/ToolsAPI","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/IBX","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Internet","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/PROPERTY%20EDITORS","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/soap","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/XML","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Indy10/Core","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Indy10/System","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Indy10/Protocols","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/fmx","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/databinding/components","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/databinding/engine","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/databinding/graph","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/ado","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/cloud","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/datasnap","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/dbx","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/dsnap","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/vclctrls","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/datasnap/connectors","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/datasnap/proxygen","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DataExplorer","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/Common","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/Common/dunit","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/DelphiExperts/Common","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/DelphiExperts/DUnitProject","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/DelphiExperts/DUnitProject/dunit","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/src","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/tests","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Experts","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/indy/abstraction","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/indy/implementation","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/indyimpl","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Property%20Editors/Indy10","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/soap/wsdlimporter","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Visualizers","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/XMLReporting","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/XPGen","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/rest","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/firedac","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/tethering","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnitX","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/ems","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/rtl/net","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/FlatBox2D","file:///C%3A/Users/Public/Documents/Embarcadero/Studio/37.0/Dcp/%25PLATFORM%25","file:///%25TP%25/runtime/vcl","file:///S%3A/sc_famos_src/svn_vcl/cpxedits","file:///S%3A/sc_famos_src/svn_vcl/dzChart","file:///S%3A/sc_famos_src/svn_vcl/eaeditor","file:///S%3A/sc_famos_src/svn_vcl/FamosEvents","file:///S%3A/sc_famos_src/svn_vcl/HTML_Viewer/source","file:///S%3A/sc_famos_src/svn_vcl/Myc_ChartEdit","file:///S%3A/sc_famos_src/svn_vcl/Myc_HemiDrag","file:///S%3A/sc_famos_src/svn_vcl/Myc_SplitControl","file:///S%3A/sc_famos_src/svn_vcl/NiceChart","file:///S%3A/sc_famos_src/svn_vcl/plotter","file:///S%3A/sc_famos_src/svn_vcl/SimpleIPC","file:///S%3A/sc_famos_src/svn_vcl/SynEdit-master/Source","file:///S%3A/sc_famos_src/svn_vcl/ValEdits","file:///S%3A/sc_famos_src/svn_vcl/ZipMaster","file:///S%3A/sc_famos_src/svn_vcl/ZipMaster/zlib","file:///S%3A/sc_famos_src/svn_vcl/ZipMaster/zlib/win32","file:///S%3A/sc_famos_src/svn_vcl/Virtual-TreeView/Source","file:///S%3A/sc_famos_src/svn_common/caHelpSys","file:///S%3A/sc_famos_src/svn_common/Misc","file:///S%3A/sc_famos_src/svn_common/Myc_VecMath","file:///S%3A/sc_famos_src/svn_common/PascalScript/source","file:///S%3A/sc_famos_src/svn_common/TreeBase","file:///S%3A/sc_famos_src/svn_common/TreeBase/Medien","file:///S%3A/3rdParty/spring4d/Source","file:///S%3A/3rdParty/spring4d/Source/Base","file:///S%3A/3rdParty/spring4d/Source/Base/Collections","file:///S%3A/3rdParty/spring4d/Source/Base/Logging","file:///S%3A/3rdParty/spring4d/Source/Base/Patches","file:///S%3A/3rdParty/spring4d/Source/Core/Container","file:///S%3A/3rdParty/spring4d/Source/Core/Interception","file:///S%3A/3rdParty/spring4d/Source/Core/Logging","file:///S%3A/3rdParty/spring4d/Source/Core/Mocking","file:///S%3A/3rdParty/spring4d/Source/Core/Services","file:///S%3A/3rdParty/spring4d/Source/Extensions/Cryptography","file:///S%3A/3rdParty/spring4d/Source/Extensions/Utils","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressCore%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressCommon%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressGDI%2B%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressLibrary/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/XP%20Theme%20Manager/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressLayout%20Control/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressPageControl/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressEditors%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressDocking%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressBars/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressOfficeCore%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressMemData/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressDataController/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressNavBar/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressSkins%20Library/Sources","file:///T%3A/Myc/Src","file:///T%3A/Myc/Src/Data","file:///T%3A/Myc/Src/AST" ] , "CommonAppData": "file:///C%3A/Users/Brummel/AppData/Roaming/Embarcadero/BDS/37.0/" , "Templates": "file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/ObjRepos/" } } \ No newline at end of file +{ "settings": { "project": "file:///T%3A/Myc/ASTPlayground/ASTPlayground.dpr", "dllname": "dcc64370.dll", "dccOptions": "-$O- -$W+ --inline:off -$R+ -$Q+ --no-config -Q -TX.exe -AGenerics.Collections=System.Generics.Collections;Generics.Defaults=System.Generics.Defaults;WinTypes=Winapi.Windows;WinProcs=Winapi.Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE -DDEBUG;;FRAMEWORK_FMX -E.\\Win64\\Debug -I\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\debug\\DE\";\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\debug\";\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\\DE\";T:\\Myc\\Src\\Data;T:\\Myc\\Src\\AST;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\";C:\\Users\\Brummel\\Documents\\Embarcadero\\Studio\\37.0\\Imports\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\Imports\";C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\include\";S:\\sc_famos_src\\svn_vcl\\Virtual-TreeView\\Source;S:\\sc_famos_src\\svn_vcl\\cpxedits;S:\\sc_famos_src\\svn_vcl\\dzChart;S:\\sc_famos_src\\svn_vcl\\eaeditor;S:\\sc_famos_src\\svn_vcl\\FamosEvents;S:\\sc_famos_src\\svn_vcl\\HTML_Viewer\\source;S:\\sc_famos_src\\svn_vcl\\Myc_ChartEdit;S:\\sc_famos_src\\svn_vcl\\Myc_HemiDrag;S:\\sc_famos_src\\svn_vcl\\Myc_SplitControl;S:\\sc_famos_src\\svn_vcl\\plotter;S:\\sc_famos_src\\svn_vcl\\SimpleIPC;S:\\sc_famos_src\\svn_vcl\\SynEdit-master\\Source;S:\\sc_famos_src\\svn_vcl\\ValEdits;S:\\sc_famos_src\\svn_vcl\\ZipMaster;S:\\sc_famos_src\\svn_common\\Myc_VecMath;\"C:\\Program Files (x86)\\DevExpress VCL\\Library\\RS28\\Win64\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCommon Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressGDI+ Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLibrary\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\XP Theme Manager\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLayout Control\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressPageControl\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressEditors Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDocking Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressBars\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressOfficeCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressMemData\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDataController\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressNavBar\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressSkins Library\\Sources\";S:\\3rdParty\\FastMM5;C:\\Users\\Brummel\\AppData\\Local\\Programs\\TestInsight\\Source;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\source\\DUnitX\" -LEC:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Bpl\\Win64 -LNC:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64 -NU.\\Win64\\Debug -NSWinapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;System;Xml;Data;Datasnap;Web;Soap; -OT:\\Myc\\Src\\Data;T:\\Myc\\Src\\AST;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\";C:\\Users\\Brummel\\Documents\\Embarcadero\\Studio\\37.0\\Imports\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\Imports\";C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\include\";S:\\sc_famos_src\\svn_vcl\\Virtual-TreeView\\Source;S:\\sc_famos_src\\svn_vcl\\cpxedits;S:\\sc_famos_src\\svn_vcl\\dzChart;S:\\sc_famos_src\\svn_vcl\\eaeditor;S:\\sc_famos_src\\svn_vcl\\FamosEvents;S:\\sc_famos_src\\svn_vcl\\HTML_Viewer\\source;S:\\sc_famos_src\\svn_vcl\\Myc_ChartEdit;S:\\sc_famos_src\\svn_vcl\\Myc_HemiDrag;S:\\sc_famos_src\\svn_vcl\\Myc_SplitControl;S:\\sc_famos_src\\svn_vcl\\plotter;S:\\sc_famos_src\\svn_vcl\\SimpleIPC;S:\\sc_famos_src\\svn_vcl\\SynEdit-master\\Source;S:\\sc_famos_src\\svn_vcl\\ValEdits;S:\\sc_famos_src\\svn_vcl\\ZipMaster;S:\\sc_famos_src\\svn_common\\Myc_VecMath;\"C:\\Program Files (x86)\\DevExpress VCL\\Library\\RS28\\Win64\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCommon Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressGDI+ Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLibrary\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\XP Theme Manager\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLayout Control\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressPageControl\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressEditors Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDocking Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressBars\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressOfficeCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressMemData\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDataController\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressNavBar\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressSkins Library\\Sources\";S:\\3rdParty\\FastMM5;C:\\Users\\Brummel\\AppData\\Local\\Programs\\TestInsight\\Source;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\source\\DUnitX\" -R\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\\DE\";T:\\Myc\\Src\\Data;T:\\Myc\\Src\\AST;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\";C:\\Users\\Brummel\\Documents\\Embarcadero\\Studio\\37.0\\Imports\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\Imports\";C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\include\";S:\\sc_famos_src\\svn_vcl\\Virtual-TreeView\\Source;S:\\sc_famos_src\\svn_vcl\\cpxedits;S:\\sc_famos_src\\svn_vcl\\dzChart;S:\\sc_famos_src\\svn_vcl\\eaeditor;S:\\sc_famos_src\\svn_vcl\\FamosEvents;S:\\sc_famos_src\\svn_vcl\\HTML_Viewer\\source;S:\\sc_famos_src\\svn_vcl\\Myc_ChartEdit;S:\\sc_famos_src\\svn_vcl\\Myc_HemiDrag;S:\\sc_famos_src\\svn_vcl\\Myc_SplitControl;S:\\sc_famos_src\\svn_vcl\\plotter;S:\\sc_famos_src\\svn_vcl\\SimpleIPC;S:\\sc_famos_src\\svn_vcl\\SynEdit-master\\Source;S:\\sc_famos_src\\svn_vcl\\ValEdits;S:\\sc_famos_src\\svn_vcl\\ZipMaster;S:\\sc_famos_src\\svn_common\\Myc_VecMath;\"C:\\Program Files (x86)\\DevExpress VCL\\Library\\RS28\\Win64\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCommon Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressGDI+ Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLibrary\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\XP Theme Manager\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLayout Control\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressPageControl\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressEditors Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDocking Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressBars\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressOfficeCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressMemData\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDataController\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressNavBar\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressSkins Library\\Sources\";S:\\3rdParty\\FastMM5;C:\\Users\\Brummel\\AppData\\Local\\Programs\\TestInsight\\Source;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\source\\DUnitX\" -U\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\debug\\DE\";\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\debug\";\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\\DE\";T:\\Myc\\Src\\Data;T:\\Myc\\Src\\AST;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\lib\\Win64\\release\";C:\\Users\\Brummel\\Documents\\Embarcadero\\Studio\\37.0\\Imports\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\Imports\";C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\include\";S:\\sc_famos_src\\svn_vcl\\Virtual-TreeView\\Source;S:\\sc_famos_src\\svn_vcl\\cpxedits;S:\\sc_famos_src\\svn_vcl\\dzChart;S:\\sc_famos_src\\svn_vcl\\eaeditor;S:\\sc_famos_src\\svn_vcl\\FamosEvents;S:\\sc_famos_src\\svn_vcl\\HTML_Viewer\\source;S:\\sc_famos_src\\svn_vcl\\Myc_ChartEdit;S:\\sc_famos_src\\svn_vcl\\Myc_HemiDrag;S:\\sc_famos_src\\svn_vcl\\Myc_SplitControl;S:\\sc_famos_src\\svn_vcl\\plotter;S:\\sc_famos_src\\svn_vcl\\SimpleIPC;S:\\sc_famos_src\\svn_vcl\\SynEdit-master\\Source;S:\\sc_famos_src\\svn_vcl\\ValEdits;S:\\sc_famos_src\\svn_vcl\\ZipMaster;S:\\sc_famos_src\\svn_common\\Myc_VecMath;\"C:\\Program Files (x86)\\DevExpress VCL\\Library\\RS28\\Win64\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressCommon Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressGDI+ Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLibrary\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\XP Theme Manager\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressLayout Control\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressPageControl\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressEditors Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDocking Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressBars\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressOfficeCore Library\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressMemData\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressDataController\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressNavBar\\Sources\";\"C:\\Program Files (x86)\\DevExpress VCL\\ExpressSkins Library\\Sources\";S:\\3rdParty\\FastMM5;C:\\Users\\Brummel\\AppData\\Local\\Programs\\TestInsight\\Source;T:\\Myc\\Src;\"c:\\program files (x86)\\embarcadero\\studio\\37.0\\source\\DUnitX\" -V -VN -VR -NBC:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\Dcp\\Win64 -NHC:\\Users\\Public\\Documents\\Embarcadero\\Studio\\37.0\\hpp\\Win64 -NO.\\Win64\\Debug -LU" , "projectFiles":[ { "name": "MainForm", "file": "file:///T%3A/Myc/ASTPlayground/MainForm.pas" }, { "name": "Myc.Ast.Nodes", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Nodes.pas" }, { "name": "Myc.Ast.Scope", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Scope.pas" }, { "name": "Myc.Data.Value", "file": "file:///T%3A/Myc/ASTPlayground/Myc.Data.Value.pas" }, { "name": "Myc.Ast.Visitor", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Visitor.pas" }, { "name": "Myc.Ast.RTL", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.RTL.pas" }, { "name": "Myc.Ast.Dumper", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Dumper.pas" }, { "name": "Myc.Ast.RTL.Core", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.RTL.Core.pas" }, { "name": "Myc.Utils", "file": "file:///T%3A/Myc/Src/Myc.Utils.pas" }, { "name": "Myc.Ast.Script", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Script.pas" }, { "name": "Myc.Ast.Types", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Types.pas" }, { "name": "Myc.Data.Keyword", "file": "file:///T%3A/Myc/Src/Data/Myc.Data.Keyword.pas" }, { "name": "Myc.Ast.Compiler.TCO", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.TCO.pas" }, { "name": "Myc.Ast.Compiler.Binder", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.Binder.pas" }, { "name": "Myc.Ast.Compiler.Lowering", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.Lowering.pas" }, { "name": "Myc.Ast.Compiler.TypeChecker", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.TypeChecker.pas" }, { "name": "Myc.Ast.Compiler.Macros", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.Macros.pas" }, { "name": "Myc.Ast.Compiler.Specializer", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Compiler.Specializer.pas" }, { "name": "Myc.Ast.Environment", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Environment.pas" }, { "name": "Myc.Ast.Debugger", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Debugger.pas" }, { "name": "Myc.Ast.Analysis.Purity", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Analysis.Purity.pas" }, { "name": "Myc.Ast.Identities", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Identities.pas" }, { "name": "Myc.Fmx.AstEditor.Handlers", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Handlers.pas" }, { "name": "Myc.Fmx.AstEditor.Visualizer", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Visualizer.pas" }, { "name": "Myc.Fmx.AstEditor.Workspace", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Workspace.pas" }, { "name": "Myc.Fmx.AstEditor.Layout", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Layout.pas" }, { "name": "Myc.Fmx.AstEditor.Node", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Node.pas" }, { "name": "Myc.Fmx.AstEditor", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.pas" }, { "name": "Myc.Ast.Refactoring.Remove", "file": "file:///T%3A/Myc/Src/AST/Myc.Ast.Refactoring.Remove.pas" }, { "name": "Myc.Fmx.AstEditor.Render", "file": "file:///T%3A/Myc/Src/AST/Myc.Fmx.AstEditor.Render.pas" } ] , "includeDCUsInUsesCompletion": true, "enableKeyWordCompletion": true, "browsingPaths": [ "file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/OCX/Servers","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/VCL","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/rtl/common","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/RTL/SYS","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/rtl/win","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/rtl/win/winrt","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/ToolsAPI","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/IBX","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Internet","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/PROPERTY%20EDITORS","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/soap","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/SOURCE/XML","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Indy10/Core","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Indy10/System","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Indy10/Protocols","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/fmx","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/databinding/components","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/databinding/engine","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/databinding/graph","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/ado","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/cloud","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/datasnap","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/dbx","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/dsnap","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/vclctrls","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/datasnap/connectors","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/datasnap/proxygen","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DataExplorer","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/Common","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/Common/dunit","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/DelphiExperts/Common","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/DelphiExperts/DUnitProject","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/DUnitWizard/Source/DelphiExperts/DUnitProject/dunit","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/src","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/tests","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Experts","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/indy/abstraction","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/indy/implementation","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/indyimpl","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Property%20Editors/Indy10","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/soap/wsdlimporter","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/Visualizers","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/XMLReporting","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnit/Contrib/XPGen","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/rest","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/firedac","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/tethering","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/DUnitX","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/data/ems","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/rtl/net","file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/source/FlatBox2D","file:///C%3A/Users/Public/Documents/Embarcadero/Studio/37.0/Dcp/%25PLATFORM%25","file:///%25TP%25/runtime/vcl","file:///S%3A/sc_famos_src/svn_vcl/cpxedits","file:///S%3A/sc_famos_src/svn_vcl/dzChart","file:///S%3A/sc_famos_src/svn_vcl/eaeditor","file:///S%3A/sc_famos_src/svn_vcl/FamosEvents","file:///S%3A/sc_famos_src/svn_vcl/HTML_Viewer/source","file:///S%3A/sc_famos_src/svn_vcl/Myc_ChartEdit","file:///S%3A/sc_famos_src/svn_vcl/Myc_HemiDrag","file:///S%3A/sc_famos_src/svn_vcl/Myc_SplitControl","file:///S%3A/sc_famos_src/svn_vcl/NiceChart","file:///S%3A/sc_famos_src/svn_vcl/plotter","file:///S%3A/sc_famos_src/svn_vcl/SimpleIPC","file:///S%3A/sc_famos_src/svn_vcl/SynEdit-master/Source","file:///S%3A/sc_famos_src/svn_vcl/ValEdits","file:///S%3A/sc_famos_src/svn_vcl/ZipMaster","file:///S%3A/sc_famos_src/svn_vcl/ZipMaster/zlib","file:///S%3A/sc_famos_src/svn_vcl/ZipMaster/zlib/win32","file:///S%3A/sc_famos_src/svn_vcl/Virtual-TreeView/Source","file:///S%3A/sc_famos_src/svn_common/caHelpSys","file:///S%3A/sc_famos_src/svn_common/Misc","file:///S%3A/sc_famos_src/svn_common/Myc_VecMath","file:///S%3A/sc_famos_src/svn_common/PascalScript/source","file:///S%3A/sc_famos_src/svn_common/TreeBase","file:///S%3A/sc_famos_src/svn_common/TreeBase/Medien","file:///S%3A/3rdParty/spring4d/Source","file:///S%3A/3rdParty/spring4d/Source/Base","file:///S%3A/3rdParty/spring4d/Source/Base/Collections","file:///S%3A/3rdParty/spring4d/Source/Base/Logging","file:///S%3A/3rdParty/spring4d/Source/Base/Patches","file:///S%3A/3rdParty/spring4d/Source/Core/Container","file:///S%3A/3rdParty/spring4d/Source/Core/Interception","file:///S%3A/3rdParty/spring4d/Source/Core/Logging","file:///S%3A/3rdParty/spring4d/Source/Core/Mocking","file:///S%3A/3rdParty/spring4d/Source/Core/Services","file:///S%3A/3rdParty/spring4d/Source/Extensions/Cryptography","file:///S%3A/3rdParty/spring4d/Source/Extensions/Utils","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressCore%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressCommon%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressGDI%2B%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressLibrary/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/XP%20Theme%20Manager/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressLayout%20Control/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressPageControl/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressEditors%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressDocking%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressBars/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressOfficeCore%20Library/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressMemData/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressDataController/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressNavBar/Sources","file:///C%3A/Program%20Files%20%28x86%29/DevExpress%20VCL/ExpressSkins%20Library/Sources","file:///T%3A/Myc/Src","file:///T%3A/Myc/Src/Data","file:///T%3A/Myc/Src/AST" ] , "CommonAppData": "file:///C%3A/Users/Brummel/AppData/Roaming/Embarcadero/BDS/37.0/" , "Templates": "file:///c%3A/program%20files%20%28x86%29/embarcadero/studio/37.0/ObjRepos/" } } \ No newline at end of file diff --git a/ASTPlayground/ASTPlayground.dpr b/ASTPlayground/ASTPlayground.dpr index 9398403..fd60b49 100644 --- a/ASTPlayground/ASTPlayground.dpr +++ b/ASTPlayground/ASTPlayground.dpr @@ -32,7 +32,8 @@ uses Myc.Fmx.AstEditor.Layout in '..\Src\AST\Myc.Fmx.AstEditor.Layout.pas', Myc.Fmx.AstEditor.Node in '..\Src\AST\Myc.Fmx.AstEditor.Node.pas', Myc.Fmx.AstEditor in '..\Src\AST\Myc.Fmx.AstEditor.pas', - Myc.Ast.Refactoring.Remove in '..\Src\AST\Myc.Ast.Refactoring.Remove.pas'; + Myc.Ast.Refactoring.Remove in '..\Src\AST\Myc.Ast.Refactoring.Remove.pas', + Myc.Fmx.AstEditor.Render in '..\Src\AST\Myc.Fmx.AstEditor.Render.pas'; {$R *.res} diff --git a/ASTPlayground/ASTPlayground.dproj b/ASTPlayground/ASTPlayground.dproj index 2b43926..edeb3e9 100644 --- a/ASTPlayground/ASTPlayground.dproj +++ b/ASTPlayground/ASTPlayground.dproj @@ -163,6 +163,7 @@ + Base diff --git a/Src/AST/Myc.Ast.Dumper.pas b/Src/AST/Myc.Ast.Dumper.pas index 99934be..b3d6ef4 100644 --- a/Src/AST/Myc.Ast.Dumper.pas +++ b/Src/AST/Myc.Ast.Dumper.pas @@ -30,7 +30,6 @@ type function FormatAddress(const Addr: TResolvedAddress): string; protected - // Override abstract PROCEDURES from TAstVisitor function VisitConstant(const Node: IConstantNode): TVoid; override; function VisitIdentifier(const Node: IIdentifierNode): TVoid; override; function VisitKeyword(const Node: IKeywordNode): TVoid; override; diff --git a/Src/AST/Myc.Fmx.AstEditor.Handlers.pas b/Src/AST/Myc.Fmx.AstEditor.Handlers.pas index 270374e..049c33a 100644 --- a/Src/AST/Myc.Fmx.AstEditor.Handlers.pas +++ b/Src/AST/Myc.Fmx.AstEditor.Handlers.pas @@ -9,20 +9,18 @@ uses System.UITypes, System.Generics.Collections, FMX.Types, - FMX.Controls, - FMX.StdCtrls, FMX.Graphics, Myc.Data.Value, Myc.Data.Keyword, Myc.Ast, Myc.Ast.Nodes, Myc.Ast.Identities, - Myc.Fmx.AstEditor.Layout, - Myc.Fmx.AstEditor.Node; + Myc.Fmx.AstEditor.Render, // The new Virtual Engine + Myc.Fmx.AstEditor.Node; // The View Node type // --- Abstract List Base --- - // Now implements IReorderable to support drag & drop reordering + // Implements IReorderable to support drag & drop reordering within the virtual tree TNodeListHandler = class(TBaseNodeHandler>, IReorderable) protected FChildNodes: TList; @@ -35,7 +33,7 @@ type function ReconstructAst(OwnerNode: TAstViewNode): IAstNode; override; abstract; // IReorderable Implementation - function CanDrag(Child: TControl): Boolean; + function CanDrag(Child: TVisualNode): Boolean; procedure MoveChild(SourceIndex, TargetIndex: Integer); end; @@ -75,7 +73,7 @@ type TRecordFieldHandler = class(TBaseNodeHandler) private - FKeyLabel: TLabel; + FKeyLabel: TTextNode; FValueNode: TAstViewNode; public procedure BuildUI(OwnerNode: TAstViewNode); override; @@ -322,47 +320,45 @@ begin visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := True; - OwnerNode.Orientation := GetOrientation; - OwnerNode.Alignment := GetAlignment; + // 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); + if openTok <> '' then + OwnerNode.AddLabel(OwnerNode, openTok); - for i := 0 to FNode.Count - 1 do + for i := 0 to FNode.Count - 1 do + begin + childView := visu.CallAccept(FNode[i]); + FChildNodes.Add(childView); + + if (i < FNode.Count - 1) and (sep <> '') and (sep <> ' ') then + OwnerNode.AddLabel(OwnerNode, sep); + end; + + if closeTok <> '' then + OwnerNode.AddLabel(OwnerNode, closeTok); + + if FNode.Count = 0 then + begin + if (openTok = '') and (closeTok = '') then begin - childView := visu.CallAccept(FNode[i]); - FChildNodes.Add(childView); - - if (i < FNode.Count - 1) and (sep <> '') and (sep <> ' ') then - OwnerNode.AddLabel(OwnerNode, sep); + var lbl := OwnerNode.AddLabel(OwnerNode, 'ø'); + lbl.Opacity := 0.5; end; - - if closeTok <> '' then - OwnerNode.AddLabel(OwnerNode, closeTok); - - if FNode.Count = 0 then - begin - if (openTok = '') and (closeTok = '') then - begin - var lbl := OwnerNode.AddLabel(OwnerNode, 'ø'); - lbl.Opacity := 0.5; - end; - end; - - finally - OwnerNode.EndUpdate; end; end; // IReorderable Implementation -function TNodeListHandler.CanDrag(Child: TControl): Boolean; +function TNodeListHandler.CanDrag(Child: TVisualNode): Boolean; begin - // Allow dragging only if the child is one of our managed ViewNodes - Result := (Child is TAstViewNode) and FChildNodes.Contains(TAstViewNode(Child)); + // 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); @@ -385,8 +381,7 @@ begin FChildNodes.Delete(SourceIndex); FChildNodes.Insert(TargetIndex, item); - // The visual order update will happen upon the next ReconstructAst -> Compile -> BuildUI cycle - // triggered by the controller. + // The visual order update happens via the controller's compilation cycle end; { TParameterListHandler } @@ -482,26 +477,20 @@ var visu: IAstVisualizer; begin visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := True; - OwnerNode.Orientation := loHorizontal; - OwnerNode.Alignment := laCenter; - FKeyLabel := OwnerNode.AddLabel(OwnerNode, ':' + FNode.Key.Value.Name); - FKeyLabel.Font.Style := FKeyLabel.Font.Style + [TFontStyle.fsBold]; - FKeyLabel.StyledSettings := FKeyLabel.StyledSettings - [TStyledSetting.FontColor]; - FKeyLabel.FontColor := TAlphaColors.Mediumvioletred; + OwnerNode.Frameless := True; + OwnerNode.Orientation := loHorizontal; + OwnerNode.Alignment := laCenter; - FValueNode := visu.CallAccept(FNode.Value); - finally - OwnerNode.EndUpdate; - end; + FKeyLabel := OwnerNode.AddLabel(OwnerNode, ':' + FNode.Key.Value.Name); + FKeyLabel.FontSettings.Font.Style := [TFontStyle.fsBold]; + FKeyLabel.Color := TAlphaColors.Mediumvioletred; + + FValueNode := visu.CallAccept(FNode.Value); end; function TRecordFieldHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; begin - // Updated to use new Factory Overload to preserve Identity Result := TAst.RecordField(FNode.Identity, FNode.Key, FValueNode.CreateAst); end; @@ -511,33 +500,25 @@ procedure TConstantNodeHandler.BuildUI(OwnerNode: TAstViewNode); var valueStr: string; isConcise: Boolean; - titleLabel: TLabel; - valueLabel: TLabel; + titleLabel: TTextNode; begin - OwnerNode.BeginUpdate; - try - valueStr := FNode.Value.ToString; - isConcise := ((FNode.Value.Kind = TDataValueKind.vkScalar) or (Pos(sLineBreak, valueStr) = 0)) and (Length(valueStr) < 40); + valueStr := FNode.Value.ToString; + isConcise := ((FNode.Value.Kind = TDataValueKind.vkScalar) or (Pos(sLineBreak, valueStr) = 0)) and (Length(valueStr) < 40); - if isConcise then - begin - OwnerNode.Frameless := True; - OwnerNode.AddLabel(OwnerNode, valueStr); - end - else - begin - OwnerNode.Frameless := False; - OwnerNode.Orientation := loVertical; + if isConcise then + begin + OwnerNode.Frameless := True; + OwnerNode.AddLabel(OwnerNode, valueStr); + end + else + begin + OwnerNode.Frameless := False; + OwnerNode.Orientation := loVertical; - titleLabel := OwnerNode.AddLabel(OwnerNode, 'Const'); - titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; + titleLabel := OwnerNode.AddLabel(OwnerNode, 'Const'); + titleLabel.FontSettings.Font.Style := [TFontStyle.fsBold]; - valueLabel := OwnerNode.AddLabel(OwnerNode, valueStr); - valueLabel.AutoSize := False; - valueLabel.WordWrap := True; - end; - finally - OwnerNode.EndUpdate; + OwnerNode.AddLabel(OwnerNode, valueStr); end; end; @@ -550,13 +531,8 @@ end; procedure TIdentifierNodeHandler.BuildUI(OwnerNode: TAstViewNode); begin - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := True; - OwnerNode.AddLabel(OwnerNode, FNode.Name); - finally - OwnerNode.EndUpdate; - end; + OwnerNode.Frameless := True; + OwnerNode.AddLabel(OwnerNode, FNode.Name); end; function TIdentifierNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; @@ -568,17 +544,11 @@ end; procedure TKeywordNodeHandler.BuildUI(OwnerNode: TAstViewNode); var - lbl: TLabel; + lbl: TTextNode; begin - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := True; - lbl := OwnerNode.AddLabel(OwnerNode, ':' + FNode.Value.Name); - lbl.StyledSettings := lbl.StyledSettings - [TStyledSetting.FontColor]; - lbl.FontColor := TAlphaColors.Mediumvioletred; - finally - OwnerNode.EndUpdate; - end; + OwnerNode.Frameless := True; + lbl := OwnerNode.AddLabel(OwnerNode, ':' + FNode.Value.Name); + lbl.Color := TAlphaColors.Mediumvioletred; end; function TKeywordNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; @@ -590,19 +560,14 @@ end; procedure TNopNodeHandler.BuildUI(OwnerNode: TAstViewNode); var - lbl: TLabel; + lbl: TTextNode; begin - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := True; - OwnerNode.Alignment := TLayoutAlignment.laCenter; - OwnerNode.Orientation := TLayoutOrientation.loHorizontal; - lbl := OwnerNode.AddLabel(OwnerNode, '...'); - lbl.Font.Style := lbl.Font.Style + [TFontStyle.fsBold]; - lbl.Margins.Rect := TRectF.Create(8, 4, 8, 4); - finally - OwnerNode.EndUpdate; - end; + OwnerNode.Frameless := True; + OwnerNode.Alignment := TLayoutAlignment.laCenter; + OwnerNode.Orientation := TLayoutOrientation.loHorizontal; + lbl := OwnerNode.AddLabel(OwnerNode, '...'); + lbl.FontSettings.Font.Style := [TFontStyle.fsBold]; + lbl.Margins := TMarginRect.Create(8, 4, 8, 4); end; function TNopNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; @@ -615,23 +580,19 @@ end; procedure TBlockExpressionNodeHandler.BuildUI(OwnerNode: TAstViewNode); var visu: IAstVisualizer; - titleLabel: TLabel; + titleLabel: TTextNode; begin visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := False; - OwnerNode.Orientation := loVertical; - OwnerNode.Alignment := laFlush; - titleLabel := OwnerNode.AddLabel(OwnerNode, 'do'); - titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; + OwnerNode.Frameless := False; + OwnerNode.Orientation := loVertical; + OwnerNode.Alignment := laFlush; - FExpressionsNode := visu.CallAccept(FNode.Expressions); - FExpressionsNode.Frameless := True; - finally - OwnerNode.EndUpdate; - end; + titleLabel := OwnerNode.AddLabel(OwnerNode, 'do'); + titleLabel.FontSettings.Font.Style := [TFontStyle.fsBold]; + + FExpressionsNode := visu.CallAccept(FNode.Expressions); + FExpressionsNode.Frameless := True; end; function TBlockExpressionNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; @@ -643,19 +604,14 @@ end; procedure TIfExpressionNodeHandler.BuildUI(OwnerNode: TAstViewNode); begin - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := False; - OwnerNode.Orientation := loVertical; - OwnerNode.Alignment := laFlush; + OwnerNode.Frameless := False; + OwnerNode.Orientation := loVertical; + OwnerNode.Alignment := laFlush; - FConditionNode := OwnerNode.AddExpr(OwnerNode, 'if', FNode.Condition); - FThenNode := OwnerNode.AddExpr(OwnerNode, 'then', FNode.ThenBranch); - if Assigned(FNode.ElseBranch) then - FElseNode := OwnerNode.AddExpr(OwnerNode, 'else', FNode.ElseBranch); - finally - OwnerNode.EndUpdate; - end; + FConditionNode := OwnerNode.AddExpr(OwnerNode, 'if', FNode.Condition); + FThenNode := OwnerNode.AddExpr(OwnerNode, 'then', FNode.ThenBranch); + if Assigned(FNode.ElseBranch) then + FElseNode := OwnerNode.AddExpr(OwnerNode, 'else', FNode.ElseBranch); end; function TIfExpressionNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; @@ -677,18 +633,14 @@ var visu: IAstVisualizer; begin visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := True; - OwnerNode.Orientation := loHorizontal; - FConditionNode := visu.CallAccept(FNode.Condition); - OwnerNode.AddLabel(OwnerNode, '?'); - FThenNode := visu.CallAccept(FNode.ThenBranch); - OwnerNode.AddLabel(OwnerNode, ':'); - FElseNode := visu.CallAccept(FNode.ElseBranch); - finally - OwnerNode.EndUpdate; - end; + + OwnerNode.Frameless := True; + OwnerNode.Orientation := loHorizontal; + FConditionNode := visu.CallAccept(FNode.Condition); + OwnerNode.AddLabel(OwnerNode, '?'); + FThenNode := visu.CallAccept(FNode.ThenBranch); + OwnerNode.AddLabel(OwnerNode, ':'); + FElseNode := visu.CallAccept(FNode.ElseBranch); end; function TTernaryExpressionNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; @@ -701,31 +653,27 @@ end; procedure TLambdaExpressionNodeHandler.BuildUI(OwnerNode: TAstViewNode); var visu: IAstVisualizer; - titleContainer: TAutoFitControl; - lbl: TLabel; + titleContainer: TAutoFitLayout; + lbl: TTextNode; begin visu := OwnerNode.Visualizer.Clone(OwnerNode, 0); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := False; - OwnerNode.Orientation := loVertical; - OwnerNode.Alignment := laFlush; - OwnerNode.BackgroundColor := $090000ff; - titleContainer := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter); - lbl := OwnerNode.AddLabel(titleContainer, 'fn'); - lbl.Font.Style := lbl.Font.Style + [TFontStyle.fsBold]; + OwnerNode.Frameless := False; + OwnerNode.Orientation := loVertical; + OwnerNode.Alignment := laFlush; + OwnerNode.BackgroundColor := $090000ff; - // Parameters: Delegate to List Handler - var paramVisu := visu.Clone(titleContainer, 0); - FParamsNode := paramVisu.CallAccept(FNode.Parameters); + titleContainer := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter); + lbl := OwnerNode.AddLabel(titleContainer, 'fn'); + lbl.FontSettings.Font.Style := [TFontStyle.fsBold]; - // Body - FBodyNode := visu.CallAccept(FNode.Body); - FBodyNode.Frameless := False; - finally - OwnerNode.EndUpdate; - end; + // Parameters: Delegate to List Handler + var paramVisu := visu.Clone(titleContainer, 0); + FParamsNode := paramVisu.CallAccept(FNode.Parameters); + + // Body + FBodyNode := visu.CallAccept(FNode.Body); + FBodyNode.Frameless := False; end; function TLambdaExpressionNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; @@ -749,23 +697,19 @@ end; procedure TFunctionCallNodeHandler.BuildUI(OwnerNode: TAstViewNode); var visu: IAstVisualizer; - callLabel: TLabel; + callLabel: TTextNode; begin visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := True; - OwnerNode.Orientation := loHorizontal; - callLabel := OwnerNode.AddLabel(OwnerNode, 'call '); - callLabel.Font.Style := callLabel.Font.Style + [TFontStyle.fsBold]; + OwnerNode.Frameless := True; + OwnerNode.Orientation := loHorizontal; - FCalleeNode := visu.CallAccept(FNode.Callee); + callLabel := OwnerNode.AddLabel(OwnerNode, 'call '); + callLabel.FontSettings.Font.Style := [TFontStyle.fsBold]; - FArgumentsNode := visu.CallAccept(FNode.Arguments); - finally - OwnerNode.EndUpdate; - end; + FCalleeNode := visu.CallAccept(FNode.Callee); + + FArgumentsNode := visu.CallAccept(FNode.Arguments); end; function TFunctionCallNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; @@ -787,19 +731,15 @@ end; procedure TMacroExpansionNodeHandler.BuildUI(OwnerNode: TAstViewNode); var visu: IAstVisualizer; - titleLabel: TLabel; + titleLabel: TTextNode; begin visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := False; - OwnerNode.Orientation := loVertical; - titleLabel := OwnerNode.AddLabel(OwnerNode, 'Macro Expansion'); - titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; - FExpandedBodyNode := visu.CallAccept(FNode.ExpandedBody); - finally - OwnerNode.EndUpdate; - end; + + OwnerNode.Frameless := False; + OwnerNode.Orientation := loVertical; + titleLabel := OwnerNode.AddLabel(OwnerNode, 'Macro Expansion'); + titleLabel.FontSettings.Font.Style := [TFontStyle.fsBold]; + FExpandedBodyNode := visu.CallAccept(FNode.ExpandedBody); end; function TMacroExpansionNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; @@ -812,21 +752,17 @@ end; procedure TRecurNodeHandler.BuildUI(OwnerNode: TAstViewNode); var visu: IAstVisualizer; - titleLabel: TLabel; + titleLabel: TTextNode; begin visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := True; - OwnerNode.Orientation := loHorizontal; - titleLabel := OwnerNode.AddLabel(OwnerNode, 'recur'); - titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; + OwnerNode.Frameless := True; + OwnerNode.Orientation := loHorizontal; - FArgumentsNode := visu.CallAccept(FNode.Arguments); - finally - OwnerNode.EndUpdate; - end; + titleLabel := OwnerNode.AddLabel(OwnerNode, 'recur'); + titleLabel.FontSettings.Font.Style := [TFontStyle.fsBold]; + + FArgumentsNode := visu.CallAccept(FNode.Arguments); end; function TRecurNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; @@ -839,29 +775,25 @@ end; procedure TVariableDeclarationNodeHandler.BuildUI(OwnerNode: TAstViewNode); var visu: IAstVisualizer; - varLabel: TLabel; + varLabel: TTextNode; begin visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := True; - OwnerNode.Orientation := loHorizontal; - varLabel := OwnerNode.AddLabel(OwnerNode, 'var'); + OwnerNode.Frameless := True; + OwnerNode.Orientation := loHorizontal; - varLabel.Font.Style := varLabel.Font.Style + [TFontStyle.fsBold]; - FTargetNode := visu.CallAccept(FNode.Target); + varLabel := OwnerNode.AddLabel(OwnerNode, 'var'); - if Assigned(FNode.Initializer) then - begin - OwnerNode.AddLabel(OwnerNode, ':='); - FInitializerNode := visu.CallAccept(FNode.Initializer); - end - else - FInitializerNode := nil; - finally - OwnerNode.EndUpdate; - end; + varLabel.FontSettings.Font.Style := [TFontStyle.fsBold]; + FTargetNode := visu.CallAccept(FNode.Target); + + if Assigned(FNode.Initializer) then + begin + OwnerNode.AddLabel(OwnerNode, ':='); + FInitializerNode := visu.CallAccept(FNode.Initializer); + end + else + FInitializerNode := nil; end; function TVariableDeclarationNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; @@ -882,16 +814,12 @@ var visu: IAstVisualizer; begin visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := True; - OwnerNode.Orientation := loHorizontal; - FTargetNode := visu.CallAccept(FNode.Target); - OwnerNode.AddLabel(OwnerNode, ':='); - FValueNode := visu.CallAccept(FNode.Value); - finally - OwnerNode.EndUpdate; - end; + + OwnerNode.Frameless := True; + OwnerNode.Orientation := loHorizontal; + FTargetNode := visu.CallAccept(FNode.Target); + OwnerNode.AddLabel(OwnerNode, ':='); + FValueNode := visu.CallAccept(FNode.Value); end; function TAssignmentNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; @@ -904,27 +832,23 @@ end; procedure TMacroDefinitionNodeHandler.BuildUI(OwnerNode: TAstViewNode); var visu: IAstVisualizer; - titleLabel: TLabel; - titleContainer: TAutoFitControl; + titleLabel: TTextNode; + titleContainer: TAutoFitLayout; begin visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := False; - OwnerNode.Orientation := loVertical; - titleContainer := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter); - titleLabel := OwnerNode.AddLabel(titleContainer, 'Macro Def: ' + FNode.Name.Name); - titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; + OwnerNode.Frameless := False; + OwnerNode.Orientation := loVertical; - // Parameters List - var paramVisu := visu.Clone(titleContainer, visu.ExprDepth); - FParamsNode := paramVisu.CallAccept(FNode.Parameters); + titleContainer := OwnerNode.AddContainer(OwnerNode, loHorizontal, laCenter); + titleLabel := OwnerNode.AddLabel(titleContainer, 'Macro Def: ' + FNode.Name.Name); + titleLabel.FontSettings.Font.Style := [TFontStyle.fsBold]; - FBodyNode := visu.CallAccept(FNode.Body); - finally - OwnerNode.EndUpdate; - end; + // Parameters List + var paramVisu := visu.Clone(titleContainer, visu.ExprDepth); + FParamsNode := paramVisu.CallAccept(FNode.Parameters); + + FBodyNode := visu.CallAccept(FNode.Body); end; function TMacroDefinitionNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; @@ -937,19 +861,15 @@ end; procedure TQuasiquoteNodeHandler.BuildUI(OwnerNode: TAstViewNode); var visu: IAstVisualizer; - titleLabel: TLabel; + titleLabel: TTextNode; begin visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := False; - OwnerNode.Orientation := loVertical; - titleLabel := OwnerNode.AddLabel(OwnerNode, 'Quasiquote'); - titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; - FExpressionNode := visu.CallAccept(FNode.Expression); - finally - OwnerNode.EndUpdate; - end; + + OwnerNode.Frameless := False; + OwnerNode.Orientation := loVertical; + titleLabel := OwnerNode.AddLabel(OwnerNode, 'Quasiquote'); + titleLabel.FontSettings.Font.Style := [TFontStyle.fsBold]; + FExpressionNode := visu.CallAccept(FNode.Expression); end; function TQuasiquoteNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; @@ -962,26 +882,25 @@ end; procedure TUnquoteNodeHandler.BuildUI(OwnerNode: TAstViewNode); var visu: IAstVisualizer; - leftBracket, rightBracket: TLabel; + leftBracket, rightBracket: TTextNode; begin visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := True; - OwnerNode.Orientation := loHorizontal; - leftBracket := OwnerNode.AddLabel(OwnerNode, '<'); - leftBracket.Padding.Right := 0; - leftBracket.Margins.Right := 0; + OwnerNode.Frameless := True; + OwnerNode.Orientation := loHorizontal; - FExpressionNode := visu.CallAccept(FNode.Expression); + leftBracket := OwnerNode.AddLabel(OwnerNode, '<'); + // We cannot assign to fields of record properties directly. + // Replace the entire margin record. + // Default from AddLabel is (cNodePadding, cTitleTopPadding, cNodePadding, cTitleBottomPadding) + // We want Right Margin = 0. + leftBracket.Margins := TMarginRect.Create(cNodePadding, cTitleTopPadding, 0, cTitleBottomPadding); - rightBracket := OwnerNode.AddLabel(OwnerNode, '>'); - rightBracket.Padding.Left := 0; - rightBracket.Margins.Left := 0; - finally - OwnerNode.EndUpdate; - end; + FExpressionNode := visu.CallAccept(FNode.Expression); + + rightBracket := OwnerNode.AddLabel(OwnerNode, '>'); + // We want Left Margin = 0. + rightBracket.Margins := TMarginRect.Create(0, cTitleTopPadding, cNodePadding, cTitleBottomPadding); end; function TUnquoteNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; @@ -994,19 +913,15 @@ end; procedure TUnquoteSplicingNodeHandler.BuildUI(OwnerNode: TAstViewNode); var visu: IAstVisualizer; - titleLabel: TLabel; + titleLabel: TTextNode; begin visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := False; - OwnerNode.Orientation := loVertical; - titleLabel := OwnerNode.AddLabel(OwnerNode, 'Unquote-Splicing'); - titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; - FExpressionNode := visu.CallAccept(FNode.Expression); - finally - OwnerNode.EndUpdate; - end; + + OwnerNode.Frameless := False; + OwnerNode.Orientation := loVertical; + titleLabel := OwnerNode.AddLabel(OwnerNode, 'Unquote-Splicing'); + titleLabel.FontSettings.Font.Style := [TFontStyle.fsBold]; + FExpressionNode := visu.CallAccept(FNode.Expression); end; function TUnquoteSplicingNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; @@ -1021,17 +936,13 @@ var visu: IAstVisualizer; begin visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := True; - OwnerNode.Orientation := loHorizontal; - FBaseNode := visu.CallAccept(FNode.Base); - OwnerNode.AddLabel(OwnerNode, '['); - FIndexNode := visu.CallAccept(FNode.Index); - OwnerNode.AddLabel(OwnerNode, ']'); - finally - OwnerNode.EndUpdate; - end; + + OwnerNode.Frameless := True; + OwnerNode.Orientation := loHorizontal; + FBaseNode := visu.CallAccept(FNode.Base); + OwnerNode.AddLabel(OwnerNode, '['); + FIndexNode := visu.CallAccept(FNode.Index); + OwnerNode.AddLabel(OwnerNode, ']'); end; function TIndexerNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; @@ -1046,21 +957,16 @@ var visu: IAstVisualizer; begin visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := True; - OwnerNode.Orientation := loHorizontal; - FBaseNode := visu.CallAccept(FNode.Base); - OwnerNode.AddLabel(OwnerNode, '.'); - OwnerNode.AddLabel(OwnerNode, FNode.Member.Value.Name); - finally - OwnerNode.EndUpdate; - end; + + OwnerNode.Frameless := True; + OwnerNode.Orientation := loHorizontal; + FBaseNode := visu.CallAccept(FNode.Base); + OwnerNode.AddLabel(OwnerNode, '.'); + OwnerNode.AddLabel(OwnerNode, FNode.Member.Value.Name); end; function TMemberAccessNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; begin - // Reuse Identifier, Reuse Member Keyword (via TAst.Keyword with Identity) Result := TAst.MemberAccess(FNode.Identity, FBaseNode.CreateAst, TAst.Keyword(FNode.Member.Identity.AsKeyword), FNode.StaticType); end; @@ -1071,17 +977,13 @@ var visu: IAstVisualizer; begin visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := False; - OwnerNode.Orientation := loVertical; - OwnerNode.Alignment := laFlush; - // Delegate to RecordFieldList - FFieldsNode := visu.CallAccept(FNode.Fields); - finally - OwnerNode.EndUpdate; - end; + OwnerNode.Frameless := False; + OwnerNode.Orientation := loVertical; + OwnerNode.Alignment := laFlush; + + // Delegate to RecordFieldList + FFieldsNode := visu.CallAccept(FNode.Fields); end; function TRecordLiteralNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; @@ -1100,17 +1002,12 @@ end; procedure TCreateSeriesNodeHandler.BuildUI(OwnerNode: TAstViewNode); var - titleLabel: TLabel; + titleLabel: TTextNode; begin - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := False; - OwnerNode.Orientation := loVertical; - titleLabel := OwnerNode.AddLabel(OwnerNode, 'Create Series: ' + FNode.Definition); - titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; - finally - OwnerNode.EndUpdate; - end; + OwnerNode.Frameless := False; + OwnerNode.Orientation := loVertical; + titleLabel := OwnerNode.AddLabel(OwnerNode, 'Create Series: ' + FNode.Definition); + titleLabel.FontSettings.Font.Style := [TFontStyle.fsBold]; end; function TCreateSeriesNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; @@ -1123,25 +1020,21 @@ end; procedure TAddSeriesItemNodeHandler.BuildUI(OwnerNode: TAstViewNode); var visu: IAstVisualizer; - titleLabel: TLabel; + titleLabel: TTextNode; begin visu := OwnerNode.Visualizer.Clone(OwnerNode, OwnerNode.Visualizer.ExprDepth + 1); - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := False; - OwnerNode.Orientation := loVertical; - titleLabel := OwnerNode.AddLabel(OwnerNode, 'Add Item to: ' + FNode.Series.Name); - titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; + OwnerNode.Frameless := False; + OwnerNode.Orientation := loVertical; - FValueNode := visu.CallAccept(FNode.Value); - if Assigned(FNode.Lookback) then - FLookbackNode := visu.CallAccept(FNode.Lookback) - else - FLookbackNode := nil; - finally - OwnerNode.EndUpdate; - end; + titleLabel := OwnerNode.AddLabel(OwnerNode, 'Add Item to: ' + FNode.Series.Name); + titleLabel.FontSettings.Font.Style := [TFontStyle.fsBold]; + + FValueNode := visu.CallAccept(FNode.Value); + if Assigned(FNode.Lookback) then + FLookbackNode := visu.CallAccept(FNode.Lookback) + else + FLookbackNode := nil; end; function TAddSeriesItemNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; @@ -1167,17 +1060,12 @@ end; procedure TSeriesLengthNodeHandler.BuildUI(OwnerNode: TAstViewNode); var - titleLabel: TLabel; + titleLabel: TTextNode; begin - OwnerNode.BeginUpdate; - try - OwnerNode.Frameless := False; - OwnerNode.Orientation := loVertical; - titleLabel := OwnerNode.AddLabel(OwnerNode, 'Length of: ' + FNode.Series.Name); - titleLabel.Font.Style := titleLabel.Font.Style + [TFontStyle.fsBold]; - finally - OwnerNode.EndUpdate; - end; + OwnerNode.Frameless := False; + OwnerNode.Orientation := loVertical; + titleLabel := OwnerNode.AddLabel(OwnerNode, 'Length of: ' + FNode.Series.Name); + titleLabel.FontSettings.Font.Style := [TFontStyle.fsBold]; end; function TSeriesLengthNodeHandler.ReconstructAst(OwnerNode: TAstViewNode): IAstNode; diff --git a/Src/AST/Myc.Fmx.AstEditor.Node.pas b/Src/AST/Myc.Fmx.AstEditor.Node.pas index 5306f91..62d016e 100644 --- a/Src/AST/Myc.Fmx.AstEditor.Node.pas +++ b/Src/AST/Myc.Fmx.AstEditor.Node.pas @@ -12,13 +12,11 @@ uses System.Generics.Defaults, System.Generics.Collections, FMX.Types, - FMX.Controls, - FMX.Objects, FMX.Graphics, - FMX.StdCtrls, + FMX.TextLayout, Myc.Ast.Nodes, - Myc.Fmx.AstEditor.Workspace, - Myc.Fmx.AstEditor.Layout; + Myc.Fmx.AstEditor.Render, + Myc.Fmx.AstEditor.Workspace; const cNodePadding = 10; @@ -26,7 +24,7 @@ const cTitleBottomPadding = 4; cMinNodeWidth = 10; cMinNodeHeight = 10; - cDragGutterWidth = 20; // Width of the trigger zone for dragging + cDragGutterWidth = 20; type TAstViewNode = class; @@ -40,26 +38,26 @@ type IReorderable = interface ['{9FA7C504-D327-4E00-A5FE-DD2876886212}'] - function CanDrag(Child: TControl): Boolean; + function CanDrag(Child: TVisualNode): Boolean; procedure MoveChild(SourceIndex, TargetIndex: Integer); end; IAstVisualizer = interface {$region 'private'} function GetExprDepth: Integer; - function GetParentControl: TControl; + function GetParentNode: TVisualNode; function GetWorkspace: TWorkspace; {$endregion} - function Clone(ParentControl: TControl; ExprDepth: Integer): IAstVisualizer; + function Clone(ParentNode: TVisualNode; ExprDepth: Integer): IAstVisualizer; function CallAccept(const Node: IAstNode): TAstViewNode; property ExprDepth: Integer read GetExprDepth; - property ParentControl: TControl read GetParentControl; + property ParentNode: TVisualNode read GetParentNode; property Workspace: TWorkspace read GetWorkspace; end; - TAstViewNode = class(TAutoFitControl) + TAstViewNode = class(TAutoFitLayout) private FBackgroundColor: TAlphaColor; FBorderColor: TAlphaColor; @@ -73,6 +71,7 @@ type FTypeInfoText: string; FIsFocused: Boolean; + FIsHovered: Boolean; procedure SetBackgroundColor(const Value: TAlphaColor); procedure SetBorderColor(const Value: TAlphaColor); @@ -83,28 +82,27 @@ type procedure SetErrorMessage(const Value: string); procedure SetTypeInfoText(const Value: string); - procedure UpdateVisualState; procedure SetIsFocused(const Value: Boolean); + procedure InvalidateVisuals; protected - procedure Paint; override; + procedure DoPaint(Canvas: TCanvas; const Offset: TPointF); override; procedure SetupNode; - procedure DoMouseEnter; override; - procedure DoMouseLeave; override; - procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override; - procedure MouseMove(Shift: TShiftState; X, Y: Single); override; - procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override; - public constructor Create(const AVisualizer: IAstVisualizer; const AHandler: IAstViewNodeHandler); reintroduce; destructor Destroy; override; procedure AfterConstruction; override; - function AddLabel(Parent: TControl; const Txt: String): TLabel; - function AddContainer(Parent: TControl; Orientation: TLayoutOrientation; Alignment: TLayoutAlignment): TAutoFitControl; - function AddExpr(Parent: TControl; const Title: String; const Node: IAstNode): TAstViewNode; + procedure MouseEnter; override; + procedure MouseLeave; override; + procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override; + procedure MouseMove(Shift: TShiftState; X, Y: Single); override; + + function AddLabel(Parent: TVisualNode; const Txt: String): TTextNode; + function AddContainer(Parent: TVisualNode; Orientation: TLayoutOrientation; Alignment: TLayoutAlignment): TAutoFitLayout; + function AddExpr(Parent: TVisualNode; const Title: String; const Node: IAstNode): TAstViewNode; function CreateAst: IAstNode; @@ -116,42 +114,11 @@ type property TypeInfoText: string read FTypeInfoText write SetTypeInfoText; property IsFocused: Boolean read FIsFocused write SetIsFocused; - published property BorderColor: TAlphaColor read FBorderColor write SetBorderColor; property BorderWidth: Single read FBorderWidth write SetBorderWidth; property BorderRadius: Single read FBorderRadius write SetBorderRadius; property BackgroundColor: TAlphaColor read FBackgroundColor write SetBackgroundColor; property Frameless: Boolean read FFrameless write SetFrameless; - - property Align; - property Anchors; - property ClipChildren default True; - property Cursor default crDefault; - property DragMode default TDragMode.dmManual; - property Enabled; - property Height; - property Hint; - property HitTest default True; - property Locked; - property Margins; - property Opacity; - property Padding; - property PopupMenu; - property Position; - property RotationAngle; - property RotationCenter; - property Scale; - property Size; - property Visible; - property Width; - property OnClick; - property OnDblClick; - property OnMouseDown; - property OnMouseMove; - property OnMouseUp; - property OnMouseWheel; - property OnMouseEnter; - property OnMouseLeave; end; TBaseNodeHandler = class(TInterfacedObject, IAstViewNodeHandler) @@ -173,9 +140,10 @@ uses constructor TAstViewNode.Create(const AVisualizer: IAstVisualizer; const AHandler: IAstViewNodeHandler); begin - inherited Create(AVisualizer.Workspace); + inherited Create(AVisualizer.Workspace as IVisualHost); - Parent := AVisualizer.ParentControl; + if Assigned(AVisualizer.ParentNode) then + AVisualizer.ParentNode.AddChild(Self); FVisualizer := AVisualizer.Clone(Self, AVisualizer.ExprDepth); FHandler := AHandler; @@ -187,25 +155,18 @@ begin FFrameless := False; FIsFocused := False; + FIsHovered := False; - Width := cMinNodeWidth; - Height := cMinNodeHeight; + Size := TSizeF.Create(cMinNodeWidth, cMinNodeHeight); - HitTest := True; - ClipChildren := True; + HitTestEnabled := True; - Margins.Left := 4; - Margins.Top := 4; - Margins.Right := 4; - Margins.Bottom := 4; - Padding.Left := 3; - Padding.Top := 3; - Padding.Right := 3; - Padding.Bottom := 3; + Margins := TMarginRect.Create(4, 4, 4, 4); + Padding := TMarginRect.Create(3, 3, 3, 3); var cn: Cardinal := $ea - (7 * FVisualizer.ExprDepth); var c: Cardinal := $ff000000 or (cn shl 16) or (cn shl 8) or cn; - BackgroundColor := c; + FBackgroundColor := c; end; destructor TAstViewNode.Destroy; @@ -214,103 +175,18 @@ begin inherited; end; -procedure TAstViewNode.DoMouseEnter; -begin - inherited; - Repaint; -end; - -procedure TAstViewNode.DoMouseLeave; -begin - inherited; - Repaint; -end; - -procedure TAstViewNode.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); -const - cHeaderHeight = 30; // Defined height for header drag area -begin - // Check for Drag Start. - // Condition: Left Click AND we are part of a container (list) - if (Button = TMouseButton.mbLeft) and (Parent is TAutoFitControl) then - begin - // Hit-Test: Either Gutter (Left) OR Header area (Top) - if (X < cDragGutterWidth) or (Y < cHeaderHeight) then - begin - if Assigned(FVisualizer.Workspace) then - begin - FVisualizer.Workspace.BeginDragNode(Self); - Exit; - end; - end; - end; - - inherited; -end; - -procedure TAstViewNode.MouseMove(Shift: TShiftState; X, Y: Single); -const - cHeaderHeight = 30; -begin - // Cursor Logic (Hover Feedback) - if (Parent is TAutoFitControl) and ((X < cDragGutterWidth) or (Y < cHeaderHeight)) then - Cursor := crSizeAll - else - Cursor := crDefault; - - inherited; -end; - -procedure TAstViewNode.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single); -begin - inherited; -end; - -function TAstViewNode.AddContainer(Parent: TControl; Orientation: TLayoutOrientation; Alignment: TLayoutAlignment): TAutoFitControl; -begin - Result := TAutoFitControl.Create(Self); - Result.Parent := Parent; - Result.Orientation := Orientation; - Result.Alignment := Alignment; - Result.HitTest := False; -end; - -function TAstViewNode.AddExpr(Parent: TControl; const Title: String; const Node: IAstNode): TAstViewNode; -begin - var cont := AddContainer(Parent, loHorizontal, laCenter); - - var lbl := AddLabel(cont, Title); - lbl.Font.Style := lbl.Font.Style + [TFontStyle.fsBold]; - - Result := FVisualizer.Clone(cont, FVisualizer.ExprDepth + 1).CallAccept(Node); -end; - -function TAstViewNode.AddLabel(Parent: TControl; const Txt: String): TLabel; -begin - Result := TLabel.Create(Self); - Result.Parent := Parent; - - Result.Position.Point := TPoint.Create(cNodePadding, cNodePadding); - Result.Margins.Left := cNodePadding; - Result.Margins.Right := cNodePadding; - Result.Margins.Top := cTitleTopPadding; - Result.Margins.Bottom := cTitleBottomPadding; - Result.WordWrap := False; - Result.AutoSize := True; - Result.HitTest := False; - - Result.StyledSettings := Result.StyledSettings - [TStyledSetting.Style]; - - Result.Text := Txt; - Result.ApplyStyleLookup; -end; - procedure TAstViewNode.AfterConstruction; begin inherited; SetupNode; end; +procedure TAstViewNode.SetupNode; +begin + if Assigned(FHandler) then + FHandler.BuildUI(Self); +end; + function TAstViewNode.CreateAst: IAstNode; begin if Assigned(FHandler) then @@ -327,154 +203,142 @@ begin Result := nil; end; -procedure TAstViewNode.SetErrorMessage(const Value: string); +function TAstViewNode.AddContainer(Parent: TVisualNode; Orientation: TLayoutOrientation; Alignment: TLayoutAlignment): TAutoFitLayout; begin - if FErrorMessage <> Value then - begin - FErrorMessage := Value; - UpdateVisualState; - Repaint; - end; + Result := TAutoFitLayout.Create(Host); + Parent.AddChild(Result); + Result.Orientation := Orientation; + Result.Alignment := Alignment; + Result.HitTestEnabled := False; end; -procedure TAstViewNode.SetTypeInfoText(const Value: string); +function TAstViewNode.AddExpr(Parent: TVisualNode; const Title: String; const Node: IAstNode): TAstViewNode; begin - if FTypeInfoText <> Value then - begin - FTypeInfoText := Value; - UpdateVisualState; - end; + var cont := AddContainer(Parent, loHorizontal, laCenter); + + var lbl := AddLabel(cont, Title); + lbl.FontSettings.Font.Style := [TFontStyle.fsBold]; + + Result := FVisualizer.Clone(cont, FVisualizer.ExprDepth + 1).CallAccept(Node); end; -procedure TAstViewNode.SetIsFocused(const Value: Boolean); +function TAstViewNode.AddLabel(Parent: TVisualNode; const Txt: String): TTextNode; begin - if FIsFocused <> Value then - begin - FIsFocused := Value; - Repaint; - end; + Result := TTextNode.Create(Host); + Parent.AddChild(Result); + + Result.Margins := TMarginRect.Create(cNodePadding, cTitleTopPadding, cNodePadding, cTitleBottomPadding); + Result.Padding := TMarginRect.Create(0, 0, 0, 0); + + Result.Text := Txt; end; -procedure TAstViewNode.UpdateVisualState; -begin - if FErrorMessage <> '' then - begin - Hint := 'Error: ' + FErrorMessage; - ShowHint := True; - end - else if FTypeInfoText <> '' then - begin - Hint := 'Type: ' + FTypeInfoText; - ShowHint := True; - end - else - begin - Hint := ''; - ShowHint := False; - end; -end; - -procedure TAstViewNode.Paint; +procedure TAstViewNode.DoPaint(Canvas: TCanvas; const Offset: TPointF); var - rect: TRectF; - effBorderColor: TAlphaColor; - effBorderWidth: Single; - effDash: TStrokeDash; - isHovering: Boolean; - shouldIgnoreHover: Boolean; + Rect: TRectF; + EffBorderColor: TAlphaColor; + EffBorderWidth: Single; + EffDash: TStrokeDash; + ShouldIgnoreHover: Boolean; begin - inherited; + Rect := TRectF.Create(Offset, Size.Width, Size.Height); - shouldIgnoreHover := False; + ShouldIgnoreHover := False; if Assigned(Node) then begin case Node.Kind of - akBlockExpression, akParameterList, akArgumentList, akExpressionList, akRecordFieldList: shouldIgnoreHover := True; + akBlockExpression, akParameterList, akArgumentList, akExpressionList, akRecordFieldList: ShouldIgnoreHover := True; end; end; - isHovering := IsMouseOver and (not shouldIgnoreHover); - - // 1. Determine Base Style if FFrameless then begin - effBorderColor := FBorderColor; - effBorderWidth := FBorderWidth; - effDash := TStrokeDash.Dot; + EffBorderColor := FBorderColor; + EffBorderWidth := FBorderWidth; + EffDash := TStrokeDash.Dot; end else begin - effBorderColor := FBorderColor; - effBorderWidth := FBorderWidth; - effDash := TStrokeDash.Solid; + EffBorderColor := FBorderColor; + EffBorderWidth := FBorderWidth; + EffDash := TStrokeDash.Solid; end; - // 2. Hover Overlay - if isHovering then + if FIsHovered and (not ShouldIgnoreHover) then begin - effBorderColor := TAlphaColors.White; - effBorderWidth := Max(2.0, FBorderWidth + 1.0); - effDash := TStrokeDash.Solid; + EffBorderColor := TAlphaColors.White; + EffBorderWidth := Max(2.0, FBorderWidth + 1.0); + EffDash := TStrokeDash.Solid; end; - // 3. Error Overlay (High Priority for Color) if FErrorMessage <> '' then begin - effBorderColor := TAlphaColors.Red; - effBorderWidth := 2.0; - effDash := TStrokeDash.Solid; + EffBorderColor := TAlphaColors.Red; + EffBorderWidth := 2.0; + EffDash := TStrokeDash.Solid; end; - // 4. Focus Overlay (Highest Priority for Visibility/Color) - // Note: If Error is present, Focus will override color to Blue to indicate "Active Cursor". - // Error text is available in Hint. if FIsFocused then begin - effBorderColor := TAlphaColors.Dodgerblue; - effBorderWidth := 2.0; - effDash := TStrokeDash.Solid; + EffBorderColor := TAlphaColors.Dodgerblue; + EffBorderWidth := 2.0; + EffDash := TStrokeDash.Solid; end; Canvas.Fill.Kind := TBrushKind.Solid; Canvas.Fill.Color := FBackgroundColor; - if FFrameless and (FErrorMessage = '') and (not isHovering) and (not FIsFocused) then + if FFrameless and (FErrorMessage = '') and (not FIsHovered) and (not FIsFocused) then begin - Canvas.FillRect(TRectF.Create(0, 0, Width, Height), 0, 0, [], 1.0); + Canvas.FillRect(Rect, 0, 0, AllCorners, 1.0); if FBorderWidth > 0 then begin Canvas.Stroke.Kind := TBrushKind.Solid; - Canvas.Stroke.Color := effBorderColor; - Canvas.Stroke.Thickness := effBorderWidth; - Canvas.Stroke.Dash := effDash; - Canvas.DrawRect(TRectF.Create(0, 0, Width, Height), 0, 0, [], 1.0); + Canvas.Stroke.Color := EffBorderColor; + Canvas.Stroke.Thickness := EffBorderWidth; + Canvas.Stroke.Dash := EffDash; + Canvas.DrawRect(Rect, 0, 0, AllCorners, 1.0); end; end else begin - rect := TRectF.Create(0, 0, Width, Height); - if (effBorderWidth > 0) then - rect.Inflate(-effBorderWidth / 2, -effBorderWidth / 2); + var DrawRect := Rect; + if EffBorderWidth > 0 then + DrawRect.Inflate(-EffBorderWidth / 2, -EffBorderWidth / 2); - Canvas.FillRect(rect, FBorderRadius, FBorderRadius, AllCorners, 1.0, TCornerType.Round); + Canvas.FillRect(DrawRect, FBorderRadius, FBorderRadius, AllCorners, 1.0, TCornerType.Round); - if (effBorderWidth > 0) and (effBorderColor <> TAlphaColors.Null) then + if (EffBorderWidth > 0) and (EffBorderColor <> TAlphaColors.Null) then begin Canvas.Stroke.Kind := TBrushKind.Solid; - Canvas.Stroke.Color := effBorderColor; - Canvas.Stroke.Thickness := effBorderWidth; - Canvas.Stroke.Dash := effDash; - Canvas.DrawRect(rect, FBorderRadius, FBorderRadius, AllCorners, 1.0, TCornerType.Round); + Canvas.Stroke.Color := EffBorderColor; + Canvas.Stroke.Thickness := EffBorderWidth; + Canvas.Stroke.Dash := EffDash; + Canvas.DrawRect(DrawRect, FBorderRadius, FBorderRadius, AllCorners, 1.0, TCornerType.Round); end; end; - if isHovering and (Parent is TAutoFitControl) then + if FIsHovered and (Parent is TAutoFitLayout) then begin Canvas.Fill.Color := TAlphaColors.DimGray; - Canvas.FillEllipse(TRectF.Create(4, 6, 8, 10), 1.0); - Canvas.FillEllipse(TRectF.Create(4, 12, 8, 16), 1.0); - Canvas.FillEllipse(TRectF.Create(4, 18, 8, 22), 1.0); + Canvas.FillEllipse(TRectF.Create(Offset.X + 4, Offset.Y + 6, Offset.X + 12, Offset.Y + 14), 1.0); + Canvas.FillEllipse(TRectF.Create(Offset.X + 4, Offset.Y + 16, Offset.X + 12, Offset.Y + 24), 1.0); + end; +end; + +procedure TAstViewNode.InvalidateVisuals; +begin + if Assigned(Host) then + Host.InvalidateRect(AbsoluteRect); +end; + +procedure TAstViewNode.SetBackgroundColor(const Value: TAlphaColor); +begin + if FBackgroundColor <> Value then + begin + FBackgroundColor := Value; + InvalidateVisuals; end; end; @@ -483,7 +347,7 @@ begin if FBorderColor <> Value then begin FBorderColor := Value; - Repaint; + InvalidateVisuals; end; end; @@ -492,7 +356,7 @@ begin if FBorderRadius <> Value then begin FBorderRadius := Value; - Repaint; + InvalidateVisuals; end; end; @@ -501,7 +365,17 @@ begin if FBorderWidth <> Value then begin FBorderWidth := Value; - Repaint; + RequestLayout; + InvalidateVisuals; + end; +end; + +procedure TAstViewNode.SetErrorMessage(const Value: string); +begin + if FErrorMessage <> Value then + begin + FErrorMessage := Value; + InvalidateVisuals; end; end; @@ -510,20 +384,60 @@ begin if FFrameless <> Value then begin FFrameless := Value; - Repaint; + InvalidateVisuals; end; end; -procedure TAstViewNode.SetBackgroundColor(const Value: TAlphaColor); +procedure TAstViewNode.SetIsFocused(const Value: Boolean); begin - FBackgroundColor := Value; - Repaint; + if FIsFocused <> Value then + begin + FIsFocused := Value; + InvalidateVisuals; + end; end; -procedure TAstViewNode.SetupNode; +procedure TAstViewNode.SetTypeInfoText(const Value: string); begin - if Assigned(FHandler) then - FHandler.BuildUI(Self); + if FTypeInfoText <> Value then + begin + FTypeInfoText := Value; + end; +end; + +procedure TAstViewNode.MouseEnter; +begin + FIsHovered := True; + InvalidateVisuals; +end; + +procedure TAstViewNode.MouseLeave; +begin + FIsHovered := False; + InvalidateVisuals; +end; + +procedure TAstViewNode.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); +const + cHeaderHeight = 30; +begin + if (Button = TMouseButton.mbLeft) and (Parent is TAutoFitLayout) then + begin + if (X < cDragGutterWidth) or (Y < cHeaderHeight) then + begin + if Assigned(FVisualizer.Workspace) then + begin + FVisualizer.Workspace.BeginDragNode(Self); + Exit; + end; + end; + end; + inherited; +end; + +procedure TAstViewNode.MouseMove(Shift: TShiftState; X, Y: Single); +begin + inherited; end; { TBaseNodeHandler } diff --git a/Src/AST/Myc.Fmx.AstEditor.Render.pas b/Src/AST/Myc.Fmx.AstEditor.Render.pas new file mode 100644 index 0000000..b3abc16 --- /dev/null +++ b/Src/AST/Myc.Fmx.AstEditor.Render.pas @@ -0,0 +1,626 @@ +unit Myc.Fmx.AstEditor.Render; + +interface + +uses + System.Types, + System.UITypes, + System.Classes, + System.SysUtils, + System.Math, + System.Generics.Collections, + FMX.Types, + FMX.Graphics, + FMX.TextLayout; + +type + TVisualNode = class; + + // Interface for the host (e.g. TWorkspace) to request repaints/layouts + IVisualHost = interface + ['{A9E2BD60-281B-42A2-9DB5-3100E8EF1519}'] + procedure InvalidateRect(const R: TRectF); + procedure RequestLayout; + function GetCanvas: TCanvas; + end; + + // Helper structure for margins and padding + TMarginRect = record + Left, Top, Right, Bottom: Single; + function Width: Single; inline; + function Height: Single; inline; + class function Create(L, T, R, B: Single): TMarginRect; static; inline; + class operator Initialize(out Dest: TMarginRect); + end; + + // The base class for all virtual UI elements (Flyweight) + TVisualNode = class + private + FHost: IVisualHost; + FParent: TVisualNode; + FChildren: TList; + + // Data stored as Position and Size (Layout Model) + // Direct field access is preferred within the unit + FPosition: TPointF; + FSize: TSizeF; + + FPadding: TMarginRect; + FMargins: TMarginRect; + FVisible: Boolean; + FHitTest: Boolean; + FTag: NativeInt; + FOpacity: Single; + + procedure SetParent(const Value: TVisualNode); + + protected + procedure SetHost(const Value: IVisualHost); virtual; + // Called to paint the node-specific content (background, etc.) + procedure DoPaint(Canvas: TCanvas; const Offset: TPointF); virtual; + public + constructor Create(AHost: IVisualHost = nil); virtual; + destructor Destroy; override; + + // Layout system + procedure RequestLayout; + procedure RecalcLayout; virtual; + + // Geometry + function GetAbsolutePosition: TPointF; + function LocalToAbsolute(const P: TPointF): TPointF; + function AbsoluteToLocal(const P: TPointF): TPointF; + function AbsoluteRect: TRectF; + + function HitTest(const P: TPointF): TVisualNode; virtual; + + // Rendering pipeline + // Offset is the absolute position of the parent content area + procedure Paint(Canvas: TCanvas; const Offset: TPointF); + + // Child Management + procedure AddChild(Child: TVisualNode); + procedure RemoveChild(Child: TVisualNode); + procedure DeleteChildren; + function GetChildCount: Integer; inline; + function GetChild(Index: Integer): TVisualNode; inline; + + // Interaction stubs (called by the host) + procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); virtual; + procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single); virtual; + procedure MouseMove(Shift: TShiftState; X, Y: Single); virtual; + procedure MouseEnter; virtual; + procedure MouseLeave; virtual; + + property Host: IVisualHost read FHost; + property Parent: TVisualNode read FParent; + + // Direct field access via properties + property Position: TPointF read FPosition write FPosition; + property Size: TSizeF read FSize write FSize; + + property Padding: TMarginRect read FPadding write FPadding; + property Margins: TMarginRect read FMargins write FMargins; + + property Visible: Boolean read FVisible write FVisible; + property HitTestEnabled: Boolean read FHitTest write FHitTest; + property Opacity: Single read FOpacity write FOpacity; + property Tag: NativeInt read FTag write FTag; + end; + + // Lightweight replacement for TLabel + TTextNode = class(TVisualNode) + private + FText: string; + FLayout: TTextLayout; + FFontSettings: TTextSettings; // Stores font properties + FColor: TAlphaColor; + FIsLayoutDirty: Boolean; + procedure SetText(const Value: string); + procedure SetColor(const Value: TAlphaColor); + protected + procedure DoPaint(Canvas: TCanvas; const Offset: TPointF); override; + procedure UpdateTextLayout(Canvas: TCanvas); + public + constructor Create(AHost: IVisualHost = nil); override; + destructor Destroy; override; + procedure RecalcLayout; override; + + property Text: string read FText write SetText; + property Color: TAlphaColor read FColor write SetColor; + property FontSettings: TTextSettings read FFontSettings; + end; + + TLayoutOrientation = (loVertical, loHorizontal); + TLayoutAlignment = (laCenter, laFlush); + + // The Layout Manager + TAutoFitLayout = class(TVisualNode) + private + FOrientation: TLayoutOrientation; + FAlignment: TLayoutAlignment; + procedure SetOrientation(const Value: TLayoutOrientation); + procedure SetAlignment(const Value: TLayoutAlignment); + protected + // TAutoFitLayout is a container, draws no background by default, but propagates Paint to children + procedure DoPaint(Canvas: TCanvas; const Offset: TPointF); override; + public + constructor Create(AHost: IVisualHost = nil); override; + procedure RecalcLayout; override; + + // Calculates the insertion index for drag & drop based on coordinates + function GetInsertionIndex(const LocalP: TPointF): Integer; + + property Orientation: TLayoutOrientation read FOrientation write SetOrientation; + property Alignment: TLayoutAlignment read FAlignment write SetAlignment; + end; + +implementation + +{ TMarginRect } + +class function TMarginRect.Create(L, T, R, B: Single): TMarginRect; +begin + Result.Left := L; + Result.Top := T; + Result.Right := R; + Result.Bottom := B; +end; + +class operator TMarginRect.Initialize(out Dest: TMarginRect); +begin + Dest.Left := 0; + Dest.Top := 0; + Dest.Right := 0; + Dest.Bottom := 0; +end; + +function TMarginRect.Height: Single; +begin + Result := Top + Bottom; +end; + +function TMarginRect.Width: Single; +begin + Result := Left + Right; +end; + +{ TVisualNode } + +constructor TVisualNode.Create(AHost: IVisualHost); +begin + inherited Create; + FHost := AHost; + FChildren := TList.Create; + FVisible := True; + FHitTest := True; + FOpacity := 1.0; + FPosition := TPointF.Create(0, 0); + FSize := TSizeF.Create(10, 10); +end; + +destructor TVisualNode.Destroy; +begin + // Recursive release + for var i := 0 to FChildren.Count - 1 do + FChildren[i].Free; + FChildren.Free; + inherited; +end; + +procedure TVisualNode.SetParent(const Value: TVisualNode); +begin + if FParent <> Value then + begin + FParent := Value; + // Propagate host if parent has one + if (FHost = nil) and Assigned(FParent) then + SetHost(FParent.Host); + end; +end; + +procedure TVisualNode.SetHost(const Value: IVisualHost); +begin + FHost := Value; + for var Child in FChildren do + Child.SetHost(Value); +end; + +procedure TVisualNode.AddChild(Child: TVisualNode); +begin + if Child.Parent <> nil then + Child.Parent.RemoveChild(Child); + + FChildren.Add(Child); + Child.SetParent(Self); + RequestLayout; +end; + +procedure TVisualNode.RemoveChild(Child: TVisualNode); +begin + FChildren.Remove(Child); + Child.FParent := nil; + RequestLayout; +end; + +procedure TVisualNode.DeleteChildren; +begin + for var i := 0 to FChildren.Count - 1 do + FChildren[i].Free; + FChildren.Clear; + RequestLayout; +end; + +function TVisualNode.GetChild(Index: Integer): TVisualNode; +begin + Result := FChildren[Index]; +end; + +function TVisualNode.GetChildCount: Integer; +begin + Result := FChildren.Count; +end; + +procedure TVisualNode.RequestLayout; +begin + if Assigned(FParent) then + FParent.RequestLayout + else if Assigned(FHost) then + FHost.RequestLayout; +end; + +procedure TVisualNode.RecalcLayout; +begin + // Base implementation: Does nothing. + // Subclasses (Layouts) must implement calculation here. +end; + +function TVisualNode.GetAbsolutePosition: TPointF; +var + Curr: TVisualNode; +begin + Result := FPosition; + Curr := FParent; + while Assigned(Curr) do + begin + // Add parent position + padding (since we are in the content area) + Result := Result + Curr.FPosition + TPointF.Create(Curr.Padding.Left, Curr.Padding.Top); + Curr := Curr.Parent; + end; +end; + +function TVisualNode.LocalToAbsolute(const P: TPointF): TPointF; +begin + Result := GetAbsolutePosition + P; +end; + +function TVisualNode.AbsoluteToLocal(const P: TPointF): TPointF; +begin + Result := P - GetAbsolutePosition; +end; + +function TVisualNode.AbsoluteRect: TRectF; +begin + Result := TRectF.Create(GetAbsolutePosition, FSize.Width, FSize.Height); +end; + +procedure TVisualNode.Paint(Canvas: TCanvas; const Offset: TPointF); +var + AbsPos: TPointF; + ChildOffset: TPointF; + Child: TVisualNode; +begin + if not FVisible then + exit; + + // Absolute position of this node + AbsPos := Offset + FPosition; + + // 1. Background / Own content + DoPaint(Canvas, AbsPos); + + // 2. Draw children + if FChildren.Count > 0 then + begin + // The 0,0 point for children is shifted by padding + ChildOffset := AbsPos + TPointF.Create(FPadding.Left, FPadding.Top); + for Child in FChildren do + Child.Paint(Canvas, ChildOffset); + end; +end; + +procedure TVisualNode.DoPaint(Canvas: TCanvas; const Offset: TPointF); +begin + // Stub +end; + +function TVisualNode.HitTest(const P: TPointF): TVisualNode; +var + i: Integer; + Child: TVisualNode; + LocalP: TPointF; + ContentOrigin: TPointF; +begin + Result := nil; + if not FVisible or not FHitTest then + exit; + + // P is relative to Position of this node. Check if P is inside rect. + if not TRectF.Create(0, 0, FSize.Width, FSize.Height).Contains(P) then + exit; + + ContentOrigin := TPointF.Create(FPadding.Left, FPadding.Top); + + // Check children in reverse Z-order (topmost first) + for i := FChildren.Count - 1 downto 0 do + begin + Child := FChildren[i]; + // Transformation into child coordinates + LocalP := P - ContentOrigin - Child.FPosition; + + Result := Child.HitTest(LocalP); + if Result <> nil then + exit; + end; + + // If no child hit, it's us + Result := Self; +end; + +procedure TVisualNode.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); +begin +end; +procedure TVisualNode.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single); +begin +end; +procedure TVisualNode.MouseMove(Shift: TShiftState; X, Y: Single); +begin +end; +procedure TVisualNode.MouseEnter; +begin +end; +procedure TVisualNode.MouseLeave; +begin +end; + +{ TTextNode } + +constructor TTextNode.Create(AHost: IVisualHost); +begin + inherited; + FHitTest := False; // Text is usually passive + FIsLayoutDirty := True; + FFontSettings := TTextSettings.Create(nil); + FColor := TAlphaColors.Black; +end; + +destructor TTextNode.Destroy; +begin + FreeAndNil(FLayout); + FreeAndNil(FFontSettings); + inherited; +end; + +procedure TTextNode.SetText(const Value: string); +begin + if FText <> Value then + begin + FText := Value; + FIsLayoutDirty := True; + RequestLayout; + end; +end; + +procedure TTextNode.SetColor(const Value: TAlphaColor); +begin + if FColor <> Value then + begin + FColor := Value; + if Assigned(FHost) then + FHost.InvalidateRect(AbsoluteRect); + end; +end; + +procedure TTextNode.UpdateTextLayout(Canvas: TCanvas); +begin + if FIsLayoutDirty or (FLayout = nil) then + begin + if FLayout = nil then + FLayout := TTextLayoutManager.DefaultTextLayout.Create(Canvas); + + FLayout.BeginUpdate; + try + FLayout.Text := FText; + FLayout.Font.Assign(FFontSettings.Font); + FLayout.Color := FColor; + FLayout.WordWrap := False; + finally + FLayout.EndUpdate; + end; + FIsLayoutDirty := False; + end; +end; + +procedure TTextNode.RecalcLayout; +begin + if Assigned(FHost) then + begin + UpdateTextLayout(FHost.GetCanvas); + + FSize.Width := FLayout.TextRect.Width + FPadding.Width; + FSize.Height := FLayout.TextRect.Height + FPadding.Height; + + // Safety net for empty strings + if FSize.Width < 1 then + FSize.Width := 5; + if FSize.Height < 1 then + FSize.Height := 10; + end; +end; + +procedure TTextNode.DoPaint(Canvas: TCanvas; const Offset: TPointF); +begin + UpdateTextLayout(Canvas); + var P := Offset + TPointF.Create(FPadding.Left, FPadding.Top); + + // Set position and color on layout, then render + FLayout.TopLeft := P; + FLayout.Color := FColor; + FLayout.RenderLayout(Canvas); +end; + +{ TAutoFitLayout } + +constructor TAutoFitLayout.Create(AHost: IVisualHost); +begin + inherited; + FOrientation := loHorizontal; + FAlignment := laCenter; +end; + +procedure TAutoFitLayout.SetOrientation(const Value: TLayoutOrientation); +begin + if FOrientation <> Value then + begin + FOrientation := Value; + RequestLayout; + end; +end; + +procedure TAutoFitLayout.SetAlignment(const Value: TLayoutAlignment); +begin + if FAlignment <> Value then + begin + FAlignment := Value; + RequestLayout; + end; +end; + +procedure TAutoFitLayout.DoPaint(Canvas: TCanvas; const Offset: TPointF); +begin + // TAutoFitLayout is a container, draws no background by default. + inherited DoPaint(Canvas, Offset); +end; + +procedure TAutoFitLayout.RecalcLayout; +var + Child: TVisualNode; + CurrentX, CurrentY: Single; + ReqW, ReqH: Single; +begin + // 1. Recursion: Calculate children + for Child in FChildren do + begin + if Child.Visible then + Child.RecalcLayout; + end; + + CurrentX := 0; + CurrentY := 0; + ReqW := 0; + ReqH := 0; + + // 2. Stacking Logic + if FOrientation = loVertical then + begin + for Child in FChildren do + begin + if not Child.Visible then + continue; + + // Set Y-Position + Child.FPosition := TPointF.Create(Child.Margins.Left, CurrentY + Child.Margins.Top); + + var ChildTotalH := Child.Size.Height + Child.Margins.Top + Child.Margins.Bottom; + var ChildTotalW := Child.Size.Width + Child.Margins.Left + Child.Margins.Right; + + CurrentY := CurrentY + ChildTotalH; + ReqW := Max(ReqW, ChildTotalW); + end; + ReqH := CurrentY; + + // 3. Alignment Logic (Cross-Axis) + if FAlignment = laCenter then + begin + for Child in FChildren do + begin + if not Child.Visible then + continue; + var ChildTotalW := Child.Size.Width + Child.Margins.Left + Child.Margins.Right; + var OffsetX := (ReqW - ChildTotalW) * 0.5; + Child.FPosition := TPointF.Create(Child.Margins.Left + OffsetX, Child.FPosition.Y); + end; + end; + end + else // Horizontal + begin + for Child in FChildren do + begin + if not Child.Visible then + continue; + + // Set X-Position + Child.FPosition := TPointF.Create(CurrentX + Child.Margins.Left, Child.Margins.Top); + + var ChildTotalW := Child.Size.Width + Child.Margins.Left + Child.Margins.Right; + var ChildTotalH := Child.Size.Height + Child.Margins.Top + Child.Margins.Bottom; + + CurrentX := CurrentX + ChildTotalW; + ReqH := Max(ReqH, ChildTotalH); + end; + ReqW := CurrentX; + + // 3. Alignment Logic (Cross-Axis) + if FAlignment = laCenter then + begin + for Child in FChildren do + begin + if not Child.Visible then + continue; + var ChildTotalH := Child.Size.Height + Child.Margins.Top + Child.Margins.Bottom; + var OffsetY := (ReqH - ChildTotalH) * 0.5; + Child.FPosition := TPointF.Create(Child.FPosition.X, Child.Margins.Top + OffsetY); + end; + end; + end; + + // 4. Set own size + FSize.Width := ReqW + FPadding.Width; + FSize.Height := ReqH + FPadding.Height; +end; + +function TAutoFitLayout.GetInsertionIndex(const LocalP: TPointF): Integer; +var + i: Integer; + Child: TVisualNode; + Center: Single; + ContentP: TPointF; +begin + // Assumption: Append to end as default + Result := FChildren.Count; + + // Convert coords to content area + ContentP := LocalP - TPointF.Create(FPadding.Left, FPadding.Top); + + for i := 0 to FChildren.Count - 1 do + begin + Child := FChildren[i]; + if not Child.Visible then + continue; + + if FOrientation = loVertical then + begin + Center := Child.FPosition.Y + (Child.Size.Height * 0.5); + if ContentP.Y < Center then + exit(i); + end + else + begin + Center := Child.FPosition.X + (Child.Size.Width * 0.5); + if ContentP.X < Center then + exit(i); + end; + end; +end; + +end. diff --git a/Src/AST/Myc.Fmx.AstEditor.Visualizer.pas b/Src/AST/Myc.Fmx.AstEditor.Visualizer.pas index fae9a98..78589be 100644 --- a/Src/AST/Myc.Fmx.AstEditor.Visualizer.pas +++ b/Src/AST/Myc.Fmx.AstEditor.Visualizer.pas @@ -9,65 +9,79 @@ uses Myc.Data.Value, Myc.Ast.Nodes, Myc.Ast.Visitor, - Myc.Fmx.AstEditor.Workspace, - Myc.Fmx.AstEditor.Node, - Myc.Fmx.AstEditor.Handlers; + Myc.Fmx.AstEditor.Render, // Virtual Engine + Myc.Fmx.AstEditor.Node, // View Nodes + Myc.Fmx.AstEditor.Handlers, // Handlers + Myc.Fmx.AstEditor.Workspace; // Host type - // Inherits from the generic TAstVisitor + // Implementation of the Factory/Visitor for the Virtual Tree TAstVisualizer = class(TAstVisitor, IAstVisualizer) private FExprDepth: Integer; - FParentControl: TControl; - FWorkspace: TWorkspace; // Changed from TAstWorkspace to TWorkspace + FParentNode: TVisualNode; // Changed from TControl + FWorkspace: TWorkspace; + function CallAccept(const Node: IAstNode): TAstViewNode; + + // IAstVisualizer Implementation function GetExprDepth: Integer; - function GetParentControl: TControl; - function GetWorkspace: TWorkspace; // Changed signature - procedure SetExprDepth(const Value: Integer); - procedure SetParentControl(const Value: TControl); + function GetParentNode: TVisualNode; + function GetWorkspace: TWorkspace; + protected - // Visitor implementations for each AST node type. + // --- Visitor Implementations --- function VisitConstant(const Node: IConstantNode): TAstViewNode; override; function VisitIdentifier(const Node: IIdentifierNode): TAstViewNode; override; function VisitKeyword(const Node: IKeywordNode): TAstViewNode; override; - // --- List Visitors (NEW) --- + // Lists function VisitParameterList(const Node: IParameterList): TAstViewNode; override; function VisitArgumentList(const Node: IArgumentList): TAstViewNode; override; function VisitExpressionList(const Node: IExpressionList): TAstViewNode; override; function VisitRecordFieldList(const Node: IRecordFieldList): TAstViewNode; override; function VisitRecordField(const Node: IRecordFieldNode): TAstViewNode; override; + // Control Flow function VisitIfExpression(const Node: IIfExpressionNode): TAstViewNode; override; function VisitTernaryExpression(const Node: ITernaryExpressionNode): TAstViewNode; override; - function VisitLambdaExpression(const Node: ILambdaExpressionNode): TAstViewNode; override; - function VisitFunctionCall(const Node: IFunctionCallNode): TAstViewNode; override; - function VisitMacroExpansionNode(const Node: IMacroExpansionNode): TAstViewNode; override; function VisitBlockExpression(const Node: IBlockExpressionNode): TAstViewNode; override; - function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TAstViewNode; override; - function VisitAssignment(const Node: IAssignmentNode): TAstViewNode; override; - function VisitMacroDefinition(const Node: IMacroDefinitionNode): TAstViewNode; override; - function VisitQuasiquote(const Node: IQuasiquoteNode): TAstViewNode; override; - function VisitUnquote(const Node: IUnquoteNode): TAstViewNode; override; - function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TAstViewNode; override; - function VisitIndexer(const Node: IIndexerNode): TAstViewNode; override; - function VisitMemberAccess(const Node: IMemberAccessNode): TAstViewNode; override; - function VisitRecordLiteral(const Node: IRecordLiteralNode): TAstViewNode; override; - function VisitCreateSeries(const Node: ICreateSeriesNode): TAstViewNode; override; - function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TAstViewNode; override; - function VisitSeriesLength(const Node: ISeriesLengthNode): TAstViewNode; override; function VisitRecurNode(const Node: IRecurNode): TAstViewNode; override; function VisitNop(const Node: INopNode): TAstViewNode; override; + // Functions + function VisitLambdaExpression(const Node: ILambdaExpressionNode): TAstViewNode; override; + function VisitFunctionCall(const Node: IFunctionCallNode): TAstViewNode; override; + function VisitMacroExpansionNode(const Node: IMacroExpansionNode): TAstViewNode; override; + + // Declarations + function VisitVariableDeclaration(const Node: IVariableDeclarationNode): TAstViewNode; override; + function VisitAssignment(const Node: IAssignmentNode): TAstViewNode; override; + function VisitMacroDefinition(const Node: IMacroDefinitionNode): TAstViewNode; override; + + // Metaprogramming + function VisitQuasiquote(const Node: IQuasiquoteNode): TAstViewNode; override; + function VisitUnquote(const Node: IUnquoteNode): TAstViewNode; override; + function VisitUnquoteSplicing(const Node: IUnquoteSplicingNode): TAstViewNode; override; + + // Data Access + function VisitIndexer(const Node: IIndexerNode): TAstViewNode; override; + function VisitMemberAccess(const Node: IMemberAccessNode): TAstViewNode; override; + function VisitRecordLiteral(const Node: IRecordLiteralNode): TAstViewNode; override; + + // Series + function VisitCreateSeries(const Node: ICreateSeriesNode): TAstViewNode; override; + function VisitAddSeriesItem(const Node: IAddSeriesItemNode): TAstViewNode; override; + function VisitSeriesLength(const Node: ISeriesLengthNode): TAstViewNode; override; + public - constructor Create(AWorkspace: TWorkspace; AParentControl: TControl; AExprDepth: Integer); + constructor Create(AWorkspace: TWorkspace; AParentNode: TVisualNode; AExprDepth: Integer); destructor Destroy; override; - function Clone(ParentControl: TControl; ExprDepth: Integer): IAstVisualizer; + function Clone(ParentNode: TVisualNode; ExprDepth: Integer): IAstVisualizer; - property ExprDepth: Integer read GetExprDepth write SetExprDepth; - property ParentControl: TControl read GetParentControl write SetParentControl; + property ExprDepth: Integer read GetExprDepth; + property ParentNode: TVisualNode read GetParentNode; property Workspace: TWorkspace read GetWorkspace; end; @@ -75,11 +89,11 @@ implementation { TAstVisualizer } -constructor TAstVisualizer.Create(AWorkspace: TWorkspace; AParentControl: TControl; AExprDepth: Integer); +constructor TAstVisualizer.Create(AWorkspace: TWorkspace; AParentNode: TVisualNode; AExprDepth: Integer); begin inherited Create; FWorkspace := AWorkspace; - FParentControl := AParentControl; + FParentNode := AParentNode; FExprDepth := AExprDepth; end; @@ -95,21 +109,18 @@ begin if not Assigned(Node) then exit(nil); + // Dynamic dispatch via Visitor pattern dataValue := Node.Accept(Self); if dataValue.Kind = TDataValueKind.vkGeneric then - begin - Result := dataValue.AsGeneric; - end + Result := dataValue.AsGeneric else - begin Result := nil; - end; end; -function TAstVisualizer.Clone(ParentControl: TControl; ExprDepth: Integer): IAstVisualizer; +function TAstVisualizer.Clone(ParentNode: TVisualNode; ExprDepth: Integer): IAstVisualizer; begin - Result := TAstVisualizer.Create(FWorkspace, ParentControl, ExprDepth); + Result := TAstVisualizer.Create(FWorkspace, ParentNode, ExprDepth); end; function TAstVisualizer.GetExprDepth: Integer; @@ -117,9 +128,9 @@ begin Result := FExprDepth; end; -function TAstVisualizer.GetParentControl: TControl; +function TAstVisualizer.GetParentNode: TVisualNode; begin - Result := FParentControl; + Result := FParentNode; end; function TAstVisualizer.GetWorkspace: TWorkspace; @@ -127,17 +138,7 @@ begin Result := FWorkspace; end; -procedure TAstVisualizer.SetExprDepth(const Value: Integer); -begin - FExprDepth := Value; -end; - -procedure TAstVisualizer.SetParentControl(const Value: TControl); -begin - FParentControl := Value; -end; - -// --- Visitor Implementations --- +// --- Visitor Implementation Helpers --- function TAstVisualizer.VisitConstant(const Node: IConstantNode): TAstViewNode; begin @@ -154,7 +155,7 @@ begin Result := TAstViewNode.Create(Self, TKeywordNodeHandler.Create(Node)); end; -// --- List Visitors --- +// Lists function TAstVisualizer.VisitParameterList(const Node: IParameterList): TAstViewNode; begin @@ -181,7 +182,7 @@ begin Result := TAstViewNode.Create(Self, TRecordFieldHandler.Create(Node)); end; -// --- Node Visitors --- +// Control Flow function TAstVisualizer.VisitBlockExpression(const Node: IBlockExpressionNode): TAstViewNode; begin @@ -198,6 +199,18 @@ begin Result := TAstViewNode.Create(Self, TTernaryExpressionNodeHandler.Create(Node)); end; +function TAstVisualizer.VisitRecurNode(const Node: IRecurNode): TAstViewNode; +begin + Result := TAstViewNode.Create(Self, TRecurNodeHandler.Create(Node)); +end; + +function TAstVisualizer.VisitNop(const Node: INopNode): TAstViewNode; +begin + Result := TAstViewNode.Create(Self, TNopNodeHandler.Create(Node)); +end; + +// Functions + function TAstVisualizer.VisitLambdaExpression(const Node: ILambdaExpressionNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TLambdaExpressionNodeHandler.Create(Node)); @@ -213,6 +226,8 @@ begin Result := TAstViewNode.Create(Self, TMacroExpansionNodeHandler.Create(Node)); end; +// Declarations + function TAstVisualizer.VisitVariableDeclaration(const Node: IVariableDeclarationNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TVariableDeclarationNodeHandler.Create(Node)); @@ -228,6 +243,8 @@ begin Result := TAstViewNode.Create(Self, TMacroDefinitionNodeHandler.Create(Node)); end; +// Metaprogramming + function TAstVisualizer.VisitQuasiquote(const Node: IQuasiquoteNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TQuasiquoteNodeHandler.Create(Node)); @@ -243,6 +260,8 @@ begin Result := TAstViewNode.Create(Self, TUnquoteSplicingNodeHandler.Create(Node)); end; +// Data Access + function TAstVisualizer.VisitIndexer(const Node: IIndexerNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TIndexerNodeHandler.Create(Node)); @@ -258,6 +277,8 @@ begin Result := TAstViewNode.Create(Self, TRecordLiteralNodeHandler.Create(Node)); end; +// Series + function TAstVisualizer.VisitCreateSeries(const Node: ICreateSeriesNode): TAstViewNode; begin Result := TAstViewNode.Create(Self, TCreateSeriesNodeHandler.Create(Node)); @@ -273,14 +294,4 @@ begin Result := TAstViewNode.Create(Self, TSeriesLengthNodeHandler.Create(Node)); end; -function TAstVisualizer.VisitRecurNode(const Node: IRecurNode): TAstViewNode; -begin - Result := TAstViewNode.Create(Self, TRecurNodeHandler.Create(Node)); -end; - -function TAstVisualizer.VisitNop(const Node: INopNode): TAstViewNode; -begin - Result := TAstViewNode.Create(Self, TNopNodeHandler.Create(Node)); -end; - end. diff --git a/Src/AST/Myc.Fmx.AstEditor.Workspace.pas b/Src/AST/Myc.Fmx.AstEditor.Workspace.pas index d8c1595..5c0a6dc 100644 --- a/Src/AST/Myc.Fmx.AstEditor.Workspace.pas +++ b/Src/AST/Myc.Fmx.AstEditor.Workspace.pas @@ -14,146 +14,84 @@ uses FMX.Objects, FMX.Graphics, FMX.Forms, - Myc.Fmx.AstEditor.Layout; + Myc.Fmx.AstEditor.Render; type TOnPaintConnectionsEvent = procedure(ASender: TObject; ACanvas: TCanvas) of object; - TOnDragDropEvent = procedure(ASource, ATarget: TControl; AIndex: Integer) of object; + TOnDragDropEvent = procedure(ASource, ATarget: TVisualNode; AIndex: Integer) of object; - TAstWorld = class(TControl) - private - FOnPaintConnections: TOnPaintConnectionsEvent; - // VISUAL: Drop Marker State - FShowDropMarker: Boolean; - FDropP1, FDropP2: TPointF; - protected - procedure Paint; override; - procedure AfterPaint; override; - public - constructor Create(AOwner: TComponent); override; - procedure InvalidateConnections; - property OnPaintConnections: TOnPaintConnectionsEvent read FOnPaintConnections write FOnPaintConnections; - end; - - TWorkspace = class(TControl) + TWorkspace = class(TControl, IVisualHost) private const MinZoom = 0.1; MaxZoom = 5.0; ZoomStep = 0.1; private - FRootLayer: TAstWorld; + FRootNode: TVisualNode; + + FContentOffset: TPointF; + FZoom: Single; + FIsPanning: Boolean; FLastMousePos: TPointF; + FMouseOverNode: TVisualNode; + FCapturedNode: TVisualNode; FIsDraggingNode: Boolean; - FDragSource: TControl; - FDragVisual: TControl; + FDragSource: TVisualNode; + FDragVisualBitmap: TBitmap; + FDragVisualPos: TPointF; FDragOffset: TPointF; - FCurrentDropTarget: TControl; + FCurrentDropTarget: TVisualNode; FCurrentDropIndex: Integer; + FShowDropMarker: Boolean; + FDropP1, FDropP2: TPointF; + FOnPaintConnections: TOnPaintConnectionsEvent; FOnNodeDragDrop: TOnDragDropEvent; - function GetZoom: Single; - procedure SetZoom(const Value: Single); - function GetContentOffset: TPointF; - procedure SetContentOffset(const Value: TPointF); - function GetOnPaintConnections: TOnPaintConnectionsEvent; - procedure SetOnPaintConnections(const Value: TOnPaintConnectionsEvent); + // IVisualHost + procedure InvalidateRect(const R: TRectF); + function GetCanvas: TCanvas; + procedure SetZoom(const Value: Single); + procedure SetContentOffset(const Value: TPointF); + procedure SetRootNode(const Value: TVisualNode); + + procedure UpdateDropMarker(const WorldPos: TPointF); procedure StopDrag; - procedure UpdateDropMarker(const ScreenPos: TPointF); + protected - procedure Loaded; override; + procedure Paint; override; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override; procedure MouseMove(Shift: TShiftState; X, Y: Single); override; procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override; procedure MouseWheel(Shift: TShiftState; WheelDelta: Integer; var Handled: Boolean); override; + procedure Resize; override; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; + procedure BeginDragNode(ASource: TVisualNode); + procedure InvalidateConnections; + + // Moved to public for Editor access function ScreenToWorld(const APoint: TPointF): TPointF; - procedure BeginDragNode(ASource: TControl); + procedure RequestLayout; - property World: TAstWorld read FRootLayer; - property Zoom: Single read GetZoom write SetZoom; - property ContentOffset: TPointF read GetContentOffset write SetContentOffset; - property OnPaintConnections: TOnPaintConnectionsEvent read GetOnPaintConnections write SetOnPaintConnections; + property RootNode: TVisualNode read FRootNode write SetRootNode; + property Zoom: Single read FZoom write SetZoom; + property ContentOffset: TPointF read FContentOffset write SetContentOffset; + property OnPaintConnections: TOnPaintConnectionsEvent read FOnPaintConnections write FOnPaintConnections; property OnNodeDragDrop: TOnDragDropEvent read FOnNodeDragDrop write FOnNodeDragDrop; end; implementation -{ TAstWorld } - -constructor TAstWorld.Create(AOwner: TComponent); -begin - inherited; - HitTest := False; - Locked := True; - Stored := False; - ClipChildren := False; - Width := 100; - Height := 100; - FShowDropMarker := False; -end; - -procedure TAstWorld.Paint; -begin - inherited; - if (csDesigning in ComponentState) then - DrawDesignBorder; - - // Connections should be BEHIND the nodes, so Paint is the correct place. - if Assigned(FOnPaintConnections) then - FOnPaintConnections(Self, Canvas); -end; - -procedure TAstWorld.AfterPaint; -var - ScaleFactor: Single; - Radius: Single; - Thickness: Single; -begin - inherited; - - // --- DRAW DROP MARKER (IN FRONT OF NODES) --- - if FShowDropMarker then - begin - // Calculate visual sizes inversely proportional to zoom - if Scale.X > 0 then - ScaleFactor := 1 / Scale.X - else - ScaleFactor := 1; - - Thickness := 3 * ScaleFactor; - Radius := 4 * ScaleFactor; - - Canvas.Stroke.Kind := TBrushKind.Solid; - Canvas.Stroke.Color := TAlphaColors.Red; - Canvas.Stroke.Thickness := Thickness; - Canvas.Stroke.Cap := TStrokeCap.Round; - - // Draw Line - Canvas.DrawLine(FDropP1, FDropP2, 1.0); - - // Draw Circles at ends - Canvas.Fill.Kind := TBrushKind.Solid; - Canvas.Fill.Color := TAlphaColors.Red; - - Canvas.FillEllipse(TRectF.Create(FDropP1.X - Radius, FDropP1.Y - Radius, FDropP1.X + Radius, FDropP1.Y + Radius), 1.0); - Canvas.FillEllipse(TRectF.Create(FDropP2.X - Radius, FDropP2.Y - Radius, FDropP2.X + Radius, FDropP2.Y + Radius), 1.0); - end; -end; - -procedure TAstWorld.InvalidateConnections; -begin - Repaint; -end; +uses + Myc.Fmx.AstEditor.Node; { TWorkspace } @@ -162,260 +100,234 @@ begin inherited Create(AOwner); ClipChildren := True; HitTest := True; - CanFocus := True; // Enable Keyboard Input + CanFocus := True; AutoCapture := True; - FRootLayer := TAstWorld.Create(Self); - FRootLayer.Parent := Self; - FRootLayer.SetBounds(0, 0, 100, 100); - FRootLayer.Scale.Point := TPointF.Create(1, 1); + FZoom := 1.0; + FContentOffset := TPointF.Zero; + FRootNode := TVisualNode.Create(Self); end; destructor TWorkspace.Destroy; begin + FreeAndNil(FRootNode); + FreeAndNil(FDragVisualBitmap); inherited; end; -procedure TWorkspace.Loaded; +function TWorkspace.GetCanvas: TCanvas; +begin + Result := Canvas; +end; + +procedure TWorkspace.InvalidateRect(const R: TRectF); +begin + Repaint; +end; + +procedure TWorkspace.RequestLayout; +begin + if Assigned(FRootNode) then + begin + FRootNode.RecalcLayout; + Repaint; + end; +end; + +procedure TWorkspace.SetRootNode(const Value: TVisualNode); +begin + if FRootNode <> Value then + begin + if Assigned(FRootNode) then + FRootNode.Free; + FRootNode := Value; + RequestLayout; + end; +end; + +procedure TWorkspace.SetZoom(const Value: Single); +begin + if FZoom <> Value then + begin + FZoom := EnsureRange(Value, MinZoom, MaxZoom); + Repaint; + end; +end; + +procedure TWorkspace.SetContentOffset(const Value: TPointF); +begin + if FContentOffset <> Value then + begin + FContentOffset := Value; + Repaint; + end; +end; + +procedure TWorkspace.Paint; +var + State: TCanvasSaveState; + DragRect: TRectF; begin inherited; - if FRootLayer <> nil then - FRootLayer.BringToFront; + + if (csDesigning in ComponentState) then + begin + Canvas.Stroke.Kind := TBrushKind.Solid; + Canvas.Stroke.Color := TAlphaColors.Gray; + Canvas.Stroke.Dash := TStrokeDash.Dash; + Canvas.DrawRect(LocalRect, 0, 0, AllCorners, 1.0); + end; + + State := Canvas.SaveState; + try + Canvas.IntersectClipRect(LocalRect); + + Canvas.MultiplyMatrix(TMatrix.CreateScaling(FZoom, FZoom)); + Canvas.MultiplyMatrix(TMatrix.CreateTranslation(FContentOffset.X, FContentOffset.Y)); + + if Assigned(FOnPaintConnections) then + FOnPaintConnections(Self, Canvas); + + if Assigned(FRootNode) then + FRootNode.Paint(Canvas, TPointF.Zero); + + if FShowDropMarker then + begin + Canvas.Stroke.Kind := TBrushKind.Solid; + Canvas.Stroke.Color := TAlphaColors.Red; + Canvas.Stroke.Thickness := 3 / FZoom; + Canvas.Stroke.Cap := TStrokeCap.Round; + + Canvas.DrawLine(FDropP1, FDropP2, 1.0); + + Canvas.Fill.Color := TAlphaColors.Red; + var R: Single := 4 / FZoom; + Canvas.FillEllipse(TRectF.Create(FDropP1.X - R, FDropP1.Y - R, FDropP1.X + R, FDropP1.Y + R), 1.0); + Canvas.FillEllipse(TRectF.Create(FDropP2.X - R, FDropP2.Y - R, FDropP2.X + R, FDropP2.Y + R), 1.0); + end; + + if FIsDraggingNode and Assigned(FDragVisualBitmap) then + begin + DragRect := TRectF.Create(FDragVisualPos, FDragVisualBitmap.Width, FDragVisualBitmap.Height); + Canvas.DrawBitmap(FDragVisualBitmap, TRectF.Create(0, 0, FDragVisualBitmap.Width, FDragVisualBitmap.Height), DragRect, 0.7); + end; + + finally + Canvas.RestoreState(State); + end; end; function TWorkspace.ScreenToWorld(const APoint: TPointF): TPointF; -begin - Result := ScreenToLocal(APoint); - Result := FRootLayer.AbsoluteToLocal(LocalToAbsolute(Result)); -end; - -procedure TWorkspace.BeginDragNode(ASource: TControl); var - Snapshot: TBitmap; - DragImg: TImage; - MouseWorld: TPointF; - AbsPos, WorldPos: TPointF; + LocalP: TPointF; begin - if FIsDraggingNode or FIsPanning then - Exit; - - FIsDraggingNode := True; - FDragSource := ASource; - Root.Captured := Self; - - Snapshot := ASource.MakeScreenshot; - - DragImg := TImage.Create(nil); - DragImg.Parent := FRootLayer; - DragImg.Bitmap := Snapshot; - DragImg.WrapMode := TImageWrapMode.Stretch; - DragImg.HitTest := False; - DragImg.Opacity := 0.7; - DragImg.BringToFront; - - AbsPos := ASource.LocalToAbsolute(TPointF.Zero); - WorldPos := FRootLayer.AbsoluteToLocal(AbsPos); - - DragImg.SetBounds(WorldPos.X, WorldPos.Y, ASource.Width, ASource.Height); - FDragVisual := DragImg; - - MouseWorld := ScreenToWorld(Screen.MousePos); - FDragOffset := MouseWorld - WorldPos; - - ASource.Opacity := 0.4; + LocalP := ScreenToLocal(APoint); + Result := (LocalP - FContentOffset) / FZoom; end; -procedure TWorkspace.UpdateDropMarker(const ScreenPos: TPointF); -var - Obj: IControl; - TargetCtrl: TControl; - TargetLocalPos: TPointF; - IsHorizontal: Boolean; - InsertAfter: Boolean; - PTL, PBR: TPointF; - P1, P2: TPointF; - SourceParent: TControl; - TargetContainer: TAutoFitControl; +procedure TWorkspace.Resize; begin - FRootLayer.FShowDropMarker := False; - FCurrentDropTarget := nil; - FCurrentDropIndex := -1; - - if FDragSource = nil then - Exit; - - if not (FDragSource.Parent is TControl) then - Exit; - SourceParent := TControl(FDragSource.Parent); - - // 1. Find Drop Target - Obj := ObjectAtPoint(ScreenPos); - if (Obj = nil) or not (Obj.GetObject is TControl) then - Exit; - - TargetCtrl := TControl(Obj.GetObject); - - // 2. Walk up hierarchy - while (TargetCtrl <> nil) and (TargetCtrl.Parent <> SourceParent) do - begin - TargetCtrl := TargetCtrl.ParentControl; - if TargetCtrl = FRootLayer then - Exit; - end; - - if TargetCtrl = nil then - Exit; - if TargetCtrl = FDragSource then - Exit; - - FCurrentDropTarget := TargetCtrl; - - // 3. Determine Geometry using TAutoFitControl info - TargetLocalPos := TargetCtrl.AbsoluteToLocal(ScreenPos); - - IsHorizontal := True; // Default fallback - - if SourceParent is TAutoFitControl then - begin - TargetContainer := TAutoFitControl(SourceParent); - - if TargetContainer.Orientation = TLayoutOrientation.loHorizontal then - IsHorizontal := True - else - IsHorizontal := False; - end; - - // Split logic - if IsHorizontal then - InsertAfter := TargetLocalPos.X > (TargetCtrl.Width / 2) - else - InsertAfter := TargetLocalPos.Y > (TargetCtrl.Height / 2); - - // 4. Calculate Index - if InsertAfter then - FCurrentDropIndex := TargetCtrl.Index + 1 - else - FCurrentDropIndex := TargetCtrl.Index; - - // 5. Calculate Marker Visuals - var AbsTL := TargetCtrl.LocalToAbsolute(TPointF.Zero); - var AbsBR := TargetCtrl.LocalToAbsolute(TPointF.Create(TargetCtrl.Width, TargetCtrl.Height)); - - PTL := FRootLayer.AbsoluteToLocal(AbsTL); - PBR := FRootLayer.AbsoluteToLocal(AbsBR); - - if IsHorizontal then - begin - // Vertical Line - var XPos := PTL.X; - if InsertAfter then - XPos := PBR.X; - - if InsertAfter then - XPos := XPos + 2 - else - XPos := XPos - 2; - - P1 := TPointF.Create(XPos, PTL.Y); - P2 := TPointF.Create(XPos, PBR.Y); - end - else - begin - // Horizontal Line - var YPos := PTL.Y; - if InsertAfter then - YPos := PBR.Y; - - if InsertAfter then - YPos := YPos + 2 - else - YPos := YPos - 2; - - P1 := TPointF.Create(PTL.X, YPos); - P2 := TPointF.Create(PBR.X, YPos); - end; - - FRootLayer.FDropP1 := P1; - FRootLayer.FDropP2 := P2; - FRootLayer.FShowDropMarker := True; -end; - -procedure TWorkspace.StopDrag; -begin - if not FIsDraggingNode then - Exit; - - if Assigned(FDragVisual) then - begin - FDragVisual.Parent := nil; - FDragVisual.Free; - FDragVisual := nil; - end; - - if Assigned(FDragSource) then - FDragSource.Opacity := 1.0; - - FRootLayer.FShowDropMarker := False; - FRootLayer.Repaint; - - if Assigned(FOnNodeDragDrop) and Assigned(FCurrentDropTarget) and (FCurrentDropIndex >= 0) then - FOnNodeDragDrop(FDragSource, FCurrentDropTarget, FCurrentDropIndex); - - FIsDraggingNode := False; - FDragSource := nil; - FCurrentDropTarget := nil; - Root.Captured := nil; + inherited; + Repaint; end; procedure TWorkspace.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); +var + WorldP: TPointF; + Hit: TVisualNode; begin inherited; - // Capture Keyboard Focus if CanFocus then SetFocus; - if not FIsDraggingNode and (Button in [TMouseButton.mbLeft, TMouseButton.mbMiddle]) then + WorldP := ScreenToWorld(LocalToScreen(TPointF.Create(X, Y))); + + if (Button in [TMouseButton.mbLeft, TMouseButton.mbMiddle]) and (ssCtrl in Shift) then begin FIsPanning := True; FLastMousePos := TPointF.Create(X, Y); Root.Captured := Self; + Exit; + end; + + if Assigned(FRootNode) then + begin + Hit := FRootNode.HitTest(WorldP); + + if Assigned(Hit) then + begin + FCapturedNode := Hit; + var NodeLocal := Hit.AbsoluteToLocal(WorldP); + Hit.MouseDown(Button, Shift, NodeLocal.X, NodeLocal.Y); + end + else if Button = TMouseButton.mbLeft then + begin + FIsPanning := True; + FLastMousePos := TPointF.Create(X, Y); + Root.Captured := Self; + end; end; end; procedure TWorkspace.MouseMove(Shift: TShiftState; X, Y: Single); var - LCurrentPos: TPointF; - LDelta: TPointF; - LWorldPos: TPointF; + WorldP: TPointF; + LocalP: TPointF; + Hit: TVisualNode; + Delta: TPointF; begin inherited; + LocalP := TPointF.Create(X, Y); + WorldP := ScreenToWorld(LocalToScreen(LocalP)); if FIsDraggingNode then begin - if Assigned(FDragVisual) then - begin - LWorldPos := ScreenToWorld(Screen.MousePos); - FDragVisual.Position.Point := LWorldPos - FDragOffset; - end; - - UpdateDropMarker(Screen.MousePos); - - FRootLayer.Repaint; + FDragVisualPos := WorldP - FDragOffset; + UpdateDropMarker(WorldP); + Repaint; end else if FIsPanning then begin - LCurrentPos := TPointF.Create(X, Y); - LDelta := LCurrentPos - FLastMousePos; + Delta := LocalP - FLastMousePos; + FContentOffset := FContentOffset + Delta; + FLastMousePos := LocalP; + Repaint; + end + else + begin + if Assigned(FCapturedNode) then + begin + var NodeLocal := FCapturedNode.AbsoluteToLocal(WorldP); + FCapturedNode.MouseMove(Shift, NodeLocal.X, NodeLocal.Y); + end + else if Assigned(FRootNode) then + begin + Hit := FRootNode.HitTest(WorldP); + if Hit <> FMouseOverNode then + begin + if Assigned(FMouseOverNode) then + FMouseOverNode.MouseLeave; + FMouseOverNode := Hit; + if Assigned(FMouseOverNode) then + FMouseOverNode.MouseEnter; + end; - FRootLayer.Position.Point := FRootLayer.Position.Point + LDelta; - - FLastMousePos := LCurrentPos; + if Assigned(FMouseOverNode) then + begin + var NodeLocal := FMouseOverNode.AbsoluteToLocal(WorldP); + FMouseOverNode.MouseMove(Shift, NodeLocal.X, NodeLocal.Y); + end; + end; end; end; procedure TWorkspace.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single); +var + WorldP: TPointF; begin inherited; + WorldP := ScreenToWorld(LocalToScreen(TPointF.Create(X, Y))); + if FIsDraggingNode then begin StopDrag; @@ -424,68 +336,192 @@ begin begin FIsPanning := False; Root.Captured := nil; + end + else if Assigned(FCapturedNode) then + begin + var NodeLocal := FCapturedNode.AbsoluteToLocal(WorldP); + FCapturedNode.MouseUp(Button, Shift, NodeLocal.X, NodeLocal.Y); + FCapturedNode := nil; end; end; procedure TWorkspace.MouseWheel(Shift: TShiftState; WheelDelta: Integer; var Handled: Boolean); var - LOldZoom, LNewZoom: Single; - LScaleRatio: Single; - LMousePosLocal: TPointF; - LOffset: TPointF; + OldZoom: Single; + LocalP, OffsetLocal: TPointF; begin - LOldZoom := Zoom; + OldZoom := FZoom; if WheelDelta > 0 then - LNewZoom := LOldZoom + ZoomStep + SetZoom(FZoom + ZoomStep) else - LNewZoom := LOldZoom - ZoomStep; + SetZoom(FZoom - ZoomStep); - LNewZoom := EnsureRange(LNewZoom, MinZoom, MaxZoom); - - if not SameValue(LNewZoom, LOldZoom, TEpsilon.Vector) then + if not SameValue(OldZoom, FZoom, TEpsilon.Position) then begin - LMousePosLocal := ScreenToLocal(Screen.MousePos); - LOffset := LMousePosLocal - FRootLayer.Position.Point; - LScaleRatio := LNewZoom / LOldZoom; - - FRootLayer.Position.Point := LMousePosLocal - (LOffset * LScaleRatio); - SetZoom(LNewZoom); + LocalP := ScreenToLocal(Screen.MousePos); + OffsetLocal := LocalP - FContentOffset; + FContentOffset := LocalP - (OffsetLocal * (FZoom / OldZoom)); + Repaint; end; Handled := True; - - if not Handled then - inherited; end; -function TWorkspace.GetZoom: Single; +procedure TWorkspace.BeginDragNode(ASource: TVisualNode); +var + Bitmap: TBitmap; + Scale: Single; begin - Result := FRootLayer.Scale.X; + if FIsDraggingNode or FIsPanning then + Exit; + if ASource = nil then + Exit; + + FIsDraggingNode := True; + FDragSource := ASource; + Root.Captured := Self; + + Scale := Scene.GetSceneScale; + Bitmap := TBitmap.Create(Round(ASource.Size.Width * Scale), Round(ASource.Size.Height * Scale)); + Bitmap.BitmapScale := Scale; + + if Bitmap.Canvas.BeginScene then + try + Bitmap.Canvas.Clear(0); + ASource.Paint(Bitmap.Canvas, TPointF.Zero); + finally + Bitmap.Canvas.EndScene; + end; + + FDragVisualBitmap := Bitmap; + + var MouseWorld := ScreenToWorld(Screen.MousePos); + var NodeWorld := ASource.GetAbsolutePosition; + + FDragOffset := MouseWorld - NodeWorld; + FDragVisualPos := NodeWorld; + + ASource.Opacity := 0.4; + ASource.RequestLayout; end; -procedure TWorkspace.SetZoom(const Value: Single); +procedure TWorkspace.UpdateDropMarker(const WorldPos: TPointF); +var + Hit: TVisualNode; + TargetContainer: TAutoFitLayout; + IsHorizontal: Boolean; + InsertIndex: Integer; + Child: TVisualNode; + P1, P2: TPointF; + AbsP: TPointF; begin - FRootLayer.Scale.Point := TPointF.Create(Value, Value); + FShowDropMarker := False; + FCurrentDropTarget := nil; + FCurrentDropIndex := -1; + + if FDragSource = nil then + Exit; + + Hit := FRootNode.HitTest(WorldPos); + if Hit = nil then + Exit; + + if (Hit is TAutoFitLayout) then + TargetContainer := TAutoFitLayout(Hit) + else if (Hit.Parent is TAutoFitLayout) then + TargetContainer := TAutoFitLayout(Hit.Parent) + else + Exit; + + if TargetContainer = FDragSource then + Exit; + + FCurrentDropTarget := TargetContainer; + IsHorizontal := TargetContainer.Orientation = loHorizontal; + + var TargetLocal := TargetContainer.AbsoluteToLocal(WorldPos); + InsertIndex := TargetContainer.GetInsertionIndex(TargetLocal); + FCurrentDropIndex := InsertIndex; + + if InsertIndex < TargetContainer.GetChildCount then + begin + Child := TargetContainer.GetChild(InsertIndex); + AbsP := Child.GetAbsolutePosition; + if IsHorizontal then + begin + P1 := AbsP; + P2 := AbsP + TPointF.Create(0, Child.Size.Height); + end + else + begin + P1 := AbsP; + P2 := AbsP + TPointF.Create(Child.Size.Width, 0); + end; + end + else if TargetContainer.GetChildCount > 0 then + begin + Child := TargetContainer.GetChild(TargetContainer.GetChildCount - 1); + AbsP := Child.GetAbsolutePosition; + if IsHorizontal then + begin + P1 := AbsP + TPointF.Create(Child.Size.Width + Child.Margins.Right, 0); + P2 := P1 + TPointF.Create(0, Child.Size.Height); + end + else + begin + P1 := AbsP + TPointF.Create(0, Child.Size.Height + Child.Margins.Bottom); + P2 := P1 + TPointF.Create(Child.Size.Width, 0); + end; + end + else + begin + AbsP := TargetContainer.GetAbsolutePosition + TPointF.Create(TargetContainer.Padding.Left, TargetContainer.Padding.Top); + if IsHorizontal then + begin + P1 := AbsP; + P2 := AbsP + TPointF.Create(0, 20); + end + else + begin + P1 := AbsP; + P2 := AbsP + TPointF.Create(20, 0); + end; + end; + + FDropP1 := P1; + FDropP2 := P2; + FShowDropMarker := True; end; -function TWorkspace.GetContentOffset: TPointF; +procedure TWorkspace.StopDrag; begin - Result := FRootLayer.Position.Point; + if not FIsDraggingNode then + Exit; + + FreeAndNil(FDragVisualBitmap); + + if Assigned(FDragSource) then + begin + FDragSource.Opacity := 1.0; + + if Assigned(FOnNodeDragDrop) and Assigned(FCurrentDropTarget) and (FCurrentDropIndex >= 0) then + begin + FOnNodeDragDrop(FDragSource, FCurrentDropTarget, FCurrentDropIndex); + end; + end; + + FShowDropMarker := False; + FIsDraggingNode := False; + FDragSource := nil; + FCurrentDropTarget := nil; + Root.Captured := nil; + + Repaint; end; -procedure TWorkspace.SetContentOffset(const Value: TPointF); +procedure TWorkspace.InvalidateConnections; begin - FRootLayer.Position.Point := Value; -end; - -function TWorkspace.GetOnPaintConnections: TOnPaintConnectionsEvent; -begin - Result := FRootLayer.OnPaintConnections; -end; - -procedure TWorkspace.SetOnPaintConnections(const Value: TOnPaintConnectionsEvent); -begin - FRootLayer.OnPaintConnections := Value; + Repaint; end; end. diff --git a/Src/AST/Myc.Fmx.AstEditor.pas b/Src/AST/Myc.Fmx.AstEditor.pas index f9ec82a..f11234a 100644 --- a/Src/AST/Myc.Fmx.AstEditor.pas +++ b/Src/AST/Myc.Fmx.AstEditor.pas @@ -21,9 +21,10 @@ uses Myc.Ast.Scope, Myc.Ast.Environment, Myc.Ast.Refactoring.Remove, + Myc.Fmx.AstEditor.Render, Myc.Fmx.AstEditor.Node, - Myc.Fmx.AstEditor.Layout, - Myc.Fmx.AstEditor.Workspace; + Myc.Fmx.AstEditor.Workspace, + Myc.Fmx.AstEditor.Visualizer; type TAstEditor = class(TControl) @@ -49,37 +50,29 @@ type FRootViewNode: TAstViewNode; FFocusedNode: TAstViewNode; - // State Tracking FCurrentAst: IAstNode; - // Undo/Redo Stacks FUndoStack: TUndoStack; FRedoStack: TUndoStack; FIsUndoing: Boolean; - // Events FOnPaintConnections: TOnPaintConnectionsEvent; FOnWorkspaceMouseDown: TMouseEvent; - procedure CollectNodes(Parent: TControl); + procedure CollectNodes(Parent: TVisualNode); procedure ClearVisuals; procedure ApplyErrors(const Log: ICompilerLog); procedure ApplyTypes(const TypedAst: IAstNode); - procedure RootResized(Sender: TObject); - // Internal Event Wiring - procedure HandleNodeDragDrop(ASource, ATarget: TControl; AIndex: Integer); + procedure HandleNodeDragDrop(ASource, ATarget: TVisualNode; AIndex: Integer); procedure HandleKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char; Shift: TShiftState); procedure HandleWorkspacePaintConnections(ASender: TObject; ACanvas: TCanvas); procedure HandleWorkspaceMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single); - procedure HandleNodeMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single); procedure CommitSnapshot; - // --- Navigation Helper --- procedure EnsureVisible(Node: TAstViewNode); - function GetParentNode(StartNode: TAstViewNode): TAstViewNode; - function GetFirstChild(StartNode: TAstViewNode): TAstViewNode; + function GetNextVerticalNeighbor(StartNode: TAstViewNode): TAstViewNode; function GetPrevVerticalNeighbor(StartNode: TAstViewNode): TAstViewNode; function GetNextLinearNode(StartNode: TAstViewNode): TAstViewNode; @@ -88,18 +81,16 @@ type procedure SetOnPaintConnections(const Value: TOnPaintConnectionsEvent); protected - procedure Paint; override; // For design-time border + procedure Paint; override; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; - // Must be called after creation to link the AST Environment procedure Init(const AEnv: TAstEnvironment); procedure ValidateAndShow; - // AClearHistory=False ensures stacks are kept (e.g. after internal edits) procedure SetRoot(const AstNode: IAstNode; AClearHistory: Boolean = True); procedure Undo; @@ -123,7 +114,6 @@ type property Enabled; property Opacity; - // Expose events relevant to the outside world property OnPaintConnections: TOnPaintConnectionsEvent read FOnPaintConnections write SetOnPaintConnections; property OnMouseDown: TMouseEvent read FOnWorkspaceMouseDown write FOnWorkspaceMouseDown; end; @@ -131,8 +121,7 @@ type implementation uses - Myc.Data.Value, - Myc.Fmx.AstEditor.Visualizer; + Myc.Data.Value; { TAstEditor } @@ -143,14 +132,12 @@ begin Height := 300; ClipChildren := True; - // Create Internal Workspace FWorkspace := TWorkspace.Create(Self); FWorkspace.Parent := Self; FWorkspace.Align := TAlignLayout.Client; FWorkspace.Stored := False; FWorkspace.Locked := True; - // Wire Internal Events FWorkspace.OnNodeDragDrop := HandleNodeDragDrop; FWorkspace.OnKeyDown := HandleKeyDown; FWorkspace.OnPaintConnections := HandleWorkspacePaintConnections; @@ -205,21 +192,18 @@ begin if FWorkspace.CanFocus then FWorkspace.SetFocus; + var WorldP := FWorkspace.ScreenToWorld(FWorkspace.LocalToScreen(TPointF.Create(X, Y))); + var Hit := FWorkspace.RootNode.HitTest(WorldP); + + if (Button = TMouseButton.mbLeft) and (Hit is TAstViewNode) then + begin + SetFocusedNode(TAstViewNode(Hit)); + end; + if Assigned(FOnWorkspaceMouseDown) then FOnWorkspaceMouseDown(Self, Button, Shift, X, Y); end; -procedure TAstEditor.HandleNodeMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single); -begin - if FWorkspace.CanFocus then - FWorkspace.SetFocus; - - if (Button = TMouseButton.mbLeft) and (Sender is TAstViewNode) then - begin - SetFocusedNode(TAstViewNode(Sender)); - end; -end; - procedure TAstEditor.CommitSnapshot; begin if Assigned(FCurrentAst) and (not FIsUndoing) then @@ -242,7 +226,7 @@ begin FRedoStack.Push(FCurrentAst); prevAst := FUndoStack.Pop; - SetRoot(prevAst); // Default Clear=True, but guarded by FIsUndoing + SetRoot(prevAst); finally FIsUndoing := False; end; @@ -277,56 +261,49 @@ begin Result := FRedoStack.Count > 0; end; -procedure TAstEditor.HandleNodeDragDrop(ASource, ATarget: TControl; AIndex: Integer); +procedure TAstEditor.HandleNodeDragDrop(ASource, ATarget: TVisualNode; AIndex: Integer); var - SourceParent: TControl; + SourceView, TargetView: TAstViewNode; ContainerOwner: TAstViewNode; Reorderable: IReorderable; - SourceIdx, TargetIdx: Integer; + SourceIdx: Integer; NewAst: IAstNode; begin if (ASource = nil) or (AIndex < 0) then exit; if not (ASource is TAstViewNode) then exit; - - if not (ASource.Parent is TControl) then + if not (ATarget is TAstViewNode) then exit; - SourceParent := TControl(ASource.Parent); - ContainerOwner := nil; + SourceView := TAstViewNode(ASource); + TargetView := TAstViewNode(ATarget); + ContainerOwner := TargetView; - if (SourceParent is TAstViewNode) then + if not Supports(ContainerOwner.Handler, IReorderable, Reorderable) then + exit; + + if Reorderable.CanDrag(SourceView) and (SourceView.Parent = TargetView) then begin - ContainerOwner := TAstViewNode(SourceParent); - if not Supports(ContainerOwner.Handler, IReorderable, Reorderable) then - ContainerOwner := nil; - end; - - if (ContainerOwner = nil) and (SourceParent.Parent is TAstViewNode) then - begin - ContainerOwner := TAstViewNode(SourceParent.Parent); - if not Supports(ContainerOwner.Handler, IReorderable, Reorderable) then - ContainerOwner := nil; - end; - - if (ContainerOwner <> nil) and (Reorderable <> nil) then - begin - if Reorderable.CanDrag(ASource) then + // Find current index of SourceView in Target + SourceIdx := -1; + for var i := 0 to TargetView.GetChildCount - 1 do begin - SourceIdx := ASource.Index; - TargetIdx := AIndex; - - if SourceIdx <> TargetIdx then + if TargetView.GetChild(i) = SourceView then begin - CommitSnapshot; - Reorderable.MoveChild(SourceIdx, TargetIdx); - NewAst := FRootViewNode.CreateAst; - - // IMPORTANT: Pass False to preserve the undo stack we just updated - SetRoot(NewAst, False); + SourceIdx := i; + Break; end; end; + + if SourceIdx >= 0 then + begin + CommitSnapshot; + Reorderable.MoveChild(SourceIdx, AIndex); + + NewAst := FRootViewNode.CreateAst; + SetRoot(NewAst, False); + end; end; end; @@ -334,7 +311,7 @@ procedure TAstEditor.HandleKeyDown(Sender: TObject; var Key: Word; var KeyChar: var NewRoot: IAstNode; begin - // Undo / Redo Handling + // Undo / Redo if (ssCtrl in Shift) then begin if (Key = vkZ) then @@ -361,7 +338,7 @@ begin end; end; - // Delete Handling + // Delete if (Key = vkDelete) then begin if Assigned(FFocusedNode) and Assigned(FFocusedNode.Node) and Assigned(FCurrentAst) then @@ -369,7 +346,6 @@ begin CommitSnapshot; if TAstNodeRemover.TryRemove(FCurrentAst, FFocusedNode.Node, NewRoot) then begin - // IMPORTANT: Pass False to preserve the undo stack we just updated SetRoot(NewRoot, False); end; end; @@ -391,7 +367,6 @@ var begin FCurrentAst := AstNode; - // Only clear if explicitly requested AND not currently performing an undo/redo if AClearHistory and (not FIsUndoing) then begin FUndoStack.Clear; @@ -399,55 +374,47 @@ begin end; FFocusedNode := nil; + FWorkspace.RootNode := nil; - FWorkspace.World.DeleteChildren; if Assigned(FRootViewNode) then - FRootViewNode.OnResized := nil; - FRootViewNode := nil; + FRootViewNode := nil; if not Assigned(AstNode) then exit; - Visualizer := TAstVisualizer.Create(FWorkspace, FWorkspace.World, 0); + Visualizer := TAstVisualizer.Create(FWorkspace, nil, 0); FRootViewNode := Visualizer.CallAccept(AstNode); if Assigned(FRootViewNode) then begin - FWorkspace.World.Size := FRootViewNode.Size; - FRootViewNode.OnResized := RootResized; - FRootViewNode.Position.Point := TPointF.Create(50, 50); - end; - - if Assigned(FRootViewNode) then + FWorkspace.RootNode := FRootViewNode; + FRootViewNode.Position := TPointF.Create(50, 50); ValidateAndShow; + end; end; -procedure TAstEditor.CollectNodes(Parent: TControl); +procedure TAstEditor.CollectNodes(Parent: TVisualNode); var i: Integer; - child: TControl; + child: TVisualNode; viewNode: TAstViewNode; begin - for i := 0 to Parent.ChildrenCount - 1 do + for i := 0 to Parent.GetChildCount - 1 do begin - if Parent.Children[i] is TControl then + child := Parent.GetChild(i); + + if child is TAstViewNode then begin - child := TControl(Parent.Children[i]); + viewNode := TAstViewNode(child); - if child is TAstViewNode then + if Assigned(viewNode.Node) and Assigned(viewNode.Node.Identity) then begin - viewNode := TAstViewNode(child); - viewNode.OnMouseDown := HandleNodeMouseDown; - - if Assigned(viewNode.Node) and Assigned(viewNode.Node.Identity) then - begin - FNodeMap.AddOrSetValue(viewNode.Node.Identity, viewNode); - end; + FNodeMap.AddOrSetValue(viewNode.Node.Identity, viewNode); end; - - if child.ChildrenCount > 0 then - CollectNodes(child); end; + + if child.GetChildCount > 0 then + CollectNodes(child); end; end; @@ -495,11 +462,6 @@ begin end; end; -procedure TAstEditor.RootResized(Sender: TObject); -begin - FWorkspace.World.Size := FRootViewNode.Size; -end; - procedure TAstEditor.ValidateAndShow; var logicalAst: IAstNode; @@ -510,7 +472,7 @@ begin logicalAst := FRootViewNode.CreateAst; FNodeMap.Clear; - CollectNodes(FWorkspace.World); + CollectNodes(FWorkspace.RootNode); ClearVisuals; @@ -527,6 +489,9 @@ begin var compiled := FEnv.Link(specAst.AsLambdaExpression, log); ApplyErrors(log); + + FWorkspace.RootNode.RecalcLayout; + FWorkspace.InvalidateConnections; except on E: ECompilationFailed do begin @@ -537,13 +502,9 @@ begin end; end; - FWorkspace.World.Repaint; + FWorkspace.RequestLayout; end; -// ================================================================================================= -// == NAVIGATION IMPLEMENTATION -// ================================================================================================= - procedure TAstEditor.SetFocusedNode(Node: TAstViewNode); begin if FFocusedNode = Node then @@ -565,338 +526,96 @@ procedure TAstEditor.EnsureVisible(Node: TAstViewNode); const cMargin = 40; var - NodeRect, ViewRect: TRectF; - Delta: TPointF; + NodeRect: TRectF; begin if (Node = nil) or (FWorkspace = nil) then Exit; NodeRect := Node.AbsoluteRect; - ViewRect := FWorkspace.AbsoluteRect; - ViewRect.Inflate(-cMargin, -cMargin); - Delta := TPointF.Zero; + var ScreenCenter := TRectF.Create(0, 0, FWorkspace.Width, FWorkspace.Height).CenterPoint; + var NodeCenterWorld := NodeRect.CenterPoint; - if NodeRect.Width > ViewRect.Width then - Delta.X := ViewRect.CenterPoint.X - NodeRect.CenterPoint.X - else if NodeRect.Left < ViewRect.Left then - Delta.X := ViewRect.Left - NodeRect.Left - else if NodeRect.Right > ViewRect.Right then - Delta.X := ViewRect.Right - NodeRect.Right; - - if NodeRect.Height > ViewRect.Height then - Delta.Y := ViewRect.CenterPoint.Y - NodeRect.CenterPoint.Y - else if NodeRect.Top < ViewRect.Top then - Delta.Y := ViewRect.Top - NodeRect.Top - else if NodeRect.Bottom > ViewRect.Bottom then - Delta.Y := ViewRect.Bottom - NodeRect.Bottom; - - if not (SameValue(Delta.X, 0, TEpsilon.Position) and SameValue(Delta.Y, 0, TEpsilon.Position)) then - begin - FWorkspace.ContentOffset := FWorkspace.ContentOffset + Delta; - end; -end; - -function TAstEditor.GetParentNode(StartNode: TAstViewNode): TAstViewNode; -var - curr: TControl; -begin - Result := nil; - if StartNode = nil then - Exit; - - curr := StartNode.ParentControl; - while (curr <> nil) and (curr <> FWorkspace.World) do - begin - if curr is TAstViewNode then - Exit(TAstViewNode(curr)); - curr := curr.ParentControl; - end; -end; - -function TAstEditor.GetFirstChild(StartNode: TAstViewNode): TAstViewNode; - function FindFirst(Parent: TControl): TAstViewNode; - var - i: Integer; - begin - Result := nil; - for i := 0 to Parent.ChildrenCount - 1 do - begin - if Parent.Children[i] is TAstViewNode then - Exit(TAstViewNode(Parent.Children[i])) - else if (Parent.Children[i] is TControl) and (TControl(Parent.Children[i]).ChildrenCount > 0) then - begin - Result := FindFirst(TControl(Parent.Children[i])); - if Result <> nil then - Exit; - end; - end; - end; -begin - Result := FindFirst(StartNode); -end; - -function FindFirstViewNode(Container: TControl): TAstViewNode; -var - i: Integer; - Child: TControl; -begin - Result := nil; - if Container is TAstViewNode then - Exit(TAstViewNode(Container)); - - for i := 0 to Container.ChildrenCount - 1 do - begin - if Container.Children[i] is TControl then - begin - Child := TControl(Container.Children[i]); - if Child.Visible then - begin - Result := FindFirstViewNode(Child); - if Result <> nil then - Exit; - end; - end; - end; -end; - -function FindLastViewNode(Container: TControl): TAstViewNode; -var - i: Integer; - Child: TControl; -begin - Result := nil; - if Container is TAstViewNode then - exit(TAstViewNode(Container)); - - for i := Container.ChildrenCount - 1 downto 0 do - begin - if Container.Children[i] is TControl then - begin - Child := TControl(Container.Children[i]); - if Child.Visible then - begin - var Found := FindLastViewNode(Child); - if Found <> nil then - Exit(Found); - end; - end; - end; -end; - -function FindNextSiblingInList(Parent: TControl; AfterControl: TControl): TAstViewNode; -var - i, StartIndex: Integer; - Candidate: TControl; -begin - Result := nil; - StartIndex := -1; - for i := 0 to Parent.ChildrenCount - 1 do - if Parent.Children[i] = AfterControl then - begin - StartIndex := i; - Break; - end; - - if StartIndex >= 0 then - begin - for i := StartIndex + 1 to Parent.ChildrenCount - 1 do - begin - if Parent.Children[i] is TControl then - begin - Candidate := TControl(Parent.Children[i]); - if Candidate.Visible then - begin - Result := FindFirstViewNode(Candidate); - if Result <> nil then - Exit; - end; - end; - end; - end; -end; - -function FindPrevSiblingInList(Parent: TControl; BeforeControl: TControl): TAstViewNode; -var - i, StartIndex: Integer; - Candidate: TControl; -begin - Result := nil; - StartIndex := -1; - for i := 0 to Parent.ChildrenCount - 1 do - if Parent.Children[i] = BeforeControl then - begin - StartIndex := i; - Break; - end; - - if StartIndex >= 0 then - begin - for i := StartIndex - 1 downto 0 do - begin - if Parent.Children[i] is TControl then - begin - Candidate := TControl(Parent.Children[i]); - if Candidate.Visible then - begin - Result := FindLastViewNode(Candidate); - if Result <> nil then - Exit; - end; - end; - end; - end; -end; - -function TAstEditor.GetNextVerticalNeighbor(StartNode: TAstViewNode): TAstViewNode; -var - Current, Parent: TControl; -begin - Result := nil; - Current := StartNode; - - while (Current <> nil) and (Current <> FWorkspace.World) do - begin - Parent := Current.ParentControl; - if Parent = nil then - Break; - - if (Parent is TAutoFitControl) and (TAutoFitControl(Parent).Orientation = TLayoutOrientation.loVertical) then - begin - Result := FindNextSiblingInList(Parent, Current); - if Result <> nil then - Exit; - end; - - Current := Parent; - end; - - if Result = nil then - Result := GetNextLinearNode(StartNode) -end; - -function TAstEditor.GetPrevVerticalNeighbor(StartNode: TAstViewNode): TAstViewNode; -var - Current, Parent: TControl; -begin - Result := nil; - Current := StartNode; - - while (Current <> nil) and (Current <> FWorkspace.World) do - begin - Parent := Current.ParentControl; - if Parent = nil then - Break; - - if (Parent is TAutoFitControl) and (TAutoFitControl(Parent).Orientation = TLayoutOrientation.loVertical) then - begin - Result := FindPrevSiblingInList(Parent, Current); - if Result <> nil then - Exit; - end; - - Current := Parent; - end; - - if Result = nil then - Result := GetPrevLinearNode(StartNode) + FWorkspace.ContentOffset := ScreenCenter - (NodeCenterWorld * FWorkspace.Zoom); end; function TAstEditor.GetNextLinearNode(StartNode: TAstViewNode): TAstViewNode; -var - CurrentControl, ParentControl: TControl; - i, StartIndex: Integer; - Candidate: TControl; -begin - Result := GetFirstChild(StartNode); - if Result <> nil then - Exit; - - CurrentControl := StartNode; - while (CurrentControl <> nil) and (CurrentControl <> FWorkspace.World) do + function FindFirst(Node: TVisualNode): TAstViewNode; begin - ParentControl := CurrentControl.ParentControl; - if ParentControl = nil then - Break; - - StartIndex := -1; - for i := 0 to ParentControl.ChildrenCount - 1 do - if ParentControl.Children[i] = CurrentControl then - begin - StartIndex := i; - Break; - end; - - if StartIndex >= 0 then + if Node is TAstViewNode then + Exit(TAstViewNode(Node)); + for var i := 0 to Node.GetChildCount - 1 do begin - for i := StartIndex + 1 to ParentControl.ChildrenCount - 1 do - begin - if ParentControl.Children[i] is TControl then - begin - Candidate := TControl(ParentControl.Children[i]); - if Candidate.Visible then - begin - Result := FindFirstViewNode(Candidate); - if Result <> nil then - Exit; - end; - end; - end; + Result := FindFirst(Node.GetChild(i)); + if Result <> nil then + Exit; end; - - CurrentControl := ParentControl; + Result := nil; end; - Result := nil; + function FindNext(Node: TVisualNode): TAstViewNode; + var + Parent: TVisualNode; + Idx: Integer; + begin + Result := nil; + if Node.GetChildCount > 0 then + begin + Result := FindFirst(Node.GetChild(0)); + if Result <> nil then + Exit; + end; + + Parent := Node.Parent; + while Parent <> nil do + begin + Idx := -1; + for var k := 0 to Parent.GetChildCount - 1 do + if Parent.GetChild(k) = Node then + begin + Idx := k; + break; + end; + + if (Idx >= 0) and (Idx < Parent.GetChildCount - 1) then + begin + for var k := Idx + 1 to Parent.GetChildCount - 1 do + begin + Result := FindFirst(Parent.GetChild(k)); + if Result <> nil then + Exit; + end; + end; + + Node := Parent; + Parent := Node.Parent; + end; + end; +begin + for var i := 0 to StartNode.GetChildCount - 1 do + begin + Result := FindFirst(StartNode.GetChild(i)); + if Result <> nil then + Exit; + end; + Result := FindNext(StartNode); end; function TAstEditor.GetPrevLinearNode(StartNode: TAstViewNode): TAstViewNode; -var - CurrentControl, ParentControl: TControl; - i, StartIndex: Integer; - Candidate: TControl; begin - CurrentControl := StartNode; - while (CurrentControl <> nil) and (CurrentControl <> FWorkspace.World) do - begin - ParentControl := CurrentControl.ParentControl; - if ParentControl = nil then - Break; - - StartIndex := -1; - for i := 0 to ParentControl.ChildrenCount - 1 do - if ParentControl.Children[i] = CurrentControl then - begin - StartIndex := i; - Break; - end; - - if StartIndex >= 0 then - begin - for i := StartIndex - 1 downto 0 do - begin - if ParentControl.Children[i] is TControl then - begin - Candidate := TControl(ParentControl.Children[i]); - if Candidate.Visible then - begin - Result := FindLastViewNode(Candidate); - if Result <> nil then - Exit; - end; - end; - end; - end; - - if ParentControl is TAstViewNode then - Exit(TAstViewNode(ParentControl)); - - CurrentControl := ParentControl; - end; - Result := nil; end; +function TAstEditor.GetNextVerticalNeighbor(StartNode: TAstViewNode): TAstViewNode; +begin + Result := GetNextLinearNode(StartNode); +end; + +function TAstEditor.GetPrevVerticalNeighbor(StartNode: TAstViewNode): TAstViewNode; +begin + Result := GetPrevLinearNode(StartNode); +end; + procedure TAstEditor.Navigate(Key: Word; Shift: TShiftState); var Current: TAstViewNode; @@ -923,19 +642,14 @@ begin Exit; end; - if Key = vkEscape then - begin - Target := GetParentNode(Current); - if Target <> nil then - SetFocusedNode(Target); - Exit; - end; - case Key of vkLeft: Target := GetPrevLinearNode(Current); vkRight: Target := GetNextLinearNode(Current); vkUp: Target := GetPrevVerticalNeighbor(Current); vkDown: Target := GetNextVerticalNeighbor(Current); + vkEscape: + if Current.Parent is TAstViewNode then + Target := TAstViewNode(Current.Parent); end; if Target <> nil then