diff --git a/.gitignore b/.gitignore
index fc5bc1e6..6204ff29 100644
--- a/.gitignore
+++ b/.gitignore
@@ -47,4 +47,8 @@
*.Patch
*.#00
*.pch
+/Modules/DelphiFMX/pyd
+/Modules/DelphiVCL/pyd
+/Modules/DelphiFMX/dcu
+/Modules/DelphiVCL/dcu
/Tests/TestInsightSettings.ini
diff --git a/Demos/FMX/Android/CameraPreviewDemo/AppEnvironment.pas b/Demos/FMX/Android/CameraPreviewDemo/AppEnvironment.pas
new file mode 100644
index 00000000..6aadc653
--- /dev/null
+++ b/Demos/FMX/Android/CameraPreviewDemo/AppEnvironment.pas
@@ -0,0 +1,165 @@
+(**************************************************************************)
+(* *)
+(* Module: Unit 'AppEnvironment' Copyright (c) 2021 *)
+(* *)
+(* Lucas Moura Belo - lmbelo *)
+(* lucas.belo@live.com *)
+(* Brazil *)
+(* *)
+(* PyScripter *)
+(* e-mail: pyscripter@gmail.com *)
+(* *)
+(* Project pages: https://github.com/Embarcadero/python4delphi *)
+(* https://github.com/pyscripter/python4delphi *)
+(**************************************************************************)
+(* Functionality: App environment set up *)
+(* *)
+(* *)
+(**************************************************************************)
+(* This source code is distributed with no WARRANTY, for no reason or use.*)
+(* Everyone is allowed to use and change this code free for his own tasks *)
+(* and projects, as long as this header and its copyright text is intact. *)
+(* For changed versions of this code, which are public distributed the *)
+(* following additional conditions have to be fullfilled: *)
+(* 1) The header has to contain a comment on the change and the author of *)
+(* it. *)
+(* 2) A copy of the changed source has to be sent to the above E-Mail *)
+(* address or my then valid address, if this is possible to the *)
+(* author. *)
+(* The second condition has the target to maintain an up to date central *)
+(* version of the component. If this condition is not acceptable for *)
+(* confidential or legal reasons, everyone is free to derive a component *)
+(* or to generate a diff file to my or other original sources. *)
+(**************************************************************************)
+unit AppEnvironment;
+
+interface
+
+uses
+ System.Classes, System.SysUtils, System.Threading, System.Zip, PythonEngine;
+
+type
+ IProgressNotifier = interface
+ ['{7A2D1743-D4D8-4093-B372-04D814536708}']
+ procedure Start(const ADescription, AFirstAction: string; const ATotal: Int64);
+ procedure Update(const ACurrentAction: string; const AProgress: Int64);
+ procedure Stop();
+ end;
+
+ TAppEnvInit = reference to procedure(const AInitialized: boolean; const ALastErrorMsg: string);
+
+ TAppEnvironment = class
+ private
+ FInitialized: boolean;
+ FProgressNotifier: IProgressNotifier;
+ procedure OnZipProgressEvent(Sender: TObject; FileName: string; Header: TZipHeader; Position: Int64);
+ procedure DoInitializeEnvironmentAsync(const APythonEngine: TPythonEngine;
+ const ACheckPyLib: boolean = true);
+ public
+ constructor Create(const AProgressNotifier: IProgressNotifier);
+
+ procedure InitializeEnvironmentAsync(const APythonEngine: TPythonEngine;
+ const ACheckPyLib: boolean; const AAppEnvInit: TAppEnvInit);
+
+ property Initialized: boolean read FInitialized;
+ end;
+
+implementation
+
+uses
+ System.IOUtils, FMX.Dialogs, PythonLoad;
+
+{ TAppEnvironment }
+
+constructor TAppEnvironment.Create(const AProgressNotifier: IProgressNotifier);
+begin
+ Assert(Assigned(AProgressNotifier), '"AProgressNotifier" undefined');
+ FInitialized := false;
+ FProgressNotifier := AProgressNotifier;
+end;
+
+procedure TAppEnvironment.DoInitializeEnvironmentAsync(const APythonEngine: TPythonEngine;
+ const ACheckPyLib: boolean = true);
+begin
+ try
+ //Lock user iteractions
+ TThread.Synchronize(nil, procedure() begin
+ FProgressNotifier.Start('Searching for Python installation', String.Empty, 0);
+ end);
+
+ Sleep(200);
+
+ //Python distibution unzip
+ TPythonLoad.Extract(
+ procedure(const AFolderExists: boolean; var AReplaceFiles: boolean) begin
+ if not AFolderExists then begin
+ TThread.Synchronize(nil, procedure() begin
+ FProgressNotifier.Start('Installing Python', String.Empty, 0);
+ end);
+ end;
+ AReplaceFiles := false;
+ end, OnZipProgressEvent);
+
+ //Configure Python for Android
+ TThread.Synchronize(nil, procedure() begin
+ FProgressNotifier.Start('Configuring Python for Android', String.Empty, 3);
+ FProgressNotifier.Update('Check for files', 1)
+ end);
+
+ TPythonLoad.Configure(APythonEngine);
+ Sleep(1000);
+
+ //Load python library
+ TThread.Synchronize(nil, procedure() begin
+ FProgressNotifier.Start('Loading Python', String.Empty, 3);
+ FProgressNotifier.Update('Loading and mapping library', 2)
+ end);
+
+ TThread.Synchronize(nil, procedure() begin
+ APythonEngine.LoadDll();
+ end);
+ Sleep(1000);
+
+ //All done notification
+ TThread.Synchronize(nil, procedure() begin
+ FProgressNotifier.Start('Loading environment', String.Empty, 3);
+ FProgressNotifier.Update('All ready', 3)
+ end);
+ Sleep(1000);
+ finally
+ TThread.Synchronize(nil, procedure() begin
+ FProgressNotifier.Stop();
+ end);
+ end;
+end;
+
+procedure TAppEnvironment.InitializeEnvironmentAsync(
+ const APythonEngine: TPythonEngine; const ACheckPyLib: boolean;
+ const AAppEnvInit: TAppEnvInit);
+begin
+ TTask.Run(
+ procedure() begin
+ try
+ DoInitializeEnvironmentAsync(APythonEngine, ACheckPyLib);
+ FInitialized := true;
+ if Assigned(AAppEnvInit) then
+ AAppEnvInit(true, String.Empty);
+ except
+ on E: Exception do begin
+ if Assigned(AAppEnvInit) then
+ AAppEnvInit(false, E.Message);
+ end;
+ end;
+ end);
+end;
+
+procedure TAppEnvironment.OnZipProgressEvent(Sender: TObject; FileName: string;
+ Header: TZipHeader; Position: Int64);
+begin
+ TThread.Queue(nil, procedure() begin
+ FProgressNotifier.Start('Extracting files', String.Empty, Header.UncompressedSize);
+ FProgressNotifier.Update(TPath.GetFileName(FileName), Position);
+ end);
+end;
+
+end.
diff --git a/Demos/FMX/Android/CameraPreviewDemo/CameraPreviewDemo.dpr b/Demos/FMX/Android/CameraPreviewDemo/CameraPreviewDemo.dpr
new file mode 100644
index 00000000..b8dcc955
--- /dev/null
+++ b/Demos/FMX/Android/CameraPreviewDemo/CameraPreviewDemo.dpr
@@ -0,0 +1,17 @@
+program CameraPreviewDemo;
+
+uses
+ System.StartUpCopy,
+ FMX.Forms,
+ MainForm in 'MainForm.pas' {PyMainForm},
+ PythonLoad in 'PythonLoad.pas',
+ ProgressFrame in 'ProgressFrame.pas' {ProgressViewFrame: TFrame},
+ AppEnvironment in 'AppEnvironment.pas';
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TPyMainForm, PyMainForm);
+ Application.Run;
+end.
diff --git a/Demos/FMX/Android/CameraPreviewDemo/CameraPreviewDemo.dproj b/Demos/FMX/Android/CameraPreviewDemo/CameraPreviewDemo.dproj
new file mode 100644
index 00000000..b3d5e73d
--- /dev/null
+++ b/Demos/FMX/Android/CameraPreviewDemo/CameraPreviewDemo.dproj
@@ -0,0 +1,1841 @@
+
+
+ {652D9A8E-1625-4F00-9B29-2E3D31D7A186}
+ 19.2
+ FMX
+ True
+ Debug
+ Android64
+ 37915
+ Application
+ CameraPreviewDemo.dpr
+
+
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Cfg_1
+ true
+ true
+
+
+ true
+ Cfg_1
+ true
+ true
+
+
+ true
+ Cfg_1
+ true
+ true
+
+
+ true
+ Cfg_1
+ true
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Cfg_2
+ true
+ true
+
+
+ true
+ Cfg_2
+ true
+ true
+
+
+ true
+ Cfg_2
+ true
+ true
+
+
+ true
+ Cfg_2
+ true
+ true
+
+
+ .\$(Platform)\$(Config)
+ .\$(Platform)\$(Config)
+ false
+ false
+ false
+ false
+ false
+ System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ $(BDS)\bin\delphi_PROJECTICON.ico
+ $(BDS)\bin\delphi_PROJECTICNS.icns
+ CameraPreviewDemo
+
+
+ DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;bindcompfmx;fmx;FireDACIBDriver;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
+ package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=
+ Debug
+ true
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png
+ android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar
+
+
+ DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;bindcompfmx;fmx;FireDACIBDriver;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
+ package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=
+ Debug
+ true
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png
+ android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar
+
+
+ DBXSqliteDriver;RESTComponents;fmxase;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;bindcompfmx;fmx;FireDACIBDriver;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
+ CFBundleName=$(MSBuildProjectName);CFBundleDevelopmentRegion=en;CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleInfoDictionaryVersion=7.1;CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;LSRequiresIPhoneOS=true;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);UIDeviceFamily=iPhone & iPad;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user;NSLocationAlwaysAndWhenInUseUsageDescription=The reason for accessing the location information of the user;UIBackgroundModes=;NSContactsUsageDescription=The reason for accessing the contacts;NSPhotoLibraryUsageDescription=The reason for accessing the photo library;NSPhotoLibraryAddUsageDescription=The reason for adding to the photo library;NSCameraUsageDescription=The reason for accessing the camera;NSFaceIDUsageDescription=The reason for accessing the face id;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSSiriUsageDescription=The reason for accessing Siri;ITSAppUsesNonExemptEncryption=false;NSBluetoothAlwaysUsageDescription=The reason for accessing bluetooth;NSBluetoothPeripheralUsageDescription=The reason for accessing bluetooth peripherals;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSMotionUsageDescription=The reason for accessing the accelerometer;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers
+ iPhoneAndiPad
+ true
+ Debug
+ $(MSBuildProjectName)
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_1024x1024.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_180x180.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_2x.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImageDark_2x.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_3x.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImageDark_3x.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_120x120.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_SettingIcon_58x58.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_SettingIcon_87x87.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_NotificationIcon_40x40.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_NotificationIcon_60x60.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_167x167.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImage_2x.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageDark_2x.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_SettingIcon_58x58.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_NotificationIcon_40x40.png
+
+
+ DBXSqliteDriver;RESTComponents;fmxase;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;bindcompfmx;fmx;FireDACIBDriver;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
+ CFBundleName=$(MSBuildProjectName);CFBundleDevelopmentRegion=en;CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleInfoDictionaryVersion=7.1;CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;LSRequiresIPhoneOS=true;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);UIDeviceFamily=iPhone & iPad;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user;NSLocationAlwaysAndWhenInUseUsageDescription=The reason for accessing the location information of the user;UIBackgroundModes=;NSContactsUsageDescription=The reason for accessing the contacts;NSPhotoLibraryUsageDescription=The reason for accessing the photo library;NSPhotoLibraryAddUsageDescription=The reason for adding to the photo library;NSCameraUsageDescription=The reason for accessing the camera;NSFaceIDUsageDescription=The reason for accessing the face id;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSSiriUsageDescription=The reason for accessing Siri;ITSAppUsesNonExemptEncryption=false;NSBluetoothAlwaysUsageDescription=The reason for accessing bluetooth;NSBluetoothPeripheralUsageDescription=The reason for accessing bluetooth peripherals;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSMotionUsageDescription=The reason for accessing the accelerometer;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers
+ iPhoneAndiPad
+ true
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_1024x1024.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_180x180.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_2x.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImageDark_2x.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_3x.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImageDark_3x.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_120x120.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_SettingIcon_58x58.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_SettingIcon_87x87.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_NotificationIcon_40x40.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_NotificationIcon_60x60.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_167x167.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImage_2x.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageDark_2x.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_SettingIcon_58x58.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_NotificationIcon_40x40.png
+ 10.0
+
+
+ DBXSqliteDriver;RESTComponents;fmxase;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;FireDACMSSQLDriver;bindcompfmx;DBXOracleDriver;inetdb;fmx;FireDACIBDriver;fmxdae;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;DBXMySQLDriver;CloudService;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FireDACPgDriver;FireDACASADriver;FireDACTDataDriver;soaprtl;DbxCommonDriver;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;FireDACDSDriver;rtl;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;bindcomp;DBXInformixDriver;IndyIPClient;dbxcds;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage)
+ CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSCameraUsageDescription=The reason for accessing the camera;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSMotionUsageDescription=The reason for accessing the accelerometer;NSDesktopFolderUsageDescription=The reason for accessing the Desktop folder;NSDocumentsFolderUsageDescription=The reason for accessing the Documents folder;NSDownloadsFolderUsageDescription=The reason for accessing the Downloads folder;NSNetworkVolumesUsageDescription=The reason for accessing files on a network volume;NSRemovableVolumesUsageDescription=The reason for accessing files on a removable volume;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers
+ Debug
+ true
+
+
+ DBXSqliteDriver;RESTComponents;fmxase;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;bindcompvclsmp;emsclientfiredac;tethering;svnui;DataSnapFireDAC;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;svn;DBXOracleDriver;inetdb;emsedge;fmx;FireDACIBDriver;fmxdae;vcledge;FireDACDBXDriver;dbexpress;IndyCore;vclx;Python;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;vcl;IndyIPServer;DBXSybaseASEDriver;IndySystem;FireDACDb2Driver;bindcompvclwinx;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;soaprtl;DbxCommonDriver;PythonVcl;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;FireDACDSDriver;rtl;emsserverresource;DbxClientDriver;PythonFmx;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage)
+ Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
+ Debug
+ true
+ CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
+ 1033
+ $(BDS)\bin\default_app.manifest
+ $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
+ $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
+
+
+ DBXSqliteDriver;RESTComponents;fmxase;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;bindcompvclsmp;emsclientfiredac;tethering;DataSnapFireDAC;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;DBXOracleDriver;inetdb;emsedge;fmx;FireDACIBDriver;fmxdae;vcledge;FireDACDBXDriver;dbexpress;IndyCore;vclx;Python;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;vcl;IndyIPServer;DBXSybaseASEDriver;IndySystem;FireDACDb2Driver;bindcompvclwinx;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;soaprtl;DbxCommonDriver;PythonVcl;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;FireDACDSDriver;rtl;emsserverresource;DbxClientDriver;PythonFmx;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage)
+ Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)
+ Debug
+ true
+ CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
+ 1033
+ $(BDS)\bin\default_app.manifest
+ $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
+ $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
+
+
+ DEBUG;$(DCC_Define)
+ true
+ false
+ true
+ true
+ true
+
+
+
+ 1
+ #000000
+
+
+
+ 1
+ #000000
+ C:\Users\User\Documents\Embarcadero\Studio\Projects\Embarcadero\python4delphi\Source\;$(Debugger_DebugSourcePath)
+
+
+ false
+ true
+ PerMonitorV2
+
+
+ true
+ PerMonitorV2
+
+
+ false
+ RELEASE;$(DCC_Define)
+ 0
+ 0
+
+
+
+ 1
+ #000000
+
+
+
+ 1
+ #000000
+
+
+ true
+ PerMonitorV2
+
+
+ true
+ PerMonitorV2
+
+
+
+ MainSource
+
+
+
+ fmx
+
+
+
+
+ fmx
+ TFrame
+
+
+
+ Cfg_2
+ Base
+
+
+ Base
+
+
+ Cfg_1
+ Base
+
+
+
+ Delphi.Personality.12
+ Application
+
+
+
+ CameraPreviewDemo.dpr
+
+
+ Microsoft Office 2000 Sample Automation Server Wrapper Components
+ Microsoft Office XP Sample Automation Server Wrapper Components
+
+
+
+
+
+ .\assets\internal
+ build.zip
+ false
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ libCameraPreviewDemo.so
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ CameraPreviewDemo.exe
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ library\lib\arm64-v8a\
+ libpython3.9d.so
+ true
+
+
+
+
+ libCameraPreviewDemo.so
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ classes.dex
+ true
+
+
+
+
+ styles.xml
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ true
+
+
+
+
+ library\lib\armeabi-v7a\
+ libpython3.9.so
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ .\assets\internal
+ build.zip
+ false
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ .\assets\internal
+ build.zip
+ false
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ classes.dex
+ true
+
+
+
+
+ classes.dex
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ styles.xml
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ library\lib\armeabi-v7a\
+ libpython3.9d.so
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ styles.xml
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ .\assets\internal
+ build.zip
+ false
+
+
+
+
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ classes.dex
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ library\lib\arm64-v8a\
+ libpython3.9.so
+ true
+
+
+
+
+ libCameraPreviewDemo.so
+ true
+
+
+
+
+ true
+
+
+
+
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ libCameraPreviewDemo.so
+ true
+
+
+
+
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ styles.xml
+ true
+
+
+
+
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ 0
+
+
+
+
+ classes
+ 1
+
+
+ classes
+ 1
+
+
+
+
+ res\xml
+ 1
+
+
+ res\xml
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+
+
+ library\lib\armeabi
+ 1
+
+
+ library\lib\armeabi
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+
+
+ library\lib\mips
+ 1
+
+
+ library\lib\mips
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+ library\lib\arm64-v8a
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+
+
+ res\drawable
+ 1
+
+
+ res\drawable
+ 1
+
+
+
+
+ res\values
+ 1
+
+
+ res\values
+ 1
+
+
+
+
+ res\values-v21
+ 1
+
+
+ res\values-v21
+ 1
+
+
+
+
+ res\values
+ 1
+
+
+ res\values
+ 1
+
+
+
+
+ res\drawable
+ 1
+
+
+ res\drawable
+ 1
+
+
+
+
+ res\drawable-xxhdpi
+ 1
+
+
+ res\drawable-xxhdpi
+ 1
+
+
+
+
+ res\drawable-xxxhdpi
+ 1
+
+
+ res\drawable-xxxhdpi
+ 1
+
+
+
+
+ res\drawable-ldpi
+ 1
+
+
+ res\drawable-ldpi
+ 1
+
+
+
+
+ res\drawable-mdpi
+ 1
+
+
+ res\drawable-mdpi
+ 1
+
+
+
+
+ res\drawable-hdpi
+ 1
+
+
+ res\drawable-hdpi
+ 1
+
+
+
+
+ res\drawable-xhdpi
+ 1
+
+
+ res\drawable-xhdpi
+ 1
+
+
+
+
+ res\drawable-mdpi
+ 1
+
+
+ res\drawable-mdpi
+ 1
+
+
+
+
+ res\drawable-hdpi
+ 1
+
+
+ res\drawable-hdpi
+ 1
+
+
+
+
+ res\drawable-xhdpi
+ 1
+
+
+ res\drawable-xhdpi
+ 1
+
+
+
+
+ res\drawable-xxhdpi
+ 1
+
+
+ res\drawable-xxhdpi
+ 1
+
+
+
+
+ res\drawable-xxxhdpi
+ 1
+
+
+ res\drawable-xxxhdpi
+ 1
+
+
+
+
+ res\drawable-small
+ 1
+
+
+ res\drawable-small
+ 1
+
+
+
+
+ res\drawable-normal
+ 1
+
+
+ res\drawable-normal
+ 1
+
+
+
+
+ res\drawable-large
+ 1
+
+
+ res\drawable-large
+ 1
+
+
+
+
+ res\drawable-xlarge
+ 1
+
+
+ res\drawable-xlarge
+ 1
+
+
+
+
+ res\values
+ 1
+
+
+ res\values
+ 1
+
+
+
+
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ 0
+
+
+
+
+ Contents\MacOS
+ 1
+ .framework
+
+
+ Contents\MacOS
+ 1
+ .framework
+
+
+ 0
+
+
+
+
+ 1
+ .dylib
+
+
+ 1
+ .dylib
+
+
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ 0
+ .dll;.bpl
+
+
+
+
+ 1
+ .dylib
+
+
+ 1
+ .dylib
+
+
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ 0
+ .bpl
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ Contents\Resources\StartUp\
+ 0
+
+
+ Contents\Resources\StartUp\
+ 0
+
+
+ 0
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
+ 1
+
+
+ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
+ 1
+
+
+
+
+ ..\
+ 1
+
+
+ ..\
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen
+ 64
+
+
+ ..\$(PROJECTNAME).launchscreen
+ 64
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
+ 1
+
+
+
+
+ ..\
+ 1
+
+
+ ..\
+ 1
+
+
+
+
+ Contents
+ 1
+
+
+ Contents
+ 1
+
+
+
+
+ Contents\Resources
+ 1
+
+
+ Contents\Resources
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+ library\lib\arm64-v8a
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ 0
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+
+
+ Assets
+ 1
+
+
+ Assets
+ 1
+
+
+
+
+ Assets
+ 1
+
+
+ Assets
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+
+
+ 12
+
+
+
+
+
+ call $(PROJECTDIR)\..\PyDistFinder\bin\pydistfinder.exe UNZIP $(PROJECTDIR) arm true false
+ False
+
+ False
+
+ False
+
+
+ call $(PROJECTDIR)\..\PyDistFinder\bin\pydistfinder.exe UNZIP $(PROJECTDIR) aarch64 true fals
+ False
+
+ False
+
+ False
+
+
+ call $(PROJECTDIR)\..\PyDistFinder\bin\pydistfinder.exe UNZIP $(PROJECTDIR) arm false false
+ False
+
+ False
+
+ False
+
+
+ call $(PROJECTDIR)\..\PyDistFinder\bin\pydistfinder.exe UNZIP $(PROJECTDIR) aarch64 false false
+ False
+
+ False
+
+ False
+
+
diff --git a/Demos/FMX/Android/CameraPreviewDemo/MainForm.fmx b/Demos/FMX/Android/CameraPreviewDemo/MainForm.fmx
new file mode 100644
index 00000000..30e06388
--- /dev/null
+++ b/Demos/FMX/Android/CameraPreviewDemo/MainForm.fmx
@@ -0,0 +1,434 @@
+object PyMainForm: TPyMainForm
+ Left = 0
+ Top = 0
+ Caption = 'MainForm'
+ ClientHeight = 743
+ ClientWidth = 349
+ FormFactor.Width = 320
+ FormFactor.Height = 480
+ FormFactor.Devices = [Desktop]
+ OnCreate = FormCreate
+ OnDestroy = FormDestroy
+ DesignerMasterStyle = 3
+ object spInputOutput: TSplitter
+ Align = Top
+ Cursor = crVSplit
+ MinSize = 20.000000000000000000
+ Position.Y = 265.000000000000000000
+ Size.Width = 349.000000000000000000
+ Size.Height = 8.000000000000000000
+ Size.PlatformDefault = False
+ end
+ object tbTop: TToolBar
+ Size.Width = 349.000000000000000000
+ Size.Height = 48.000000000000000000
+ Size.PlatformDefault = False
+ TabOrder = 0
+ object Label1: TLabel
+ Align = Client
+ Size.Width = 349.000000000000000000
+ Size.Height = 48.000000000000000000
+ Size.PlatformDefault = False
+ StyleLookup = 'toollabel'
+ TextSettings.HorzAlign = Center
+ Text = 'Python4Delphi - Camera Preview'
+ TabOrder = 1
+ end
+ end
+ object tbBottom: TToolBar
+ Align = Bottom
+ Position.Y = 695.000000000000000000
+ Size.Width = 349.000000000000000000
+ Size.Height = 48.000000000000000000
+ Size.PlatformDefault = False
+ TabOrder = 1
+ object btnRun: TButton
+ Action = actRun
+ Align = Center
+ Enabled = True
+ ImageIndex = -1
+ Size.Width = 48.000000000000000000
+ Size.Height = 48.000000000000000000
+ Size.PlatformDefault = False
+ StyleLookup = 'playtoolbutton'
+ TabOrder = 0
+ end
+ end
+ object Layout1: TLayout
+ Align = Top
+ Position.Y = 48.000000000000000000
+ Size.Width = 349.000000000000000000
+ Size.Height = 217.000000000000000000
+ Size.PlatformDefault = False
+ TabOrder = 5
+ object mmOutput: TMemo
+ Touch.InteractiveGestures = [Pan, LongTap, DoubleTap]
+ DataDetectorTypes = []
+ ReadOnly = True
+ Align = Client
+ Margins.Left = 10.000000000000000000
+ Margins.Top = 10.000000000000000000
+ Margins.Right = 10.000000000000000000
+ Size.Width = 329.000000000000000000
+ Size.Height = 207.000000000000000000
+ Size.PlatformDefault = False
+ TabOrder = 1
+ Viewport.Width = 321.000000000000000000
+ Viewport.Height = 199.000000000000000000
+ end
+ object Layout2: TLayout
+ Anchors = [akRight, akBottom]
+ Position.X = 284.000000000000000000
+ Position.Y = 163.000000000000000000
+ TabOrder = 6
+ object Circle1: TCircle
+ Align = Contents
+ Fill.Color = claGainsboro
+ Size.Width = 50.000000000000000000
+ Size.Height = 50.000000000000000000
+ Size.PlatformDefault = False
+ Stroke.Thickness = 0.000000000000000000
+ end
+ object btnClearOutput: TButton
+ Action = actClearOutput
+ Align = Client
+ Enabled = True
+ ImageIndex = -1
+ Size.Width = 48.000000000000000000
+ Size.Height = 48.000000000000000000
+ Size.PlatformDefault = False
+ StyleLookup = 'trashtoolbutton'
+ TabOrder = 3
+ end
+ end
+ end
+ object Layout3: TLayout
+ Align = Client
+ Size.Width = 349.000000000000000000
+ Size.Height = 422.000000000000000000
+ Size.PlatformDefault = False
+ TabOrder = 6
+ object mmInput: TMemo
+ Touch.InteractiveGestures = [Pan, LongTap, DoubleTap]
+ DataDetectorTypes = []
+ Lines.Strings = (
+ '#The fmx module is exposed by PythonModule1 component'
+ ''
+ '#Module classes'
+
+ 'from fmx import (Form, Button, TabControl, TabItem, Layout, Labe' +
+ 'l,'
+
+ ' SpeedButton, CameraComponent, ActionList, Actio' +
+ 'n, Image)'
+ ''
+ '#Module variables'
+ 'from fmx import MainForm, CameraComp, ImageBuff'
+ ''
+ '#Module methods'
+
+ 'from fmx import AskDelphiForCameraPermission, AskDelphiToShowFra' +
+ 'me'
+ ''
+ 'class CameraPreview(Form):'
+ ' def OnActListUpdate(self, action, handled):'
+ ' if CameraComp.Value.Active:'
+ ' self.btnCamera.Action = self.actStop'
+ ' else:'
+ ' self.btnCamera.Action = self.actStart'
+ ''
+ ' def OnActListExec(self, action, handled):'
+ ' #Ask for Delphi if the camera permission has been granted'
+ ' if not AskDelphiForCameraPermission(self):'
+ ' handled = True'
+ ''
+ ' def OnActStartExec(self, sender):'
+ ' print("Starting camera.")'
+ ' CameraComp.Value.Active = True'
+ ''
+ ' def OnActStopExec(self, sender):'
+ ' print("Stopping camera.")'
+ ' CameraComp.Value.Active = False'
+ ''
+ ' def OnActFrontExec(self, sender):'
+ ' print("Switching to front camera.")'
+ ' CameraComp.Value.Kind = '#39'FrontCamera'#39
+ ''
+ ' def OnActBackExec(self, sender):'
+ ' print("Switching to back camera.")'
+ ' CameraComp.Value.Kind = '#39'BackCamera'#39
+ ''
+ ' def OnCamSampleBufferReady(self, sender, time):'
+ ' self.tbPages.TabIndex = 1'
+ ' AskDelphiToShowFrame(self)'
+ ''
+ ' def __init__(self, owner):'
+ ' self.Caption = '#39'Camera previewer'#39
+ ''
+ ' #Creates the camera component'
+ ' #Links directly to the Delphi'#39's "FPyCamera" variable'
+ ' CameraComp.Value = CameraComponent(MainForm)'
+
+ ' CameraComp.Value.OnSampleBufferReady = self.OnCamSampleBuffe' +
+ 'rReady'
+ ''
+ ' #ActionList'
+ ' self.actList = ActionList(self)'
+ ' self.actList.OnUpdate = self.OnActListUpdate'
+ ' self.actList.OnExecute = self.OnActListExec'
+ ''
+ ' #Start camera action'
+ ' self.actStart = Action(self)'
+ ' self.actStart.ActionList = self.actList'
+ ' self.actStart.Text = '#39'Start'#39
+ ' self.actStart.OnExecute = self.OnActStartExec'
+ ''
+ ' #Stop camera action'
+ ' self.actStop = Action(self)'
+ ' self.actStop.ActionList = self.actList'
+ ' self.actStop.Text = '#39'Stop'#39
+ ' self.actStop.OnExecute = self.OnActStopExec'
+ ''
+ ' #Set front camera option'
+ ' self.actFront = Action(self)'
+ ' self.actFront.ActionList = self.actList'
+ ' self.actFront.Text = '#39'Front'#39
+ ' self.actFront.OnExecute = self.OnActFrontExec'
+ ''
+ ' #Set back camera option'
+ ' self.actBack = Action(self)'
+ ' self.actBack.ActionList = self.actList'
+ ' self.actBack.Text = '#39'Back'#39
+ ' self.actBack.OnExecute = self.OnActBackExec'
+ ''
+ ' #Camera button'
+ ' self.btnCamera = Button(self)'
+ ' self.btnCamera.Parent = self'
+ ' self.btnCamera.Align = "Bottom"'
+ ' self.btnCamera.Margins.Left = 10'
+ ' self.btnCamera.Margins.Top = 10'
+ ' self.btnCamera.Margins.Right = 10'
+ ' self.btnCamera.Margins.Bottom = 10'
+ ' self.btnCamera.Action = self.actStart'
+ ''
+ ' #Stop camera button'
+ ' #self.btnStop = Button(self)'
+ ' #self.btnStop.Parent = self'
+ ' #self.btnStop.Align = "Top"'
+ ' #self.btnStop.Margins.Left = 10'
+ ' #self.btnStop.Margins.Top = 10'
+ ' #self.btnStop.Margins.Right = 10'
+ ' #self.btnStop.Margins.Bottom = 10'
+ ' #self.btnStop.Text = '#39'Stop Camera'#39
+ ' #self.btnStop.Action = self.actStop'
+ ''
+ ' #Start camera button'
+ ' #self.btnStart = Button(self)'
+ ' #self.btnStart.Parent = self'
+ ' #self.btnStart.Align = "Top"'
+ ' #self.btnStart.Margins.Left = 10'
+ ' #self.btnStart.Margins.Top = 10'
+ ' #self.btnStart.Margins.Right = 10'
+ ' #self.btnStart.Text = '#39'Start Camera'#39
+ ' #self.btnStart.Action = self.actStart'
+ ''
+ ' #TTabControl component'
+ ' self.tbPages = TabControl(self)'
+ ' self.tbPages.Parent = self'
+ ' self.tbPages.Align = "Client"'
+ ' self.tbPages.Margins.Top = 10'
+ ' self.tbPages.StyleLookup = "tabcontrolstyle"'
+ ' self.tbPages.TabPosition = "Top"'
+ ''
+ ' #TTabItem component - Settings'
+ ' pageSettings = self.tbPages.Add(TabItem)'
+ ' pageSettings.Text = '#39'SETTINGS'#39
+ ''
+ ' #Settings container'
+ ' self.ltSettings = Layout(pageSettings)'
+ ' self.ltSettings.Parent = pageSettings'
+ ' self.ltSettings.Align = "Client"'
+ ''
+ ' #Camera type container'
+ ' self.ltCamType = Layout(self.ltSettings)'
+ ' self.ltCamType.Parent = self.ltSettings'
+ ' self.ltCamType.Align = "Top"'
+ ' self.ltCamType.Height = 120'
+ ''
+ ' #Camera type label'
+ ' self.lbCamType = Label(self.ltCamType)'
+ ' self.lbCamType.Parent = self.ltCamType'
+ ' self.lbCamType.Align = "Top"'
+ ' self.lbCamType.Margins.Left = 5'
+ ' self.lbCamType.Margins.Top = 10'
+ ' self.lbCamType.Margins.Right = 5'
+ ' self.lbCamType.Text = '#39'Camera type:'#39
+ ''
+ ' #Camera type selection container'
+ ' self.ltCamTypeSel = Layout(self.ltCamType)'
+ ' self.ltCamTypeSel.Parent = self.ltCamType'
+ ' self.ltCamTypeSel.Align = "Client"'
+ ' self.ltCamTypeSel.Height = 72'
+ ' self.ltCamTypeSel.Margins.Top = 5'
+ ' self.ltCamTypeSel.Margins.Left = 5'
+ ' self.ltCamTypeSel.Margins.Right = 5'
+ ''
+ ' #Camera type selection segment'
+ ' self.ltCamTypeSeg = Layout(self.ltCamTypeSel)'
+ ' self.ltCamTypeSeg.Parent = self.ltCamTypeSel'
+ ' self.ltCamTypeSeg.Align = "Center"'
+ ' self.ltCamTypeSeg.Height = 72'
+ ' self.ltCamTypeSeg.Width = self.ltCamTypeSel.Width'
+ ''
+ ' #Front camera button'
+ ' self.btnFrontCam = SpeedButton(self.ltCamTypeSeg)'
+ ' self.btnFrontCam.Parent = self.ltCamTypeSeg'
+ ' self.btnFrontCam.Align = "None"'
+ ' self.btnFrontCam.Width = (self.ltCamTypeSeg.Width / 2)'
+ ' self.btnFrontCam.Position.X = 0'
+ ' self.btnFrontCam.GroupName = "CameraTypeSegment"'
+ ' self.btnFrontCam.StyleLookup = "buttonstyle"'
+ ' self.btnFrontCam.Action = self.actFront'
+ ''
+ ' #Rear camera button'
+ ' self.btnBackCam = SpeedButton(self.ltCamTypeSeg)'
+ ' self.btnBackCam.Parent = self.ltCamTypeSeg'
+ ' self.btnBackCam.Align = "None"'
+ ' self.btnBackCam.Width = (self.ltCamTypeSeg.Width / 2)'
+ ' self.btnBackCam.Position.X = self.btnFrontCam.Width'
+ ' self.btnBackCam.GroupName = "CameraTypeSegment"'
+ ' self.btnBackCam.StyleLookup = "buttonstyle"'
+ ' self.btnBackCam.Action = self.actBack'
+ ''
+ ' #TTabItem component - Camera Preview'
+ ' self.pageCameraPreview = self.tbPages.Add(TabItem)'
+ ' self.pageCameraPreview.Text = '#39'CAMERA PREVIEW'#39
+ ''
+ ' #Image buff preview'
+ ' ImageBuff.Value = Image(self.pageCameraPreview)'
+ ' ImageBuff.Value.Parent = self.pageCameraPreview'
+ ' ImageBuff.Value.Align = "Client"'
+ ''
+ 'if __name__ == '#39'__main__'#39':'
+ ' f = CameraPreview(MainForm)'
+ ' f.Show()'
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ ''
+ '')
+ Align = Client
+ Margins.Left = 10.000000000000000000
+ Margins.Right = 10.000000000000000000
+ Margins.Bottom = 10.000000000000000000
+ Size.Width = 329.000000000000000000
+ Size.Height = 412.000000000000000000
+ Size.PlatformDefault = False
+ TabOrder = 0
+ Viewport.Width = 316.000000000000000000
+ Viewport.Height = 399.000000000000000000
+ end
+ object Layout4: TLayout
+ Anchors = [akRight, akBottom]
+ Position.X = 284.000000000000000000
+ Position.Y = 358.000000000000000000
+ TabOrder = 6
+ object Circle2: TCircle
+ Align = Contents
+ Fill.Color = claGainsboro
+ Size.Width = 50.000000000000000000
+ Size.Height = 50.000000000000000000
+ Size.PlatformDefault = False
+ Stroke.Thickness = 0.000000000000000000
+ end
+ object btnClearInput: TButton
+ Action = actClearInput
+ Align = Client
+ Enabled = True
+ ImageIndex = -1
+ Size.Width = 48.000000000000000000
+ Size.Height = 48.000000000000000000
+ Size.PlatformDefault = False
+ StyleLookup = 'trashtoolbutton'
+ TabOrder = 3
+ end
+ end
+ end
+ object PythonEngine1: TPythonEngine
+ AutoLoad = False
+ IO = PythonGUIInputOutput1
+ Left = 258
+ Top = 56
+ end
+ object PythonGUIInputOutput1: TPythonGUIInputOutput
+ UnicodeIO = True
+ RawOutput = False
+ Output = mmOutput
+ Left = 259
+ Top = 112
+ end
+ object ActionList1: TActionList
+ Left = 176
+ Top = 56
+ object actRun: TAction
+ Text = 'Run'
+ OnExecute = actRunExecute
+ end
+ object actClearOutput: TAction
+ Text = 'actClearOutput'
+ OnExecute = actClearOutputExecute
+ end
+ object actClearInput: TAction
+ Text = 'actClearInput'
+ OnExecute = actClearInputExecute
+ end
+ end
+ object PythonModule1: TPythonModule
+ Engine = PythonEngine1
+ OnInitialization = PythonModule1Initialization
+ ModuleName = 'fmx'
+ Errors = <>
+ Left = 256
+ Top = 168
+ end
+ object PyDelphiWrapper1: TPyDelphiWrapper
+ Engine = PythonEngine1
+ Module = PythonModule1
+ Left = 256
+ Top = 224
+ end
+ object PythonDelphiVar1: TPythonDelphiVar
+ Engine = PythonEngine1
+ Module = 'fmx'
+ VarName = 'CameraComp'
+ OnExtGetData = PythonDelphiVar1ExtGetData
+ OnExtSetData = PythonDelphiVar1ExtSetData
+ Left = 256
+ Top = 280
+ end
+ object PythonDelphiVar2: TPythonDelphiVar
+ Engine = PythonEngine1
+ Module = 'fmx'
+ VarName = 'ImageBuff'
+ OnExtGetData = PythonDelphiVar2ExtGetData
+ OnExtSetData = PythonDelphiVar2ExtSetData
+ Left = 256
+ Top = 336
+ end
+end
diff --git a/Demos/FMX/Android/CameraPreviewDemo/MainForm.pas b/Demos/FMX/Android/CameraPreviewDemo/MainForm.pas
new file mode 100644
index 00000000..f66e17ee
--- /dev/null
+++ b/Demos/FMX/Android/CameraPreviewDemo/MainForm.pas
@@ -0,0 +1,333 @@
+(* ************************************************************************ *)
+(* *)
+(* Module: Unit 'MainForm' Copyright (c) 2021 *)
+(* *)
+(* Lucas Moura Belo - lmbelo *)
+(* lucas.belo@live.com *)
+(* Brazil *)
+(* *)
+(* PyScripter *)
+(* e-mail: pyscripter@gmail.com *)
+(* *)
+(* Project pages: https://github.com/Embarcadero/python4delphi *)
+(* https://github.com/pyscripter/python4delphi *)
+(* ************************************************************************ *)
+(* Functionality: It creates a form at run-time and adds a *)
+(* TCameraComponent on it. Also creates a *)
+(* Start/Stop camera for a previewer. *)
+(* *)
+(* ************************************************************************ *)
+(* This source code is distributed with no WARRANTY, for no reason or use. *)
+(* Everyone is allowed to use and change this code free for his own tasks *)
+(* and projects, as long as this header and its copyright text is intact. *)
+(* For changed versions of this code, which are public distributed the *)
+(* following additional conditions have to be fullfilled: *)
+(* 1) The header has to contain a comment on the change and the author of *)
+(* it. *)
+(* 2) A copy of the changed source has to be sent to the above E-Mail *)
+(* address or my then valid address, if this is possible to the *)
+(* author. *)
+(* The second condition has the target to maintain an up to date central *)
+(* version of the component. If this condition is not acceptable for *)
+(* confidential or legal reasons, everyone is free to derive a component *)
+(* or to generate a diff file to my or other original sources. *)
+(* ************************************************************************ *)
+{$I Definition.inc}
+unit MainForm;
+
+interface
+
+uses
+ System.SysUtils, System.Types, System.UITypes, System.Classes,
+ System.Variants, System.Messaging,
+ FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Memo.Types,
+ FMX.Ani, FMX.StdCtrls, FMX.Controls.Presentation, FMX.ScrollBox, FMX.Memo,
+ PythonEngine, FMX.PythonGUIInputOutput, System.Actions, System.Permissions,
+ FMX.ActnList, FMX.Objects, FMX.Layouts, FMX.Platform, FMX.Media,
+ AppEnvironment,
+ ProgressFrame, System.Threading, WrapDelphi, WrapDelphiFmx;
+
+type
+ TPyMainForm = class(TForm)
+ spInputOutput: TSplitter;
+ tbTop: TToolBar;
+ tbBottom: TToolBar;
+ btnRun: TButton;
+ PythonEngine1: TPythonEngine;
+ PythonGUIInputOutput1: TPythonGUIInputOutput;
+ ActionList1: TActionList;
+ actRun: TAction;
+ Layout1: TLayout;
+ mmOutput: TMemo;
+ actClearOutput: TAction;
+ Layout2: TLayout;
+ btnClearOutput: TButton;
+ Circle1: TCircle;
+ Layout3: TLayout;
+ mmInput: TMemo;
+ Layout4: TLayout;
+ Circle2: TCircle;
+ btnClearInput: TButton;
+ actClearInput: TAction;
+ Label1: TLabel;
+ PythonModule1: TPythonModule;
+ PyDelphiWrapper1: TPyDelphiWrapper;
+ PythonDelphiVar1: TPythonDelphiVar;
+ PythonDelphiVar2: TPythonDelphiVar;
+ procedure actRunExecute(Sender: TObject);
+ procedure actClearOutputExecute(Sender: TObject);
+ procedure actClearInputExecute(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure FormDestroy(Sender: TObject);
+ procedure PythonModule1Initialization(Sender: TObject);
+ procedure PythonDelphiVar1ExtSetData(Sender: TObject; Data: PPyObject);
+ procedure PythonDelphiVar1ExtGetData(Sender: TObject; var Data: PPyObject);
+ procedure PythonDelphiVar2ExtSetData(Sender: TObject; Data: PPyObject);
+ procedure PythonDelphiVar2ExtGetData(Sender: TObject; var Data: PPyObject);
+ private
+ FAppEnv: TAppEnvironment;
+ FSavedCameraActive : boolean;
+ FPermissionCamera: string;
+ FPyCamera: PPyObject;
+ FPyImage: PPyObject;
+ procedure DisableComponents();
+ procedure EnableComponents();
+ //App launch
+ procedure AppEventHandler(const Sender: TObject; const AMessage: TMessage);
+ //Python environment
+ procedure ConfigurePython();
+ //Device handlers
+ procedure ActivateCameraPermissionRequestResult(Sender: TObject;
+ const APermissions: TArray;
+ const AGrantResults: TArray);
+ procedure DisplayRationale(Sender: TObject;
+ const APermissions: TArray; const APostRationaleProc: TProc);
+ //Interop variables
+ function GetCameraComponent: TCameraComponent;
+ function GetImage: TImage;
+ //Interop methods
+ function AskDelphiForCameraPermission(PSelf, AArgs: PPyObject)
+ : PPyObject; cdecl;
+ function AskDelphiToShowFrame(PSelf, AArgs: PPyObject): PPyObject; cdecl;
+ protected
+ property Camera: TCameraComponent read GetCameraComponent;
+ property Image: TImage read GetImage;
+ public
+ { Public declarations }
+ end;
+
+var
+ PyMainForm: TPyMainForm;
+
+implementation
+
+uses
+ PythonLoad,
+ System.IOUtils,
+ FMX.DialogService,
+ Androidapi.Helpers,
+ Androidapi.JNI.JavaTypes,
+ Androidapi.JNI.Os,
+ WrapFMXMedia,
+ WrapFmxShapes;
+
+{$R *.fmx}
+
+{ TPyMainForm }
+
+procedure TPyMainForm.FormCreate(Sender: TObject);
+begin
+ DisableComponents();
+ FAppEnv := TAppEnvironment.Create(TProgressViewFrame.Create(Self, Self));
+ TMessageManager.DefaultManager.SubscribeToMessage(TApplicationEventMessage, AppEventHandler);
+ FPermissionCamera := JStringToString(TJManifest_permission.JavaClass.Camera);
+end;
+
+procedure TPyMainForm.FormDestroy(Sender: TObject);
+begin
+ FAppEnv.Free();
+end;
+
+function TPyMainForm.GetCameraComponent: TCameraComponent;
+begin
+ if IsDelphiObject(FPyCamera) then begin
+ Result := TPyDelphiCameraComponent(PythonToDelphi(FPyCamera)).DelphiObject
+ end else
+ Result := nil;
+end;
+
+function TPyMainForm.GetImage: TImage;
+begin
+ if IsDelphiObject(FPyImage) then
+ Result := TPyDelphiImage(PythonToDelphi(FPyImage)).DelphiObject
+ else
+ Result := nil;
+end;
+
+procedure TPyMainForm.PythonDelphiVar1ExtGetData(Sender: TObject;
+ var Data: PPyObject);
+begin
+ Data := FPyCamera;
+ PythonEngine1.Py_XINCREF(FPyCamera);
+end;
+
+procedure TPyMainForm.PythonDelphiVar1ExtSetData(Sender: TObject;
+ Data: PPyObject);
+begin
+ PythonEngine1.Py_XDECREF(FPyCamera);
+ FPyCamera := Data;
+ PythonEngine1.Py_XINCREF(FPyCamera);
+end;
+
+procedure TPyMainForm.PythonDelphiVar2ExtGetData(Sender: TObject;
+ var Data: PPyObject);
+begin
+ Data := FPyImage;
+ PythonEngine1.Py_XINCREF(FPyImage);
+end;
+
+procedure TPyMainForm.PythonDelphiVar2ExtSetData(Sender: TObject;
+ Data: PPyObject);
+begin
+ PythonEngine1.Py_XDECREF(FPyImage);
+ FPyImage := Data;
+ PythonEngine1.Py_XINCREF(FPyImage);
+end;
+
+procedure TPyMainForm.PythonModule1Initialization(Sender: TObject);
+begin
+ PythonModule1.AddDelphiMethod(
+ 'AskDelphiForCameraPermission',
+ AskDelphiForCameraPermission,
+ 'Check if camera permission has been granted.');
+
+ PythonModule1.AddDelphiMethod(
+ 'AskDelphiToShowFrame',
+ AskDelphiToShowFrame,
+ 'Displays sample buffer.');
+end;
+
+procedure TPyMainForm.actClearInputExecute(Sender: TObject);
+begin
+ mmInput.Lines.Clear();
+end;
+
+procedure TPyMainForm.actClearOutputExecute(Sender: TObject);
+begin
+ mmOutput.Lines.Clear();
+end;
+
+procedure TPyMainForm.ActivateCameraPermissionRequestResult(Sender: TObject;
+ const APermissions: TArray;
+ const AGrantResults: TArray);
+begin
+ if (Length(AGrantResults) = 1) and
+ (AGrantResults[0] = TPermissionStatus.Granted) then
+ begin
+ if Assigned(Camera) then
+ Camera.Active := True;
+ FSavedCameraActive := True;
+ end
+ else
+ TDialogService.ShowMessage
+ ('Cannot start the camera because the required permission has not been granted');
+end;
+
+procedure TPyMainForm.actRunExecute(Sender: TObject);
+begin
+ var
+ LMainForm := PyDelphiWrapper1.Wrap(Self);
+ PythonModule1.SetVar('MainForm', LMainForm);
+ PythonEngine1.Py_DECREF(LMainForm);
+ PythonEngine1.CheckError();
+ PythonEngine1.ExecString(AnsiString(mmInput.Lines.Text));
+end;
+
+procedure TPyMainForm.AppEventHandler(const Sender: TObject; const AMessage: TMessage);
+begin
+ case TApplicationEventMessage(AMessage).Value.Event of
+ TApplicationEvent.WillBecomeInactive:
+ begin
+ if Assigned(Camera) then
+ begin
+ FSavedCameraActive := Camera.Active;
+ Camera.Active := False;
+ end;
+ end;
+ TApplicationEvent.BecameActive:
+ begin
+ if Assigned(Camera) then
+ begin
+ Camera.Active := FSavedCameraActive;
+ end;
+ end;
+ TApplicationEvent.FinishedLaunching:
+ ConfigurePython();
+ end;
+end;
+
+function TPyMainForm.AskDelphiForCameraPermission(PSelf, AArgs: PPyObject)
+ : PPyObject; cdecl;
+begin
+ if not PermissionsService.IsPermissionGranted(FPermissionCamera) then
+ begin
+ Result := PythonEngine1.ReturnFalse;
+ PermissionsService.RequestPermissions([FPermissionCamera],
+ ActivateCameraPermissionRequestResult, DisplayRationale);
+ end
+ else
+ Result := PythonEngine1.ReturnTrue;
+end;
+
+function TPyMainForm.AskDelphiToShowFrame(PSelf, AArgs: PPyObject): PPyObject;
+begin
+ TThread.Synchronize(TThread.Current,
+ procedure begin
+ if Camera.Active then
+ Camera.SampleBufferToBitmap(Image.Bitmap, true);
+ end);
+ Result := PythonEngine1.ReturnNone;
+end;
+
+procedure TPyMainForm.ConfigurePython;
+begin
+ FAppEnv.InitializeEnvironmentAsync(PythonEngine1, True,
+ procedure(const AInitialized: boolean; const ALastErrorMsg: string)
+ begin
+ if AInitialized then
+ EnableComponents()
+ else
+ TThread.Synchronize(nil,
+ procedure
+ begin
+ ShowMessage(ALastErrorMsg);
+ end);
+ end);
+end;
+
+procedure TPyMainForm.DisableComponents;
+begin
+ btnRun.Enabled := false;
+ btnClearOutput.Enabled := false;
+ btnClearInput.Enabled := false;
+end;
+
+procedure TPyMainForm.DisplayRationale(Sender: TObject;
+const APermissions: TArray; const APostRationaleProc: TProc);
+begin
+ TDialogService.ShowMessage
+ ('The app needs to access the camera in order to work',
+ procedure(const AResult: TModalResult)
+ begin
+ APostRationaleProc;
+ end)
+end;
+
+procedure TPyMainForm.EnableComponents;
+begin
+ btnRun.Enabled := True;
+ btnClearOutput.Enabled := True;
+ btnClearInput.Enabled := True;
+end;
+
+end.
diff --git a/Demos/FMX/Android/CameraPreviewDemo/ProgressFrame.fmx b/Demos/FMX/Android/CameraPreviewDemo/ProgressFrame.fmx
new file mode 100644
index 00000000..cc459926
--- /dev/null
+++ b/Demos/FMX/Android/CameraPreviewDemo/ProgressFrame.fmx
@@ -0,0 +1,62 @@
+object ProgressViewFrame: TProgressViewFrame
+ Align = Client
+ Locked = True
+ HitTest = False
+ Size.Width = 313.000000000000000000
+ Size.Height = 168.000000000000000000
+ Size.PlatformDefault = False
+ object pnlBackground: TPanel
+ Align = Client
+ Opacity = 0.000000000000000000
+ Size.Width = 313.000000000000000000
+ Size.Height = 168.000000000000000000
+ Size.PlatformDefault = False
+ TabOrder = 2
+ end
+ object pnlContent: TPanel
+ Align = Center
+ Size.Width = 300.000000000000000000
+ Size.Height = 168.000000000000000000
+ Size.PlatformDefault = False
+ TabOrder = 1
+ object lbDescription: TLabel
+ Align = Top
+ Margins.Left = 10.000000000000000000
+ Margins.Top = 45.000000000000000000
+ Margins.Right = 10.000000000000000000
+ Position.X = 10.000000000000000000
+ Position.Y = 45.000000000000000000
+ Size.Width = 280.000000000000000000
+ Size.Height = 24.000000000000000000
+ Size.PlatformDefault = False
+ Text = 'lbDescription'
+ TabOrder = 0
+ end
+ object lblCurrentAction: TLabel
+ Align = Top
+ Margins.Left = 10.000000000000000000
+ Margins.Top = 2.000000000000000000
+ Margins.Right = 10.000000000000000000
+ Position.X = 10.000000000000000000
+ Position.Y = 95.000000000000000000
+ Size.Width = 280.000000000000000000
+ Size.Height = 21.000000000000000000
+ Size.PlatformDefault = False
+ TextSettings.WordWrap = False
+ Text = 'lblCurrentAction'
+ TabOrder = 1
+ end
+ object pbProgress: TProgressBar
+ Align = Top
+ Orientation = Horizontal
+ Margins.Left = 10.000000000000000000
+ Margins.Top = 4.000000000000000000
+ Margins.Right = 10.000000000000000000
+ Position.X = 10.000000000000000000
+ Position.Y = 73.000000000000000000
+ Size.Width = 280.000000000000000000
+ Size.Height = 20.000000000000000000
+ Size.PlatformDefault = False
+ end
+ end
+end
diff --git a/Demos/FMX/Android/CameraPreviewDemo/ProgressFrame.pas b/Demos/FMX/Android/CameraPreviewDemo/ProgressFrame.pas
new file mode 100644
index 00000000..47c35a01
--- /dev/null
+++ b/Demos/FMX/Android/CameraPreviewDemo/ProgressFrame.pas
@@ -0,0 +1,101 @@
+(**************************************************************************)
+(* *)
+(* Module: Unit 'ProgressFrame' Copyright (c) 2021 *)
+(* *)
+(* Lucas Moura Belo - lmbelo *)
+(* lucas.belo@live.com *)
+(* Brazil *)
+(* *)
+(* PyScripter *)
+(* e-mail: pyscripter@gmail.com *)
+(* *)
+(* Project pages: https://github.com/Embarcadero/python4delphi *)
+(* https://github.com/pyscripter/python4delphi *)
+(**************************************************************************)
+(* Functionality: Environment loading progress report *)
+(* *)
+(* *)
+(**************************************************************************)
+(* This source code is distributed with no WARRANTY, for no reason or use.*)
+(* Everyone is allowed to use and change this code free for his own tasks *)
+(* and projects, as long as this header and its copyright text is intact. *)
+(* For changed versions of this code, which are public distributed the *)
+(* following additional conditions have to be fullfilled: *)
+(* 1) The header has to contain a comment on the change and the author of *)
+(* it. *)
+(* 2) A copy of the changed source has to be sent to the above E-Mail *)
+(* address or my then valid address, if this is possible to the *)
+(* author. *)
+(* The second condition has the target to maintain an up to date central *)
+(* version of the component. If this condition is not acceptable for *)
+(* confidential or legal reasons, everyone is free to derive a component *)
+(* or to generate a diff file to my or other original sources. *)
+(**************************************************************************)
+unit ProgressFrame;
+
+interface
+
+uses
+ System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
+ FMX.Types, FMX.Graphics, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.StdCtrls,
+ FMX.Controls.Presentation, FMX.Layouts, AppEnvironment;
+
+type
+ TProgressViewFrame = class(TFrame, IProgressNotifier)
+ pnlContent: TPanel;
+ lbDescription: TLabel;
+ lblCurrentAction: TLabel;
+ pbProgress: TProgressBar;
+ pnlBackground: TPanel;
+ private
+ { Private declarations }
+ public
+ constructor Create(AOwner: TComponent; const AForm: TCustomForm); reintroduce;
+
+ procedure Start(const ADescription, AFirstAction: string; const ATotal: Int64);
+ procedure Update(const ACurrentAction: string; const AProgress: Int64);
+ procedure Stop();
+ end;
+
+implementation
+
+uses
+ Math;
+
+{$R *.fmx}
+
+{ TProgressViewFrame }
+
+constructor TProgressViewFrame.Create(AOwner: TComponent;
+ const AForm: TCustomForm);
+begin
+ inherited Create(AOwner);
+ lblCurrentAction.Text := String.Empty;
+ Parent := AForm;
+ Align := TAlignLayout.Contents;
+ pnlContent.Width := Math.Min(AForm.Width - 40, 410);
+end;
+
+procedure TProgressViewFrame.Start(const ADescription, AFirstAction: string;
+ const ATotal: Int64);
+begin
+ lbDescription.Text := ADescription;
+ lblCurrentAction.Text := AFirstAction;
+ pbProgress.Min := 0;
+ pbProgress.Max := ATotal;
+ pbProgress.Value := 0;
+ pnlContent.Visible := not ADescription.IsEmpty();
+end;
+
+procedure TProgressViewFrame.Stop;
+begin
+ Self.Visible := false;
+end;
+
+procedure TProgressViewFrame.Update(const ACurrentAction: string; const AProgress: Int64);
+begin
+ lblCurrentAction.Text := ACurrentAction;
+ pbProgress.Value := AProgress;
+end;
+
+end.
diff --git a/Demos/FMX/Android/CameraPreviewDemo/PythonLoad.pas b/Demos/FMX/Android/CameraPreviewDemo/PythonLoad.pas
new file mode 100644
index 00000000..e55583dc
--- /dev/null
+++ b/Demos/FMX/Android/CameraPreviewDemo/PythonLoad.pas
@@ -0,0 +1,136 @@
+(**************************************************************************)
+(* *)
+(* Module: Unit 'PythonLoad' Copyright (c) 2021 *)
+(* *)
+(* Lucas Moura Belo - lmbelo *)
+(* lucas.belo@live.com *)
+(* Brazil *)
+(* *)
+(* PyScripter *)
+(* e-mail: pyscripter@gmail.com *)
+(* *)
+(* Project pages: https://github.com/Embarcadero/python4delphi *)
+(* https://github.com/pyscripter/python4delphi *)
+(**************************************************************************)
+(* Functionality: Load python distribution *)
+(* *)
+(* *)
+(**************************************************************************)
+(* This source code is distributed with no WARRANTY, for no reason or use.*)
+(* Everyone is allowed to use and change this code free for his own tasks *)
+(* and projects, as long as this header and its copyright text is intact. *)
+(* For changed versions of this code, which are public distributed the *)
+(* following additional conditions have to be fullfilled: *)
+(* 1) The header has to contain a comment on the change and the author of *)
+(* it. *)
+(* 2) A copy of the changed source has to be sent to the above E-Mail *)
+(* address or my then valid address, if this is possible to the *)
+(* author. *)
+(* The second condition has the target to maintain an up to date central *)
+(* version of the component. If this condition is not acceptable for *)
+(* confidential or legal reasons, everyone is free to derive a component *)
+(* or to generate a diff file to my or other original sources. *)
+(**************************************************************************)
+unit PythonLoad;
+
+interface
+
+uses
+ System.SysUtils, System.Zip, PythonEngine;
+
+type
+ TExtractEvent = reference to procedure(const AFolderExists: boolean; var AReplaceFiles: boolean);
+ TPythonLoad = class
+ public
+ class function GetPyZip(): string; static;
+ class function GetPyRoot(): string; static;
+ class function GetPyHome(): string; static;
+ class function GetPyBin(): string; static;
+ class function GetPyLib(): string; static;
+
+ class procedure Extract(const AExtractEvent: TExtractEvent;
+ const AZipProgress: TZipProgressEvent); static;
+ class procedure Configure(const APythonEngine: TPythonEngine;
+ const ACheckPyLib: boolean = true); static;
+ end;
+
+implementation
+
+uses
+ System.IOUtils;
+
+const
+ PY_KNOWN_VER = 7;
+
+{ TPythonLoad }
+
+class procedure TPythonLoad.Extract(const AExtractEvent: TExtractEvent;
+ const AZipProgress: TZipProgressEvent);
+begin
+ var LPyRoot := TPythonLoad.GetPyRoot();
+ var LFolderExists := TDirectory.Exists(LPyRoot);
+ var LReplaceFiles := false;
+
+ if Assigned(AExtractEvent) then
+ AExtractEvent(LFolderExists, LReplaceFiles);
+
+ if LFolderExists then
+ if not LReplaceFiles then
+ Exit()
+ else
+ TDirectory.Delete(LPyRoot, true);
+
+ var LPyZip := TPythonLoad.GetPyZip();
+ if not TFile.Exists(LPyZip) then
+ raise Exception.Create('Python compressed distribution not found.');
+
+ TZipFile.ExtractZipFile(LPyZip, LPyRoot, AZipProgress);
+end;
+
+class function TPythonLoad.GetPyBin: string;
+begin
+ Result := TPath.Combine(GetPyHome(), 'bin');
+end;
+
+class function TPythonLoad.GetPyHome: string;
+begin
+ Result := TPath.Combine(GetPyRoot(), 'usr');
+end;
+
+class function TPythonLoad.GetPyLib: string;
+begin
+ Result := TPath.Combine(GetPyHome(), 'lib');
+end;
+
+class function TPythonLoad.GetPyRoot: string;
+begin
+ Result := TPath.Combine(TPath.GetDocumentsPath(), 'build');
+end;
+
+class function TPythonLoad.GetPyZip: string;
+begin
+ Result := TPath.Combine(TPath.GetDocumentsPath(), 'build.zip');
+end;
+
+class procedure TPythonLoad.Configure(const APythonEngine: TPythonEngine;
+ const ACheckPyLib: boolean);
+begin
+ if ACheckPyLib then begin
+ var LPyLibFile := TPath.Combine(TPath.GetLibraryPath(),
+ PYTHON_KNOWN_VERSIONS[PY_KNOWN_VER].DllName);
+
+ if not TFile.Exists(LPyLibFile) then
+ raise Exception.Create('Python library not found at application''s data folder.'
+ + #13#10
+ + LPyLibFile);
+ end;
+
+ APythonEngine.UseLastKnownVersion := false;
+ APythonEngine.ProgramName := TPythonLoad.GetPyBin();
+ APythonEngine.PythonHome := TPythonLoad.GetPyHome();
+ APythonEngine.RegVersion := PYTHON_KNOWN_VERSIONS[PY_KNOWN_VER].RegVersion;
+ APythonEngine.DllName := PYTHON_KNOWN_VERSIONS[PY_KNOWN_VER].DllName;
+ APythonEngine.APIVersion := PYTHON_KNOWN_VERSIONS[PY_KNOWN_VER].APIVersion;
+end;
+
+end.
diff --git a/Demos/FMX/Android/Demo00/AndroidManifest.template.xml b/Demos/FMX/Android/Demo00/AndroidManifest.template.xml
new file mode 100644
index 00000000..10c95df9
--- /dev/null
+++ b/Demos/FMX/Android/Demo00/AndroidManifest.template.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+ <%uses-permission%>
+
+
+
+ <%provider%>
+ <%application-meta-data%>
+ <%uses-libraries%>
+ <%services%>
+
+
+
+
+
+
+
+
+
+ <%activity%>
+ <%receivers%>
+
+
+
diff --git a/Demos/FMX/Android/Demo00/AppEnvironment.pas b/Demos/FMX/Android/Demo00/AppEnvironment.pas
new file mode 100644
index 00000000..6aadc653
--- /dev/null
+++ b/Demos/FMX/Android/Demo00/AppEnvironment.pas
@@ -0,0 +1,165 @@
+(**************************************************************************)
+(* *)
+(* Module: Unit 'AppEnvironment' Copyright (c) 2021 *)
+(* *)
+(* Lucas Moura Belo - lmbelo *)
+(* lucas.belo@live.com *)
+(* Brazil *)
+(* *)
+(* PyScripter *)
+(* e-mail: pyscripter@gmail.com *)
+(* *)
+(* Project pages: https://github.com/Embarcadero/python4delphi *)
+(* https://github.com/pyscripter/python4delphi *)
+(**************************************************************************)
+(* Functionality: App environment set up *)
+(* *)
+(* *)
+(**************************************************************************)
+(* This source code is distributed with no WARRANTY, for no reason or use.*)
+(* Everyone is allowed to use and change this code free for his own tasks *)
+(* and projects, as long as this header and its copyright text is intact. *)
+(* For changed versions of this code, which are public distributed the *)
+(* following additional conditions have to be fullfilled: *)
+(* 1) The header has to contain a comment on the change and the author of *)
+(* it. *)
+(* 2) A copy of the changed source has to be sent to the above E-Mail *)
+(* address or my then valid address, if this is possible to the *)
+(* author. *)
+(* The second condition has the target to maintain an up to date central *)
+(* version of the component. If this condition is not acceptable for *)
+(* confidential or legal reasons, everyone is free to derive a component *)
+(* or to generate a diff file to my or other original sources. *)
+(**************************************************************************)
+unit AppEnvironment;
+
+interface
+
+uses
+ System.Classes, System.SysUtils, System.Threading, System.Zip, PythonEngine;
+
+type
+ IProgressNotifier = interface
+ ['{7A2D1743-D4D8-4093-B372-04D814536708}']
+ procedure Start(const ADescription, AFirstAction: string; const ATotal: Int64);
+ procedure Update(const ACurrentAction: string; const AProgress: Int64);
+ procedure Stop();
+ end;
+
+ TAppEnvInit = reference to procedure(const AInitialized: boolean; const ALastErrorMsg: string);
+
+ TAppEnvironment = class
+ private
+ FInitialized: boolean;
+ FProgressNotifier: IProgressNotifier;
+ procedure OnZipProgressEvent(Sender: TObject; FileName: string; Header: TZipHeader; Position: Int64);
+ procedure DoInitializeEnvironmentAsync(const APythonEngine: TPythonEngine;
+ const ACheckPyLib: boolean = true);
+ public
+ constructor Create(const AProgressNotifier: IProgressNotifier);
+
+ procedure InitializeEnvironmentAsync(const APythonEngine: TPythonEngine;
+ const ACheckPyLib: boolean; const AAppEnvInit: TAppEnvInit);
+
+ property Initialized: boolean read FInitialized;
+ end;
+
+implementation
+
+uses
+ System.IOUtils, FMX.Dialogs, PythonLoad;
+
+{ TAppEnvironment }
+
+constructor TAppEnvironment.Create(const AProgressNotifier: IProgressNotifier);
+begin
+ Assert(Assigned(AProgressNotifier), '"AProgressNotifier" undefined');
+ FInitialized := false;
+ FProgressNotifier := AProgressNotifier;
+end;
+
+procedure TAppEnvironment.DoInitializeEnvironmentAsync(const APythonEngine: TPythonEngine;
+ const ACheckPyLib: boolean = true);
+begin
+ try
+ //Lock user iteractions
+ TThread.Synchronize(nil, procedure() begin
+ FProgressNotifier.Start('Searching for Python installation', String.Empty, 0);
+ end);
+
+ Sleep(200);
+
+ //Python distibution unzip
+ TPythonLoad.Extract(
+ procedure(const AFolderExists: boolean; var AReplaceFiles: boolean) begin
+ if not AFolderExists then begin
+ TThread.Synchronize(nil, procedure() begin
+ FProgressNotifier.Start('Installing Python', String.Empty, 0);
+ end);
+ end;
+ AReplaceFiles := false;
+ end, OnZipProgressEvent);
+
+ //Configure Python for Android
+ TThread.Synchronize(nil, procedure() begin
+ FProgressNotifier.Start('Configuring Python for Android', String.Empty, 3);
+ FProgressNotifier.Update('Check for files', 1)
+ end);
+
+ TPythonLoad.Configure(APythonEngine);
+ Sleep(1000);
+
+ //Load python library
+ TThread.Synchronize(nil, procedure() begin
+ FProgressNotifier.Start('Loading Python', String.Empty, 3);
+ FProgressNotifier.Update('Loading and mapping library', 2)
+ end);
+
+ TThread.Synchronize(nil, procedure() begin
+ APythonEngine.LoadDll();
+ end);
+ Sleep(1000);
+
+ //All done notification
+ TThread.Synchronize(nil, procedure() begin
+ FProgressNotifier.Start('Loading environment', String.Empty, 3);
+ FProgressNotifier.Update('All ready', 3)
+ end);
+ Sleep(1000);
+ finally
+ TThread.Synchronize(nil, procedure() begin
+ FProgressNotifier.Stop();
+ end);
+ end;
+end;
+
+procedure TAppEnvironment.InitializeEnvironmentAsync(
+ const APythonEngine: TPythonEngine; const ACheckPyLib: boolean;
+ const AAppEnvInit: TAppEnvInit);
+begin
+ TTask.Run(
+ procedure() begin
+ try
+ DoInitializeEnvironmentAsync(APythonEngine, ACheckPyLib);
+ FInitialized := true;
+ if Assigned(AAppEnvInit) then
+ AAppEnvInit(true, String.Empty);
+ except
+ on E: Exception do begin
+ if Assigned(AAppEnvInit) then
+ AAppEnvInit(false, E.Message);
+ end;
+ end;
+ end);
+end;
+
+procedure TAppEnvironment.OnZipProgressEvent(Sender: TObject; FileName: string;
+ Header: TZipHeader; Position: Int64);
+begin
+ TThread.Queue(nil, procedure() begin
+ FProgressNotifier.Start('Extracting files', String.Empty, Header.UncompressedSize);
+ FProgressNotifier.Update(TPath.GetFileName(FileName), Position);
+ end);
+end;
+
+end.
diff --git a/Demos/FMX/Android/Demo00/MainForm.fmx b/Demos/FMX/Android/Demo00/MainForm.fmx
new file mode 100644
index 00000000..0a3310ca
--- /dev/null
+++ b/Demos/FMX/Android/Demo00/MainForm.fmx
@@ -0,0 +1,180 @@
+object PyMainForm: TPyMainForm
+ Left = 0
+ Top = 0
+ Caption = 'MainForm'
+ ClientHeight = 743
+ ClientWidth = 349
+ FormFactor.Width = 320
+ FormFactor.Height = 480
+ FormFactor.Devices = [Desktop]
+ OnCreate = FormCreate
+ OnDestroy = FormDestroy
+ DesignerMasterStyle = 3
+ object spInputOutput: TSplitter
+ Align = Top
+ Cursor = crVSplit
+ MinSize = 20.000000000000000000
+ Position.Y = 265.000000000000000000
+ Size.Width = 349.000000000000000000
+ Size.Height = 8.000000000000000000
+ Size.PlatformDefault = False
+ end
+ object tbTop: TToolBar
+ Size.Width = 349.000000000000000000
+ Size.Height = 48.000000000000000000
+ Size.PlatformDefault = False
+ TabOrder = 0
+ object Label1: TLabel
+ Align = Client
+ Size.Width = 349.000000000000000000
+ Size.Height = 48.000000000000000000
+ Size.PlatformDefault = False
+ StyleLookup = 'toollabel'
+ TextSettings.HorzAlign = Center
+ Text = 'Python4Delphi - PyLoad'
+ TabOrder = 1
+ end
+ end
+ object tbBottom: TToolBar
+ Align = Bottom
+ Position.Y = 695.000000000000000000
+ Size.Width = 349.000000000000000000
+ Size.Height = 48.000000000000000000
+ Size.PlatformDefault = False
+ TabOrder = 1
+ object btnRun: TButton
+ Action = actRun
+ Align = Center
+ Enabled = True
+ ImageIndex = -1
+ Size.Width = 48.000000000000000000
+ Size.Height = 48.000000000000000000
+ Size.PlatformDefault = False
+ StyleLookup = 'playtoolbutton'
+ TabOrder = 0
+ end
+ end
+ object Layout1: TLayout
+ Align = Top
+ Position.Y = 48.000000000000000000
+ Size.Width = 349.000000000000000000
+ Size.Height = 217.000000000000000000
+ Size.PlatformDefault = False
+ TabOrder = 5
+ object mmOutput: TMemo
+ Touch.InteractiveGestures = [Pan, LongTap, DoubleTap]
+ DataDetectorTypes = []
+ ReadOnly = True
+ Align = Client
+ Margins.Left = 10.000000000000000000
+ Margins.Top = 10.000000000000000000
+ Margins.Right = 10.000000000000000000
+ Size.Width = 329.000000000000000000
+ Size.Height = 207.000000000000000000
+ Size.PlatformDefault = False
+ TabOrder = 1
+ Viewport.Width = 321.000000000000000000
+ Viewport.Height = 199.000000000000000000
+ end
+ object Layout2: TLayout
+ Anchors = [akRight, akBottom]
+ Position.X = 284.000000000000000000
+ Position.Y = 163.000000000000000000
+ TabOrder = 6
+ object Circle1: TCircle
+ Align = Contents
+ Fill.Color = claGainsboro
+ Size.Width = 50.000000000000000000
+ Size.Height = 50.000000000000000000
+ Size.PlatformDefault = False
+ Stroke.Thickness = 0.000000000000000000
+ end
+ object btnClearOutput: TButton
+ Action = actClearOutput
+ Align = Client
+ Enabled = True
+ ImageIndex = -1
+ Size.Width = 48.000000000000000000
+ Size.Height = 48.000000000000000000
+ Size.PlatformDefault = False
+ StyleLookup = 'trashtoolbutton'
+ TabOrder = 3
+ end
+ end
+ end
+ object Layout3: TLayout
+ Align = Client
+ Size.Width = 349.000000000000000000
+ Size.Height = 422.000000000000000000
+ Size.PlatformDefault = False
+ TabOrder = 6
+ object mmInput: TMemo
+ Touch.InteractiveGestures = [Pan, LongTap, DoubleTap]
+ DataDetectorTypes = []
+ Align = Client
+ Margins.Left = 10.000000000000000000
+ Margins.Right = 10.000000000000000000
+ Margins.Bottom = 10.000000000000000000
+ Size.Width = 329.000000000000000000
+ Size.Height = 412.000000000000000000
+ Size.PlatformDefault = False
+ TabOrder = 0
+ Viewport.Width = 321.000000000000000000
+ Viewport.Height = 404.000000000000000000
+ end
+ object Layout4: TLayout
+ Anchors = [akRight, akBottom]
+ Position.X = 284.000000000000000000
+ Position.Y = 358.000000000000000000
+ TabOrder = 6
+ object Circle2: TCircle
+ Align = Contents
+ Fill.Color = claGainsboro
+ Size.Width = 50.000000000000000000
+ Size.Height = 50.000000000000000000
+ Size.PlatformDefault = False
+ Stroke.Thickness = 0.000000000000000000
+ end
+ object btnClearInput: TButton
+ Action = actClearInput
+ Align = Client
+ Enabled = True
+ ImageIndex = -1
+ Size.Width = 48.000000000000000000
+ Size.Height = 48.000000000000000000
+ Size.PlatformDefault = False
+ StyleLookup = 'trashtoolbutton'
+ TabOrder = 3
+ end
+ end
+ end
+ object PythonEngine1: TPythonEngine
+ AutoLoad = False
+ IO = PythonGUIInputOutput1
+ Left = 258
+ Top = 56
+ end
+ object PythonGUIInputOutput1: TPythonGUIInputOutput
+ UnicodeIO = True
+ RawOutput = False
+ Output = mmOutput
+ Left = 259
+ Top = 112
+ end
+ object ActionList1: TActionList
+ Left = 288
+ Top = 320
+ object actRun: TAction
+ Text = 'Run'
+ OnExecute = actRunExecute
+ end
+ object actClearOutput: TAction
+ Text = 'actClearOutput'
+ OnExecute = actClearOutputExecute
+ end
+ object actClearInput: TAction
+ Text = 'actClearInput'
+ OnExecute = actClearInputExecute
+ end
+ end
+end
diff --git a/Demos/FMX/Android/Demo00/MainForm.pas b/Demos/FMX/Android/Demo00/MainForm.pas
new file mode 100644
index 00000000..bdd42c71
--- /dev/null
+++ b/Demos/FMX/Android/Demo00/MainForm.pas
@@ -0,0 +1,170 @@
+(**************************************************************************)
+(* *)
+(* Module: Unit 'MainForm' Copyright (c) 2021 *)
+(* *)
+(* Lucas Moura Belo - lmbelo *)
+(* lucas.belo@live.com *)
+(* Brazil *)
+(* *)
+(* PyScripter *)
+(* e-mail: pyscripter@gmail.com *)
+(* *)
+(* Project pages: https://github.com/Embarcadero/python4delphi *)
+(* https://github.com/pyscripter/python4delphi *)
+(**************************************************************************)
+(* Functionality: MainForm of PyLoad *)
+(* Python4Delphi on Android *)
+(* *)
+(**************************************************************************)
+(* This source code is distributed with no WARRANTY, for no reason or use.*)
+(* Everyone is allowed to use and change this code free for his own tasks *)
+(* and projects, as long as this header and its copyright text is intact. *)
+(* For changed versions of this code, which are public distributed the *)
+(* following additional conditions have to be fullfilled: *)
+(* 1) The header has to contain a comment on the change and the author of *)
+(* it. *)
+(* 2) A copy of the changed source has to be sent to the above E-Mail *)
+(* address or my then valid address, if this is possible to the *)
+(* author. *)
+(* The second condition has the target to maintain an up to date central *)
+(* version of the component. If this condition is not acceptable for *)
+(* confidential or legal reasons, everyone is free to derive a component *)
+(* or to generate a diff file to my or other original sources. *)
+(**************************************************************************)
+
+unit MainForm;
+
+interface
+
+uses
+ System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
+ FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Memo.Types,
+ FMX.Ani, FMX.StdCtrls, FMX.Controls.Presentation, FMX.ScrollBox, FMX.Memo,
+ PythonEngine, FMX.PythonGUIInputOutput, System.Actions, FMX.ActnList,
+ FMX.Objects, FMX.Layouts, FMX.Platform, AppEnvironment, ProgressFrame,
+ System.Threading;
+
+type
+ TPyMainForm = class(TForm)
+ spInputOutput: TSplitter;
+ tbTop: TToolBar;
+ tbBottom: TToolBar;
+ btnRun: TButton;
+ PythonEngine1: TPythonEngine;
+ PythonGUIInputOutput1: TPythonGUIInputOutput;
+ ActionList1: TActionList;
+ actRun: TAction;
+ Layout1: TLayout;
+ mmOutput: TMemo;
+ actClearOutput: TAction;
+ Layout2: TLayout;
+ btnClearOutput: TButton;
+ Circle1: TCircle;
+ Layout3: TLayout;
+ mmInput: TMemo;
+ Layout4: TLayout;
+ Circle2: TCircle;
+ btnClearInput: TButton;
+ actClearInput: TAction;
+ Label1: TLabel;
+ procedure actRunExecute(Sender: TObject);
+ procedure actClearOutputExecute(Sender: TObject);
+ procedure actClearInputExecute(Sender: TObject);
+ procedure FormCreate(Sender: TObject);
+ procedure FormDestroy(Sender: TObject);
+ private
+ FAppEnv: TAppEnvironment;
+ function AppEventHandler(AAppEvent: TApplicationEvent; AContext: TObject): boolean;
+ procedure ConfigurePython();
+ procedure DisableComponents();
+ procedure EnableComponents();
+ public
+ { Public declarations }
+ end;
+
+var
+ PyMainForm: TPyMainForm;
+
+implementation
+
+uses
+ PythonLoad, System.IOUtils;
+
+{$R *.fmx}
+
+{ TPyMainForm }
+
+procedure TPyMainForm.FormCreate(Sender: TObject);
+begin
+ DisableComponents();
+ FAppEnv := TAppEnvironment.Create(TProgressViewFrame.Create(Self, Self));
+
+ var LAppEventService := IFMXApplicationEventService(nil);
+ if TPlatformServices.Current.SupportsPlatformService(
+ IFMXApplicationEventService, IInterface(LAppEventService)) then
+ LAppEventService.SetApplicationEventHandler(AppEventHandler)
+ else begin
+ Log.d('Platform service "IFMXApplicationEventService" not supported.');
+ Halt(1);
+ end;
+end;
+
+procedure TPyMainForm.FormDestroy(Sender: TObject);
+begin
+ FAppEnv.Free();
+end;
+
+procedure TPyMainForm.actClearInputExecute(Sender: TObject);
+begin
+ mmInput.Lines.Clear();
+end;
+
+procedure TPyMainForm.actClearOutputExecute(Sender: TObject);
+begin
+ mmOutput.Lines.Clear();
+end;
+
+procedure TPyMainForm.actRunExecute(Sender: TObject);
+begin
+ PythonEngine1.ExecString(AnsiString(mmInput.Lines.Text));
+end;
+
+function TPyMainForm.AppEventHandler(AAppEvent: TApplicationEvent;
+ AContext: TObject): boolean;
+begin
+ case AAppEvent of
+ TApplicationEvent.FinishedLaunching: ConfigurePython();
+ end;
+ Result := true;
+end;
+
+procedure TPyMainForm.ConfigurePython;
+begin
+ FAppEnv.InitializeEnvironmentAsync(PythonEngine1, true,
+ procedure(const AInitialized: boolean; const ALastErrorMsg: string) begin
+ if AInitialized then
+ EnableComponents()
+ else
+ TThread.Synchronize(nil,
+ procedure
+ begin
+ ShowMessage(ALastErrorMsg);
+ end);
+ end);
+end;
+
+procedure TPyMainForm.DisableComponents;
+begin
+ btnRun.Enabled := false;
+ btnClearOutput.Enabled := false;
+ btnClearInput.Enabled := false;
+end;
+
+procedure TPyMainForm.EnableComponents;
+begin
+ btnRun.Enabled := true;
+ btnClearOutput.Enabled := true;
+ btnClearInput.Enabled := true;
+end;
+
+end.
diff --git a/Demos/FMX/Android/Demo00/ProgressFrame.fmx b/Demos/FMX/Android/Demo00/ProgressFrame.fmx
new file mode 100644
index 00000000..cc459926
--- /dev/null
+++ b/Demos/FMX/Android/Demo00/ProgressFrame.fmx
@@ -0,0 +1,62 @@
+object ProgressViewFrame: TProgressViewFrame
+ Align = Client
+ Locked = True
+ HitTest = False
+ Size.Width = 313.000000000000000000
+ Size.Height = 168.000000000000000000
+ Size.PlatformDefault = False
+ object pnlBackground: TPanel
+ Align = Client
+ Opacity = 0.000000000000000000
+ Size.Width = 313.000000000000000000
+ Size.Height = 168.000000000000000000
+ Size.PlatformDefault = False
+ TabOrder = 2
+ end
+ object pnlContent: TPanel
+ Align = Center
+ Size.Width = 300.000000000000000000
+ Size.Height = 168.000000000000000000
+ Size.PlatformDefault = False
+ TabOrder = 1
+ object lbDescription: TLabel
+ Align = Top
+ Margins.Left = 10.000000000000000000
+ Margins.Top = 45.000000000000000000
+ Margins.Right = 10.000000000000000000
+ Position.X = 10.000000000000000000
+ Position.Y = 45.000000000000000000
+ Size.Width = 280.000000000000000000
+ Size.Height = 24.000000000000000000
+ Size.PlatformDefault = False
+ Text = 'lbDescription'
+ TabOrder = 0
+ end
+ object lblCurrentAction: TLabel
+ Align = Top
+ Margins.Left = 10.000000000000000000
+ Margins.Top = 2.000000000000000000
+ Margins.Right = 10.000000000000000000
+ Position.X = 10.000000000000000000
+ Position.Y = 95.000000000000000000
+ Size.Width = 280.000000000000000000
+ Size.Height = 21.000000000000000000
+ Size.PlatformDefault = False
+ TextSettings.WordWrap = False
+ Text = 'lblCurrentAction'
+ TabOrder = 1
+ end
+ object pbProgress: TProgressBar
+ Align = Top
+ Orientation = Horizontal
+ Margins.Left = 10.000000000000000000
+ Margins.Top = 4.000000000000000000
+ Margins.Right = 10.000000000000000000
+ Position.X = 10.000000000000000000
+ Position.Y = 73.000000000000000000
+ Size.Width = 280.000000000000000000
+ Size.Height = 20.000000000000000000
+ Size.PlatformDefault = False
+ end
+ end
+end
diff --git a/Demos/FMX/Android/Demo00/ProgressFrame.pas b/Demos/FMX/Android/Demo00/ProgressFrame.pas
new file mode 100644
index 00000000..47c35a01
--- /dev/null
+++ b/Demos/FMX/Android/Demo00/ProgressFrame.pas
@@ -0,0 +1,101 @@
+(**************************************************************************)
+(* *)
+(* Module: Unit 'ProgressFrame' Copyright (c) 2021 *)
+(* *)
+(* Lucas Moura Belo - lmbelo *)
+(* lucas.belo@live.com *)
+(* Brazil *)
+(* *)
+(* PyScripter *)
+(* e-mail: pyscripter@gmail.com *)
+(* *)
+(* Project pages: https://github.com/Embarcadero/python4delphi *)
+(* https://github.com/pyscripter/python4delphi *)
+(**************************************************************************)
+(* Functionality: Environment loading progress report *)
+(* *)
+(* *)
+(**************************************************************************)
+(* This source code is distributed with no WARRANTY, for no reason or use.*)
+(* Everyone is allowed to use and change this code free for his own tasks *)
+(* and projects, as long as this header and its copyright text is intact. *)
+(* For changed versions of this code, which are public distributed the *)
+(* following additional conditions have to be fullfilled: *)
+(* 1) The header has to contain a comment on the change and the author of *)
+(* it. *)
+(* 2) A copy of the changed source has to be sent to the above E-Mail *)
+(* address or my then valid address, if this is possible to the *)
+(* author. *)
+(* The second condition has the target to maintain an up to date central *)
+(* version of the component. If this condition is not acceptable for *)
+(* confidential or legal reasons, everyone is free to derive a component *)
+(* or to generate a diff file to my or other original sources. *)
+(**************************************************************************)
+unit ProgressFrame;
+
+interface
+
+uses
+ System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
+ FMX.Types, FMX.Graphics, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.StdCtrls,
+ FMX.Controls.Presentation, FMX.Layouts, AppEnvironment;
+
+type
+ TProgressViewFrame = class(TFrame, IProgressNotifier)
+ pnlContent: TPanel;
+ lbDescription: TLabel;
+ lblCurrentAction: TLabel;
+ pbProgress: TProgressBar;
+ pnlBackground: TPanel;
+ private
+ { Private declarations }
+ public
+ constructor Create(AOwner: TComponent; const AForm: TCustomForm); reintroduce;
+
+ procedure Start(const ADescription, AFirstAction: string; const ATotal: Int64);
+ procedure Update(const ACurrentAction: string; const AProgress: Int64);
+ procedure Stop();
+ end;
+
+implementation
+
+uses
+ Math;
+
+{$R *.fmx}
+
+{ TProgressViewFrame }
+
+constructor TProgressViewFrame.Create(AOwner: TComponent;
+ const AForm: TCustomForm);
+begin
+ inherited Create(AOwner);
+ lblCurrentAction.Text := String.Empty;
+ Parent := AForm;
+ Align := TAlignLayout.Contents;
+ pnlContent.Width := Math.Min(AForm.Width - 40, 410);
+end;
+
+procedure TProgressViewFrame.Start(const ADescription, AFirstAction: string;
+ const ATotal: Int64);
+begin
+ lbDescription.Text := ADescription;
+ lblCurrentAction.Text := AFirstAction;
+ pbProgress.Min := 0;
+ pbProgress.Max := ATotal;
+ pbProgress.Value := 0;
+ pnlContent.Visible := not ADescription.IsEmpty();
+end;
+
+procedure TProgressViewFrame.Stop;
+begin
+ Self.Visible := false;
+end;
+
+procedure TProgressViewFrame.Update(const ACurrentAction: string; const AProgress: Int64);
+begin
+ lblCurrentAction.Text := ACurrentAction;
+ pbProgress.Value := AProgress;
+end;
+
+end.
diff --git a/Demos/FMX/Android/Demo00/PyLoad.dpr b/Demos/FMX/Android/Demo00/PyLoad.dpr
new file mode 100644
index 00000000..b5301f77
--- /dev/null
+++ b/Demos/FMX/Android/Demo00/PyLoad.dpr
@@ -0,0 +1,17 @@
+program PyLoad;
+
+uses
+ System.StartUpCopy,
+ FMX.Forms,
+ MainForm in 'MainForm.pas' {PyMainForm},
+ PythonLoad in 'PythonLoad.pas',
+ ProgressFrame in 'ProgressFrame.pas' {ProgressViewFrame: TFrame},
+ AppEnvironment in 'AppEnvironment.pas';
+
+{$R *.res}
+
+begin
+ Application.Initialize;
+ Application.CreateForm(TPyMainForm, PyMainForm);
+ Application.Run;
+end.
diff --git a/Demos/FMX/Android/Demo00/PyLoad.dproj b/Demos/FMX/Android/Demo00/PyLoad.dproj
new file mode 100644
index 00000000..1c1e5d23
--- /dev/null
+++ b/Demos/FMX/Android/Demo00/PyLoad.dproj
@@ -0,0 +1,1840 @@
+
+
+ {652D9A8E-1625-4F00-9B29-2E3D31D7A186}
+ 19.2
+ FMX
+ True
+ Debug
+ Android64
+ 37915
+ Application
+ PyLoad.dpr
+
+
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Cfg_1
+ true
+ true
+
+
+ true
+ Cfg_1
+ true
+ true
+
+
+ true
+ Cfg_1
+ true
+ true
+
+
+ true
+ Cfg_1
+ true
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Cfg_2
+ true
+ true
+
+
+ true
+ Cfg_2
+ true
+ true
+
+
+ true
+ Cfg_2
+ true
+ true
+
+
+ true
+ Cfg_2
+ true
+ true
+
+
+ .\$(Platform)\$(Config)
+ .\$(Platform)\$(Config)
+ false
+ false
+ false
+ false
+ false
+ System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ $(BDS)\bin\delphi_PROJECTICON.ico
+ $(BDS)\bin\delphi_PROJECTICNS.icns
+ PyLoad
+
+
+ DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;bindcompfmx;fmx;FireDACIBDriver;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
+ package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=
+ Debug
+ true
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png
+ android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar
+
+
+ DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;bindcompfmx;fmx;FireDACIBDriver;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
+ package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=
+ Debug
+ true
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png
+ android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar
+
+
+ DBXSqliteDriver;RESTComponents;fmxase;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;bindcompfmx;fmx;FireDACIBDriver;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
+ CFBundleName=$(MSBuildProjectName);CFBundleDevelopmentRegion=en;CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleInfoDictionaryVersion=7.1;CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;LSRequiresIPhoneOS=true;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);UIDeviceFamily=iPhone & iPad;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user;NSLocationAlwaysAndWhenInUseUsageDescription=The reason for accessing the location information of the user;UIBackgroundModes=;NSContactsUsageDescription=The reason for accessing the contacts;NSPhotoLibraryUsageDescription=The reason for accessing the photo library;NSPhotoLibraryAddUsageDescription=The reason for adding to the photo library;NSCameraUsageDescription=The reason for accessing the camera;NSFaceIDUsageDescription=The reason for accessing the face id;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSSiriUsageDescription=The reason for accessing Siri;ITSAppUsesNonExemptEncryption=false;NSBluetoothAlwaysUsageDescription=The reason for accessing bluetooth;NSBluetoothPeripheralUsageDescription=The reason for accessing bluetooth peripherals;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSMotionUsageDescription=The reason for accessing the accelerometer;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers
+ iPhoneAndiPad
+ true
+ Debug
+ $(MSBuildProjectName)
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_1024x1024.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_180x180.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_2x.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImageDark_2x.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_3x.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImageDark_3x.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_120x120.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_SettingIcon_58x58.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_SettingIcon_87x87.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_NotificationIcon_40x40.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_NotificationIcon_60x60.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_167x167.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImage_2x.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageDark_2x.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_SettingIcon_58x58.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_NotificationIcon_40x40.png
+
+
+ DBXSqliteDriver;RESTComponents;fmxase;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;bindcompfmx;fmx;FireDACIBDriver;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
+ CFBundleName=$(MSBuildProjectName);CFBundleDevelopmentRegion=en;CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleInfoDictionaryVersion=7.1;CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;LSRequiresIPhoneOS=true;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);UIDeviceFamily=iPhone & iPad;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user;NSLocationAlwaysAndWhenInUseUsageDescription=The reason for accessing the location information of the user;UIBackgroundModes=;NSContactsUsageDescription=The reason for accessing the contacts;NSPhotoLibraryUsageDescription=The reason for accessing the photo library;NSPhotoLibraryAddUsageDescription=The reason for adding to the photo library;NSCameraUsageDescription=The reason for accessing the camera;NSFaceIDUsageDescription=The reason for accessing the face id;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSSiriUsageDescription=The reason for accessing Siri;ITSAppUsesNonExemptEncryption=false;NSBluetoothAlwaysUsageDescription=The reason for accessing bluetooth;NSBluetoothPeripheralUsageDescription=The reason for accessing bluetooth peripherals;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSMotionUsageDescription=The reason for accessing the accelerometer;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers
+ iPhoneAndiPad
+ true
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_1024x1024.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_180x180.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_2x.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImageDark_2x.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_3x.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImageDark_3x.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_120x120.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_SettingIcon_58x58.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_SettingIcon_87x87.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_NotificationIcon_40x40.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_NotificationIcon_60x60.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_167x167.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImage_2x.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageDark_2x.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_SettingIcon_58x58.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_NotificationIcon_40x40.png
+ 10.0
+
+
+ DBXSqliteDriver;RESTComponents;fmxase;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;FireDACMSSQLDriver;bindcompfmx;DBXOracleDriver;inetdb;fmx;FireDACIBDriver;fmxdae;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;DBXMySQLDriver;CloudService;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FireDACPgDriver;FireDACASADriver;FireDACTDataDriver;soaprtl;DbxCommonDriver;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;FireDACDSDriver;rtl;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;bindcomp;DBXInformixDriver;IndyIPClient;dbxcds;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage)
+ CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSCameraUsageDescription=The reason for accessing the camera;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSMotionUsageDescription=The reason for accessing the accelerometer;NSDesktopFolderUsageDescription=The reason for accessing the Desktop folder;NSDocumentsFolderUsageDescription=The reason for accessing the Documents folder;NSDownloadsFolderUsageDescription=The reason for accessing the Downloads folder;NSNetworkVolumesUsageDescription=The reason for accessing files on a network volume;NSRemovableVolumesUsageDescription=The reason for accessing files on a removable volume;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers
+ Debug
+ true
+
+
+ DBXSqliteDriver;RESTComponents;fmxase;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;bindcompvclsmp;emsclientfiredac;tethering;svnui;DataSnapFireDAC;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;svn;DBXOracleDriver;inetdb;emsedge;fmx;FireDACIBDriver;fmxdae;vcledge;FireDACDBXDriver;dbexpress;IndyCore;vclx;Python;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;vcl;IndyIPServer;DBXSybaseASEDriver;IndySystem;FireDACDb2Driver;bindcompvclwinx;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;soaprtl;DbxCommonDriver;PythonVcl;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;FireDACDSDriver;rtl;emsserverresource;DbxClientDriver;PythonFmx;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage)
+ Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
+ Debug
+ true
+ CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
+ 1033
+ $(BDS)\bin\default_app.manifest
+ $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
+ $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
+
+
+ DBXSqliteDriver;RESTComponents;fmxase;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;bindcompvclsmp;emsclientfiredac;tethering;DataSnapFireDAC;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;DBXOracleDriver;inetdb;emsedge;fmx;FireDACIBDriver;fmxdae;vcledge;FireDACDBXDriver;dbexpress;IndyCore;vclx;Python;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;vcl;IndyIPServer;DBXSybaseASEDriver;IndySystem;FireDACDb2Driver;bindcompvclwinx;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;soaprtl;DbxCommonDriver;PythonVcl;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;FireDACDSDriver;rtl;emsserverresource;DbxClientDriver;PythonFmx;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage)
+ Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)
+ Debug
+ true
+ CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
+ 1033
+ $(BDS)\bin\default_app.manifest
+ $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
+ $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
+
+
+ DEBUG;$(DCC_Define)
+ true
+ false
+ true
+ true
+ true
+
+
+
+ 1
+ #000000
+
+
+
+ 1
+ #000000
+
+
+ false
+ true
+ PerMonitorV2
+
+
+ true
+ PerMonitorV2
+
+
+ false
+ RELEASE;$(DCC_Define)
+ 0
+ 0
+
+
+
+ 1
+ #000000
+
+
+
+ 1
+ #000000
+
+
+ true
+ PerMonitorV2
+
+
+ true
+ PerMonitorV2
+
+
+
+ MainSource
+
+
+
+ fmx
+
+
+
+
+ fmx
+ TFrame
+
+
+
+ Cfg_2
+ Base
+
+
+ Base
+
+
+ Cfg_1
+ Base
+
+
+
+ Delphi.Personality.12
+ Application
+
+
+
+ PyLoad.dpr
+
+
+ Microsoft Office 2000 Sample Automation Server Wrapper Components
+ Microsoft Office XP Sample Automation Server Wrapper Components
+
+
+
+
+
+ .\assets\internal
+ build.zip
+ false
+
+
+
+
+ PyLoad.exe
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ library\lib\arm64-v8a\
+ libpython3.9d.so
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ classes.dex
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ true
+
+
+
+
+ styles.xml
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ true
+
+
+
+
+ library\lib\armeabi-v7a\
+ libpython3.9.so
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ .\assets\internal
+ build.zip
+ false
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ .\assets\internal
+ build.zip
+ false
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ classes.dex
+ true
+
+
+
+
+ classes.dex
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ styles.xml
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ library\lib\armeabi-v7a\
+ libpython3.9d.so
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ true
+
+
+
+
+ styles.xml
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ .\assets\internal
+ build.zip
+ false
+
+
+
+
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ classes.dex
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ library\lib\arm64-v8a\
+ libpython3.9.so
+ true
+
+
+
+
+ true
+
+
+
+
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ styles.xml
+ true
+
+
+
+
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ 0
+
+
+
+
+ classes
+ 1
+
+
+ classes
+ 1
+
+
+
+
+ res\xml
+ 1
+
+
+ res\xml
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+
+
+ library\lib\armeabi
+ 1
+
+
+ library\lib\armeabi
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+
+
+ library\lib\mips
+ 1
+
+
+ library\lib\mips
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+ library\lib\arm64-v8a
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+
+
+ res\drawable
+ 1
+
+
+ res\drawable
+ 1
+
+
+
+
+ res\values
+ 1
+
+
+ res\values
+ 1
+
+
+
+
+ res\values-v21
+ 1
+
+
+ res\values-v21
+ 1
+
+
+
+
+ res\values
+ 1
+
+
+ res\values
+ 1
+
+
+
+
+ res\drawable
+ 1
+
+
+ res\drawable
+ 1
+
+
+
+
+ res\drawable-xxhdpi
+ 1
+
+
+ res\drawable-xxhdpi
+ 1
+
+
+
+
+ res\drawable-xxxhdpi
+ 1
+
+
+ res\drawable-xxxhdpi
+ 1
+
+
+
+
+ res\drawable-ldpi
+ 1
+
+
+ res\drawable-ldpi
+ 1
+
+
+
+
+ res\drawable-mdpi
+ 1
+
+
+ res\drawable-mdpi
+ 1
+
+
+
+
+ res\drawable-hdpi
+ 1
+
+
+ res\drawable-hdpi
+ 1
+
+
+
+
+ res\drawable-xhdpi
+ 1
+
+
+ res\drawable-xhdpi
+ 1
+
+
+
+
+ res\drawable-mdpi
+ 1
+
+
+ res\drawable-mdpi
+ 1
+
+
+
+
+ res\drawable-hdpi
+ 1
+
+
+ res\drawable-hdpi
+ 1
+
+
+
+
+ res\drawable-xhdpi
+ 1
+
+
+ res\drawable-xhdpi
+ 1
+
+
+
+
+ res\drawable-xxhdpi
+ 1
+
+
+ res\drawable-xxhdpi
+ 1
+
+
+
+
+ res\drawable-xxxhdpi
+ 1
+
+
+ res\drawable-xxxhdpi
+ 1
+
+
+
+
+ res\drawable-small
+ 1
+
+
+ res\drawable-small
+ 1
+
+
+
+
+ res\drawable-normal
+ 1
+
+
+ res\drawable-normal
+ 1
+
+
+
+
+ res\drawable-large
+ 1
+
+
+ res\drawable-large
+ 1
+
+
+
+
+ res\drawable-xlarge
+ 1
+
+
+ res\drawable-xlarge
+ 1
+
+
+
+
+ res\values
+ 1
+
+
+ res\values
+ 1
+
+
+
+
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ 0
+
+
+
+
+ Contents\MacOS
+ 1
+ .framework
+
+
+ Contents\MacOS
+ 1
+ .framework
+
+
+ 0
+
+
+
+
+ 1
+ .dylib
+
+
+ 1
+ .dylib
+
+
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ 0
+ .dll;.bpl
+
+
+
+
+ 1
+ .dylib
+
+
+ 1
+ .dylib
+
+
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ 0
+ .bpl
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ Contents\Resources\StartUp\
+ 0
+
+
+ Contents\Resources\StartUp\
+ 0
+
+
+ 0
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
+ 1
+
+
+ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
+ 1
+
+
+
+
+ ..\
+ 1
+
+
+ ..\
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen
+ 64
+
+
+ ..\$(PROJECTNAME).launchscreen
+ 64
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
+ 1
+
+
+
+
+ ..\
+ 1
+
+
+ ..\
+ 1
+
+
+
+
+ Contents
+ 1
+
+
+ Contents
+ 1
+
+
+
+
+ Contents\Resources
+ 1
+
+
+ Contents\Resources
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+ library\lib\arm64-v8a
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ 0
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+
+
+ Assets
+ 1
+
+
+ Assets
+ 1
+
+
+
+
+ Assets
+ 1
+
+
+ Assets
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+
+
+ 12
+
+
+
+
+
+ call $(PROJECTDIR)\..\PyDistFinder\bin\pydistfinder.exe UNZIP $(PROJECTDIR) arm true false
+ False
+
+ False
+
+ False
+
+
+ call $(PROJECTDIR)\..\PyDistFinder\bin\pydistfinder.exe UNZIP $(PROJECTDIR) aarch64 true fals
+ False
+
+ False
+
+ False
+
+
+ call $(PROJECTDIR)\..\PyDistFinder\bin\pydistfinder.exe UNZIP $(PROJECTDIR) arm false false
+ False
+
+ False
+
+ False
+
+
+ call $(PROJECTDIR)\..\PyDistFinder\bin\pydistfinder.exe UNZIP $(PROJECTDIR) aarch64 false false
+ False
+
+ False
+
+ False
+
+
diff --git a/Demos/FMX/Android/Demo00/PythonLoad.pas b/Demos/FMX/Android/Demo00/PythonLoad.pas
new file mode 100644
index 00000000..0a0891a1
--- /dev/null
+++ b/Demos/FMX/Android/Demo00/PythonLoad.pas
@@ -0,0 +1,136 @@
+(**************************************************************************)
+(* *)
+(* Module: Unit 'PythonLoad' Copyright (c) 2021 *)
+(* *)
+(* Lucas Moura Belo - lmbelo *)
+(* lucas.belo@live.com *)
+(* Brazil *)
+(* *)
+(* PyScripter *)
+(* e-mail: pyscripter@gmail.com *)
+(* *)
+(* Project pages: https://github.com/Embarcadero/python4delphi *)
+(* https://github.com/pyscripter/python4delphi *)
+(**************************************************************************)
+(* Functionality: Load python distribution *)
+(* *)
+(* *)
+(**************************************************************************)
+(* This source code is distributed with no WARRANTY, for no reason or use.*)
+(* Everyone is allowed to use and change this code free for his own tasks *)
+(* and projects, as long as this header and its copyright text is intact. *)
+(* For changed versions of this code, which are public distributed the *)
+(* following additional conditions have to be fullfilled: *)
+(* 1) The header has to contain a comment on the change and the author of *)
+(* it. *)
+(* 2) A copy of the changed source has to be sent to the above E-Mail *)
+(* address or my then valid address, if this is possible to the *)
+(* author. *)
+(* The second condition has the target to maintain an up to date central *)
+(* version of the component. If this condition is not acceptable for *)
+(* confidential or legal reasons, everyone is free to derive a component *)
+(* or to generate a diff file to my or other original sources. *)
+(**************************************************************************)
+unit PythonLoad;
+
+interface
+
+uses
+ System.SysUtils, System.Zip, PythonEngine;
+
+type
+ TExtractEvent = reference to procedure(const AFolderExists: boolean; var AReplaceFiles: boolean);
+ TPythonLoad = class
+ public
+ class function GetPyZip(): string; static;
+ class function GetPyRoot(): string; static;
+ class function GetPyHome(): string; static;
+ class function GetPyBin(): string; static;
+ class function GetPyLib(): string; static;
+
+ class procedure Extract(const AExtractEvent: TExtractEvent;
+ const AZipProgress: TZipProgressEvent); static;
+ class procedure Configure(const APythonEngine: TPythonEngine;
+ const ACheckPyLib: boolean = true); static;
+ end;
+
+implementation
+
+uses
+ System.IOUtils;
+
+const
+ PY_KNOWN_VER = 1;
+
+{ TPythonLoad }
+
+class procedure TPythonLoad.Extract(const AExtractEvent: TExtractEvent;
+ const AZipProgress: TZipProgressEvent);
+begin
+ var LPyRoot := TPythonLoad.GetPyRoot();
+ var LFolderExists := TDirectory.Exists(LPyRoot);
+ var LReplaceFiles := false;
+
+ if Assigned(AExtractEvent) then
+ AExtractEvent(LFolderExists, LReplaceFiles);
+
+ if LFolderExists then
+ if not LReplaceFiles then
+ Exit()
+ else
+ TDirectory.Delete(LPyRoot, true);
+
+ var LPyZip := TPythonLoad.GetPyZip();
+ if not TFile.Exists(LPyZip) then
+ raise Exception.Create('Python compressed distribution not found.');
+
+ TZipFile.ExtractZipFile(LPyZip, LPyRoot, AZipProgress);
+end;
+
+class function TPythonLoad.GetPyBin: string;
+begin
+ Result := TPath.Combine(GetPyHome(), 'bin');
+end;
+
+class function TPythonLoad.GetPyHome: string;
+begin
+ Result := TPath.Combine(GetPyRoot(), 'usr');
+end;
+
+class function TPythonLoad.GetPyLib: string;
+begin
+ Result := TPath.Combine(GetPyHome(), 'lib');
+end;
+
+class function TPythonLoad.GetPyRoot: string;
+begin
+ Result := TPath.Combine(TPath.GetDocumentsPath(), 'build');
+end;
+
+class function TPythonLoad.GetPyZip: string;
+begin
+ Result := TPath.Combine(TPath.GetDocumentsPath(), 'build.zip');
+end;
+
+class procedure TPythonLoad.Configure(const APythonEngine: TPythonEngine;
+ const ACheckPyLib: boolean);
+begin
+ if ACheckPyLib then begin
+ var LPyLibFile := TPath.Combine(TPath.GetLibraryPath(),
+ PYTHON_KNOWN_VERSIONS[PY_KNOWN_VER].DllName);
+
+ if not TFile.Exists(LPyLibFile) then
+ raise Exception.Create('Python library not found at application''s data folder.'
+ + #13#10
+ + LPyLibFile);
+ end;
+
+ APythonEngine.UseLastKnownVersion := false;
+ APythonEngine.ProgramName := TPythonLoad.GetPyBin();
+ APythonEngine.PythonHome := TPythonLoad.GetPyHome();
+ APythonEngine.RegVersion := PYTHON_KNOWN_VERSIONS[PY_KNOWN_VER].RegVersion;
+ APythonEngine.DllName := PYTHON_KNOWN_VERSIONS[PY_KNOWN_VER].DllName;
+ APythonEngine.APIVersion := PYTHON_KNOWN_VERSIONS[PY_KNOWN_VER].APIVersion;
+end;
+
+end.
diff --git a/Demos/FMX/Android/PyDistFinder/pydistfinder.dpr b/Demos/FMX/Android/PyDistFinder/pydistfinder.dpr
new file mode 100644
index 00000000..01dcf5e3
--- /dev/null
+++ b/Demos/FMX/Android/PyDistFinder/pydistfinder.dpr
@@ -0,0 +1,223 @@
+(**************************************************************************)
+(* *)
+(* Module: Unit 'pydistfinder' Copyright (c) 2021 *)
+(* *)
+(* Lucas Moura Belo - lmbelo *)
+(* lucas.belo@live.com *)
+(* Brazil *)
+(* *)
+(* PyScripter *)
+(* e-mail: pyscripter@gmail.com *)
+(* *)
+(* Project pages: https://github.com/Embarcadero/python4delphi *)
+(* https://github.com/pyscripter/python4delphi *)
+(**************************************************************************)
+(* Functionality: Python distribution compressor/uncompressor *)
+(* Making Python distribution available for Android *)
+(* *)
+(**************************************************************************)
+(* This source code is distributed with no WARRANTY, for no reason or use.*)
+(* Everyone is allowed to use and change this code free for his own tasks *)
+(* and projects, as long as this header and its copyright text is intact. *)
+(* For changed versions of this code, which are public distributed the *)
+(* following additional conditions have to be fullfilled: *)
+(* 1) The header has to contain a comment on the change and the author of *)
+(* it. *)
+(* 2) A copy of the changed source has to be sent to the above E-Mail *)
+(* address or my then valid address, if this is possible to the *)
+(* author. *)
+(* The second condition has the target to maintain an up to date central *)
+(* version of the component. If this condition is not acceptable for *)
+(* confidential or legal reasons, everyone is free to derive a component *)
+(* or to generate a diff file to my or other original sources. *)
+(**************************************************************************)
+
+program pydistfinder;
+
+{$APPTYPE CONSOLE}
+
+{$R *.res}
+
+uses
+ System.SysUtils,
+ System.IOUtils,
+ System.Zip;
+
+const
+ ZIP_CMD = 'ZIP';
+ UNZIP_CMD = 'UNZIP';
+ PYTHON_DIST_FOLDER_NAME = 'dist';
+ PYTHON_BUILD_FOLDER_NAME = 'build';
+ PYTHON_BUILD_ZIP_FILE_NAME = 'build.zip';
+
+function FindPythonDistFolder(AProjectPath: string): string;
+begin
+ //look for dist folder into project's dir
+ var LTarget := TPath.Combine(AProjectPath, PYTHON_DIST_FOLDER_NAME);
+ //go up until find dist folder or empty if not exists
+ while (AProjectPath <> String.Empty) and not TDirectory.Exists(LTarget) do begin
+ AProjectPath := TDirectory.GetParent(AProjectPath);
+ LTarget := TPath.Combine(AProjectPath, PYTHON_DIST_FOLDER_NAME)
+ end;
+
+ if TDirectory.Exists(LTarget) then
+ Result := LTarget
+ else
+ Result := String.Empty;
+end;
+
+function FindPythonTargetFolder(const ATargetPath, APlatform, AWithDebugSymbols: string): string;
+begin
+ Result := String.Empty;
+ if (not ATargetPath.IsEmpty()) then
+ WriteLn(Format('Python''s distribution folder found at: %s', [ATargetPath]))
+ else begin
+ WriteLn('Python''s distribution folder (dist) not found in project directory tree.');
+ ExitCode := 3;
+ Exit();
+ end;
+
+ Result := ATargetPath;
+
+ if (APlatform = 'arm') then begin
+ Result := TPath.Combine(Result, 'arm');
+ if (AWithDebugSymbols = 'true') then begin
+ Result := TPath.Combine(Result, 'Python3.9d')
+ end else begin
+ Result := TPath.Combine(Result, 'Python3.9');
+ end;
+ end else begin
+ Result := TPath.Combine(Result, 'aarch64');
+ if (AWithDebugSymbols = 'true') then begin
+ Result := TPath.Combine(Result, 'Python3.9d')
+ end else begin
+ Result := TPath.Combine(Result, 'Python3.9');
+ end;
+ end;
+end;
+
+procedure ZipFolder(const APath, APlatform, AWithDebugSymbols, AClear: string);
+begin
+ WriteLn('');
+ Writeln(Format('Compressing Python distribution', []));
+
+ var LCompressor := procedure(const ABuildPath, ABuildZipFile: string)
+ begin
+ Writeln(Format('Build folder is: %s', [ABuildPath]));
+ WriteLn('');
+ WriteLn('Compressing...');
+ WriteLn('');
+ TZipFile.ZipDirectoryContents(ABuildZipFile, ABuildPath);
+ WriteLn(Format('File created: %s', [ABuildZipFile]));
+ end;
+
+ var LBuildPath := TPath.Combine(APath, PYTHON_BUILD_FOLDER_NAME);
+ //Check for folder structure
+ if not TDirectory.Exists(LBuildPath) then begin
+ WriteLn('Invalid directory structure. Expected directory not found: ' + LBuildPath);
+ ExitCode := 2;
+ Exit();
+ end;
+
+ var LBuildZipFile := TPath.Combine(APath, PYTHON_BUILD_ZIP_FILE_NAME);
+ if TFile.Exists(LBuildZipFile) then begin
+ if (AClear = 'true') then begin
+ TFile.Delete(LBuildZipFile);
+ LCompressor(LBuildPath, LBuildZipFile);
+ end else begin
+ WriteLn('File already exists: ' + LBuildZipFile);
+ end;
+ end else
+ LCompressor(LBuildPath, LBuildZipFile);
+end;
+
+procedure UnzipFile(const APath, APlatform, AWithDebugSymbols, AClear: string);
+begin
+ WriteLn('');
+ Writeln(Format('Decompressing Python distribution', []));
+ WriteLn('');
+
+ var LDecompressor := procedure(const ABuildZipFile, ABuildPath: string)
+ begin
+ Writeln(Format('Build zip file is: %s', [ABuildZipFile]));
+ WriteLn('');
+ WriteLn('Decompressing...');
+ WriteLn('');
+ TZipFile.ExtractZipFile(ABuildZipFile, ABuildPath);
+ WriteLn(Format('Folder created: %s', [ABuildPath]));
+ end;
+
+ var LZipFile := TPath.Combine(APath, PYTHON_BUILD_ZIP_FILE_NAME);
+ //Check for folder structure
+ if not TFile.Exists(LZipFile) then begin
+ WriteLn('Invalid directory structure. Expected file not found: ' + LZipFile);
+ ExitCode := 2;
+ Exit();
+ end;
+
+ var LBuildPath := TPath.Combine(APath, PYTHON_BUILD_FOLDER_NAME);
+ if TDirectory.Exists(LBuildPath) then begin
+ if (AClear = 'true') then begin
+ TDirectory.Delete(LBuildPath, true);
+ LDecompressor(LZipFile, LBuildPath);
+ end else begin
+ WriteLn('Folder already exists: ' + LBuildPath);
+ end;
+ end else
+ LDecompressor(LZipFile, LBuildPath);
+end;
+
+procedure MakeDist(const ACmd, AProjectPath, APlatform, AWithDebugSymbols, AClear: string);
+begin
+ WriteLn('');
+ Writeln(Format('Command set to: %s', [ACmd]));
+ Writeln(Format('Platform set to: %s', [APlatform]));
+ Writeln(Format('With debug symbols set to: %s', [AWithDebugSymbols]));
+ Writeln(Format('Clear if exists set to: %s', [AClear]));
+ WriteLn('');
+
+ var LPath := FindPythonTargetFolder(FindPythonDistFolder(AProjectPath),
+ APlatform, AWithDebugSymbols);
+
+ if LPath.IsEmpty then
+ Exit();
+
+ if (ACmd = ZIP_CMD) then
+ ZipFolder(LPath, APlatform, AWithDebugSymbols, AClear)
+ else if (ACmd = UNZIP_CMD) then
+ UnzipFile(LPath, APlatform, AWithDebugSymbols, AClear);
+end;
+
+begin
+ try
+ WriteLn('');
+ WriteLn('');
+
+ WriteLn('#######################################################');
+ WriteLn('# #');
+ WriteLn('# Python4Delphi - Android #');
+ WriteLn('# #');
+ WriteLn('#######################################################');
+ WriteLn('# #');
+ WriteLn('# #');
+ WriteLn('# Python distribution #');
+ WriteLn('# finder #');
+ WriteLn('# #');
+ WriteLn('# #');
+ WriteLn('#######################################################');
+
+ WriteLn('');
+ WriteLn('');
+
+ if (ParamCount < 4) or (ParamCount > 5) then begin
+ WriteLn('Invalid parameters');
+ ExitCode := 1;
+ end else if ParamCount = 4 then
+ MakeDist(ParamStr(1), ParamStr(2), ParamStr(3), ParamStr(4), ParamStr(5))
+ else
+ MakeDist(ParamStr(1), ParamStr(2), ParamStr(3), ParamStr(4), 'false');
+ except
+ on E: Exception do
+ Writeln(E.ClassName, ': ', E.Message);
+ end;
+end.
diff --git a/Demos/FMX/Android/PyDistFinder/pydistfinder.dproj b/Demos/FMX/Android/PyDistFinder/pydistfinder.dproj
new file mode 100644
index 00000000..008421e8
--- /dev/null
+++ b/Demos/FMX/Android/PyDistFinder/pydistfinder.dproj
@@ -0,0 +1,1023 @@
+
+
+ {6AF6B9EC-BBEB-4C74-9FEC-0FFFD760DBB8}
+ 19.2
+ None
+ True
+ Release
+ Win32
+ 1
+ Console
+ pydistfinder.dpr
+
+
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Cfg_1
+ true
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Cfg_2
+ true
+ true
+
+
+ .\$(Platform)\$(Config)
+ .\bin
+ false
+ false
+ false
+ false
+ false
+ System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)
+ pydistfinder
+ 1033
+ CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
+
+
+ DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;bindcompfmx;fmx;FireDACIBDriver;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png
+ android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar
+
+
+ DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;bindcompfmx;fmx;FireDACIBDriver;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png
+ android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar
+
+
+ DBXSqliteDriver;RESTComponents;fmxase;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;bindcompfmx;fmx;FireDACIBDriver;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
+
+
+ DBXSqliteDriver;RESTComponents;fmxase;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;bindcompfmx;fmx;FireDACIBDriver;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
+
+
+ RESTComponents;emsclientfiredac;DataSnapFireDAC;FireDACADSDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;inetdb;emsedge;fmx;FireDACIBDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;DataSnapConnectors;soapserver;bindengine;CloudService;FireDACOracleDriver;FireDACMySQLDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;IndySystem;FireDACDb2Driver;FireDACInfxDriver;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;FireDACASADriver;FireDACTDataDriver;soaprtl;DbxCommonDriver;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;rtl;emsserverresource;DbxClientDriver;CustomIPTransport;bindcomp;dbxcds;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;dbrtl;IndyProtocols;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage)
+
+
+ DBXSqliteDriver;RESTComponents;fmxase;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;FireDACMSSQLDriver;bindcompfmx;DBXOracleDriver;inetdb;fmx;FireDACIBDriver;fmxdae;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;DBXMySQLDriver;CloudService;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FireDACPgDriver;FireDACASADriver;FireDACTDataDriver;soaprtl;DbxCommonDriver;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;FireDACDSDriver;rtl;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;bindcomp;DBXInformixDriver;IndyIPClient;dbxcds;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage)
+ true
+
+
+ DBXSqliteDriver;RESTComponents;fmxase;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;bindcompvclsmp;emsclientfiredac;tethering;svnui;DataSnapFireDAC;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;svn;DBXOracleDriver;inetdb;emsedge;fmx;FireDACIBDriver;fmxdae;vcledge;FireDACDBXDriver;dbexpress;IndyCore;vclx;Python;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;vcl;IndyIPServer;DBXSybaseASEDriver;IndySystem;FireDACDb2Driver;bindcompvclwinx;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;soaprtl;DbxCommonDriver;PythonVcl;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;FireDACDSDriver;rtl;emsserverresource;DbxClientDriver;PythonFmx;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage)
+ Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
+ Debug
+ CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
+ 1033
+ true
+ $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
+ $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
+
+
+ DBXSqliteDriver;RESTComponents;fmxase;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;bindcompvclsmp;emsclientfiredac;tethering;DataSnapFireDAC;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;DBXOracleDriver;inetdb;emsedge;fmx;FireDACIBDriver;fmxdae;vcledge;FireDACDBXDriver;dbexpress;IndyCore;vclx;Python;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;vcl;IndyIPServer;DBXSybaseASEDriver;IndySystem;FireDACDb2Driver;bindcompvclwinx;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;soaprtl;DbxCommonDriver;PythonVcl;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;FireDACDSDriver;rtl;emsserverresource;DbxClientDriver;PythonFmx;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage)
+ true
+ $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
+ $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
+
+
+ DEBUG;$(DCC_Define)
+ true
+ false
+ true
+ true
+ true
+
+
+ false
+
+
+ false
+ RELEASE;$(DCC_Define)
+ 0
+ 0
+
+
+ 1033
+ (None)
+
+
+
+ MainSource
+
+
+ Cfg_2
+ Base
+
+
+ Base
+
+
+ Cfg_1
+ Base
+
+
+
+ Delphi.Personality.12
+ Application
+
+
+
+ pydistfinder.dpr
+
+
+ Microsoft Office 2000 Sample Automation Server Wrapper Components
+ Microsoft Office XP Sample Automation Server Wrapper Components
+
+
+
+
+
+ true
+
+
+
+
+ true
+
+
+
+
+ true
+
+
+
+
+ pydistfinder.exe
+ true
+
+
+
+
+ pydistfinder.exe
+ true
+
+
+
+
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ 0
+
+
+
+
+ classes
+ 1
+
+
+ classes
+ 1
+
+
+
+
+ res\xml
+ 1
+
+
+ res\xml
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+
+
+ library\lib\armeabi
+ 1
+
+
+ library\lib\armeabi
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+
+
+ library\lib\mips
+ 1
+
+
+ library\lib\mips
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+ library\lib\arm64-v8a
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+
+
+ res\drawable
+ 1
+
+
+ res\drawable
+ 1
+
+
+
+
+ res\values
+ 1
+
+
+ res\values
+ 1
+
+
+
+
+ res\values-v21
+ 1
+
+
+ res\values-v21
+ 1
+
+
+
+
+ res\values
+ 1
+
+
+ res\values
+ 1
+
+
+
+
+ res\drawable
+ 1
+
+
+ res\drawable
+ 1
+
+
+
+
+ res\drawable-xxhdpi
+ 1
+
+
+ res\drawable-xxhdpi
+ 1
+
+
+
+
+ res\drawable-xxxhdpi
+ 1
+
+
+ res\drawable-xxxhdpi
+ 1
+
+
+
+
+ res\drawable-ldpi
+ 1
+
+
+ res\drawable-ldpi
+ 1
+
+
+
+
+ res\drawable-mdpi
+ 1
+
+
+ res\drawable-mdpi
+ 1
+
+
+
+
+ res\drawable-hdpi
+ 1
+
+
+ res\drawable-hdpi
+ 1
+
+
+
+
+ res\drawable-xhdpi
+ 1
+
+
+ res\drawable-xhdpi
+ 1
+
+
+
+
+ res\drawable-mdpi
+ 1
+
+
+ res\drawable-mdpi
+ 1
+
+
+
+
+ res\drawable-hdpi
+ 1
+
+
+ res\drawable-hdpi
+ 1
+
+
+
+
+ res\drawable-xhdpi
+ 1
+
+
+ res\drawable-xhdpi
+ 1
+
+
+
+
+ res\drawable-xxhdpi
+ 1
+
+
+ res\drawable-xxhdpi
+ 1
+
+
+
+
+ res\drawable-xxxhdpi
+ 1
+
+
+ res\drawable-xxxhdpi
+ 1
+
+
+
+
+ res\drawable-small
+ 1
+
+
+ res\drawable-small
+ 1
+
+
+
+
+ res\drawable-normal
+ 1
+
+
+ res\drawable-normal
+ 1
+
+
+
+
+ res\drawable-large
+ 1
+
+
+ res\drawable-large
+ 1
+
+
+
+
+ res\drawable-xlarge
+ 1
+
+
+ res\drawable-xlarge
+ 1
+
+
+
+
+ res\values
+ 1
+
+
+ res\values
+ 1
+
+
+
+
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ 0
+
+
+
+
+ Contents\MacOS
+ 1
+ .framework
+
+
+ Contents\MacOS
+ 1
+ .framework
+
+
+ 0
+
+
+
+
+ 1
+ .dylib
+
+
+ 1
+ .dylib
+
+
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ 0
+ .dll;.bpl
+
+
+
+
+ 1
+ .dylib
+
+
+ 1
+ .dylib
+
+
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ 0
+ .bpl
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ Contents\Resources\StartUp\
+ 0
+
+
+ Contents\Resources\StartUp\
+ 0
+
+
+ 0
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
+ 1
+
+
+ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
+ 1
+
+
+
+
+ ..\
+ 1
+
+
+ ..\
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen
+ 64
+
+
+ ..\$(PROJECTNAME).launchscreen
+ 64
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
+ 1
+
+
+
+
+ ..\
+ 1
+
+
+ ..\
+ 1
+
+
+
+
+ Contents
+ 1
+
+
+ Contents
+ 1
+
+
+
+
+ Contents\Resources
+ 1
+
+
+ Contents\Resources
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+ library\lib\arm64-v8a
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ 0
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+
+
+ Assets
+ 1
+
+
+ Assets
+ 1
+
+
+
+
+ Assets
+ 1
+
+
+ Assets
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+ False
+ False
+ False
+ False
+ False
+ True
+ False
+
+
+ 12
+
+
+
+
+
diff --git a/Demos/FMX/Android/dist/aarch64/Python3.9/build.zip b/Demos/FMX/Android/dist/aarch64/Python3.9/build.zip
new file mode 100644
index 00000000..6bc0df08
Binary files /dev/null and b/Demos/FMX/Android/dist/aarch64/Python3.9/build.zip differ
diff --git a/Demos/FMX/Android/dist/aarch64/Python3.9d/build.zip b/Demos/FMX/Android/dist/aarch64/Python3.9d/build.zip
new file mode 100644
index 00000000..8951bb31
Binary files /dev/null and b/Demos/FMX/Android/dist/aarch64/Python3.9d/build.zip differ
diff --git a/Demos/FMX/Android/dist/arm/Python3.9/build.zip b/Demos/FMX/Android/dist/arm/Python3.9/build.zip
new file mode 100644
index 00000000..61a9aae3
Binary files /dev/null and b/Demos/FMX/Android/dist/arm/Python3.9/build.zip differ
diff --git a/Demos/FMX/Android/dist/arm/Python3.9d/build.zip b/Demos/FMX/Android/dist/arm/Python3.9d/build.zip
new file mode 100644
index 00000000..34e76d58
Binary files /dev/null and b/Demos/FMX/Android/dist/arm/Python3.9d/build.zip differ
diff --git a/Modules/BuildAllModules.bat b/Modules/BuildAllModules.bat
new file mode 100644
index 00000000..685e4e3f
--- /dev/null
+++ b/Modules/BuildAllModules.bat
@@ -0,0 +1,11 @@
+@echo off
+call rsvars.bat
+msbuild /t:Clean /t:Build /p:config=Release /p:platform=Win32 DelphiVCL/DelphiVCL.dproj
+msbuild /t:Clean /t:Build /p:config=Release /p:platform=Win64 DelphiVCL/DelphiVCL.dproj
+msbuild /t:Clean /t:Build /p:config=Release /p:platform=Win32 DelphiFMX/DelphiFMX.dproj
+msbuild /t:Clean /t:Build /p:config=Release /p:platform=Win64 DelphiFMX/DelphiFMX.dproj
+msbuild /t:Clean /t:Build /p:config=Release /p:platform=Android DelphiFMX/DelphiFMX.dproj
+msbuild /t:Clean /t:Build /p:config=Release /p:platform=Android64 DelphiFMX/DelphiFMX.dproj
+msbuild /t:Clean /t:Build /p:config=Release /p:platform=Linux64 DelphiFMX/DelphiFMX.dproj
+msbuild /t:Clean /t:Build /p:config=Release /p:platform=OSX32 DelphiFMX/DelphiFMX.dproj
+msbuild /t:Clean /t:Build /p:config=Release /p:platform=OSX64 DelphiFMX/DelphiFMX.dproj
diff --git a/Modules/BuildAllVersions.bat b/Modules/BuildAllVersions.bat
new file mode 100644
index 00000000..06381ef7
--- /dev/null
+++ b/Modules/BuildAllVersions.bat
@@ -0,0 +1,31 @@
+@echo off
+call rsvars.bat
+for /L %%G in (4,1,7) do (
+ echo %%G > DelphiFMX\PythonVersionIndex.inc
+ echo %%G > DelphiVCL\PythonVersionIndex.inc
+ rmdir /s /q DelphiFMX\pyd%%G >nul
+ rmdir /s /q DelphiVCL\pyd%%G >nul
+ Echo VCL Win32 Index %%G
+ msbuild /nologo /v:m /t:Clean /t:Build /p:config=Release /p:platform=Win32 DelphiVCL/DelphiVCL.dproj
+ Echo VCL Win64 Index %%G
+ msbuild /nologo /v:m /t:Clean /t:Build /p:config=Release /p:platform=Win64 DelphiVCL/DelphiVCL.dproj
+ echo FMX Win32 Index %%G
+ msbuild /nologo /v:m /t:Clean /t:Build /p:config=Release /p:platform=Win32 DelphiFMX/DelphiFMX.dproj
+ Echo FMX Win64 Index %%G
+ msbuild /nologo /v:m /t:Clean /t:Build /p:config=Release /p:platform=Win64 DelphiFMX/DelphiFMX.dproj
+ if %%G==7 (
+ echo FMX Android 32-bit Index %%G
+ msbuild /nologo /v:m /t:Clean /t:Build /p:config=Release /p:platform=Android DelphiFMX/DelphiFMX.dproj
+ echo FMX Android 64-bit Index %%G
+ msbuild /nologo /v:m /t:Clean /t:Build /p:config=Release /p:platform=Android64 DelphiFMX/DelphiFMX.dproj
+ )
+ echo FMX Linux64 Index %%G
+ msbuild /nologo /v:m /t:Clean /t:Build /p:config=Release /p:platform=Linux64 DelphiFMX/DelphiFMX.dproj
+rem echo FMX OSX32 Index %%G
+rem msbuild /nologo /v:m /t:Clean /t:Build /p:config=Release /p:platform=OSX32 DelphiFMX/DelphiFMX.dproj
+ echo FMX OSX64 Index %%G
+ msbuild /nologo /v:m /t:Clean /t:Build /p:config=Release /p:platform=OSX64 DelphiFMX/DelphiFMX.dproj
+
+ ren DelphiFMX\pyd pyd%%G
+ ren DelphiVCL\pyd pyd%%G
+)
\ No newline at end of file
diff --git a/Modules/DelphiFMX/AndroidManifest.template.xml b/Modules/DelphiFMX/AndroidManifest.template.xml
new file mode 100644
index 00000000..10c95df9
--- /dev/null
+++ b/Modules/DelphiFMX/AndroidManifest.template.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+ <%uses-permission%>
+
+
+
+ <%provider%>
+ <%application-meta-data%>
+ <%uses-libraries%>
+ <%services%>
+
+
+
+
+
+
+
+
+
+ <%activity%>
+ <%receivers%>
+
+
+
diff --git a/Modules/DelphiFMX/DelphiFMX.dproj b/Modules/DelphiFMX/DelphiFMX.dproj
index 12e25d06..a23bc18c 100644
--- a/Modules/DelphiFMX/DelphiFMX.dproj
+++ b/Modules/DelphiFMX/DelphiFMX.dproj
@@ -5,14 +5,29 @@
Release
None
DelphiFMX.dpr
- Win64
+ Linux64
{0C4154A5-D276-4D62-BA30-564FACD77917}
- 19.1
- 3
+ 19.2
+ 37011
true
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
true
Base
@@ -28,11 +43,29 @@
Base
true
+
+ true
+ Cfg_1
+ true
+ true
+
+
+ true
+ Cfg_1
+ true
+ true
+
true
Base
true
+
+ true
+ Cfg_2
+ true
+ true
+
true
Cfg_2
@@ -41,12 +74,31 @@
DelphiFMX
+ .\dcu\$(Config)\$(Platform)
+ .\pyd\$(Config)\$(Platform)
00400000
System;Xml;Data;Datasnap;Web;Soap;Vcl;$(DCC_Namespace)
+ ..\..\Source;..\..\Source\fmx;..\..\Source\vcl;$(DCC_UnitSearchPath)
true
CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=
1033
+
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png
+ Debug
+ android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar
+ package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=
+
+
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png
+ Debug
+ android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar
+ package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=
+
+
+ Debug
+ CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSCameraUsageDescription=The reason for accessing the camera;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSMotionUsageDescription=The reason for accessing the accelerometer;NSDesktopFolderUsageDescription=The reason for accessing the Desktop folder;NSDocumentsFolderUsageDescription=The reason for accessing the Documents folder;NSDownloadsFolderUsageDescription=The reason for accessing the Downloads folder;NSNetworkVolumesUsageDescription=The reason for accessing files on a network volume;NSRemovableVolumesUsageDescription=The reason for accessing files on a removable volume;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers
+
Debug
Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
@@ -61,11 +113,22 @@
false
0
+
+ #000000
+ 1
+ package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=
+
+
+ (None)
+
DEBUG;$(DCC_Define)
true
false
+
+ true
+
(None)
@@ -74,6 +137,7 @@
MainSource
+
Base
@@ -96,716 +160,11 @@
-
-
-
- true
-
-
-
-
- true
-
-
-
-
- true
-
-
-
-
- DelphiFMX.dll
- true
-
-
-
-
- 1
-
-
- 0
-
-
-
-
- classes
- 1
-
-
- classes
- 1
-
-
-
-
- res\xml
- 1
-
-
- res\xml
- 1
-
-
-
-
- library\lib\armeabi-v7a
- 1
-
-
-
-
- library\lib\armeabi
- 1
-
-
- library\lib\armeabi
- 1
-
-
-
-
- library\lib\armeabi-v7a
- 1
-
-
-
-
- library\lib\mips
- 1
-
-
- library\lib\mips
- 1
-
-
-
-
- library\lib\armeabi-v7a
- 1
-
-
- library\lib\arm64-v8a
- 1
-
-
-
-
- library\lib\armeabi-v7a
- 1
-
-
-
-
- res\drawable
- 1
-
-
- res\drawable
- 1
-
-
-
-
- res\values
- 1
-
-
- res\values
- 1
-
-
-
-
- res\values-v21
- 1
-
-
- res\values-v21
- 1
-
-
-
-
- res\values
- 1
-
-
- res\values
- 1
-
-
-
-
- res\drawable
- 1
-
-
- res\drawable
- 1
-
-
-
-
- res\drawable-xxhdpi
- 1
-
-
- res\drawable-xxhdpi
- 1
-
-
-
-
- res\drawable-ldpi
- 1
-
-
- res\drawable-ldpi
- 1
-
-
-
-
- res\drawable-mdpi
- 1
-
-
- res\drawable-mdpi
- 1
-
-
-
-
- res\drawable-hdpi
- 1
-
-
- res\drawable-hdpi
- 1
-
-
-
-
- res\drawable-xhdpi
- 1
-
-
- res\drawable-xhdpi
- 1
-
-
-
-
- res\drawable-mdpi
- 1
-
-
- res\drawable-mdpi
- 1
-
-
-
-
- res\drawable-hdpi
- 1
-
-
- res\drawable-hdpi
- 1
-
-
-
-
- res\drawable-xhdpi
- 1
-
-
- res\drawable-xhdpi
- 1
-
-
-
-
- res\drawable-xxhdpi
- 1
-
-
- res\drawable-xxhdpi
- 1
-
-
-
-
- res\drawable-xxxhdpi
- 1
-
-
- res\drawable-xxxhdpi
- 1
-
-
-
-
- res\drawable-small
- 1
-
-
- res\drawable-small
- 1
-
-
-
-
- res\drawable-normal
- 1
-
-
- res\drawable-normal
- 1
-
-
-
-
- res\drawable-large
- 1
-
-
- res\drawable-large
- 1
-
-
-
-
- res\drawable-xlarge
- 1
-
-
- res\drawable-xlarge
- 1
-
-
-
-
- res\values
- 1
-
-
- res\values
- 1
-
-
-
-
- 1
-
-
- 1
-
-
- 0
-
-
-
-
- 1
- .framework
-
-
- 1
- .framework
-
-
- 0
-
-
-
-
- 1
- .dylib
-
-
- 1
- .dylib
-
-
- 0
- .dll;.bpl
-
-
-
-
- 1
- .dylib
-
-
- 1
- .dylib
-
-
- 1
- .dylib
-
-
- 1
- .dylib
-
-
- 1
- .dylib
-
-
- 0
- .bpl
-
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
- 1
-
-
- 1
-
-
-
-
-
-
-
- Contents\Resources
- 1
-
-
- Contents\Resources
- 1
-
-
-
-
- library\lib\armeabi-v7a
- 1
-
-
- library\lib\arm64-v8a
- 1
-
-
- 1
-
-
- 1
-
-
- 1
-
-
- 1
-
-
- 1
-
-
- 1
-
-
- 0
-
-
-
-
- library\lib\armeabi-v7a
- 1
-
-
-
-
- 1
-
-
- 1
-
-
-
-
- ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
- 1
-
-
- ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
- 1
-
-
-
-
-
-
-
- 1
-
-
- 1
-
-
- 1
-
-
-
-
- Assets
- 1
-
-
- Assets
- 1
-
-
-
-
- Assets
- 1
-
-
- Assets
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
-
-
-
-
-
-
-
-
-
- False
- False
- False
- False
+ True
+ True
+ True
+ True
True
True
False
diff --git a/Modules/DelphiFMX/PythonVersionIndex.inc b/Modules/DelphiFMX/PythonVersionIndex.inc
new file mode 100644
index 00000000..3169c05c
--- /dev/null
+++ b/Modules/DelphiFMX/PythonVersionIndex.inc
@@ -0,0 +1 @@
+7
diff --git a/Modules/DelphiFMX/uMain.pas b/Modules/DelphiFMX/uMain.pas
index d8f16cfa..022ff255 100644
--- a/Modules/DelphiFMX/uMain.pas
+++ b/Modules/DelphiFMX/uMain.pas
@@ -25,8 +25,9 @@ function PyInit_DelphiFMX: PPyObject;
gEngine.AutoFinalize := False;
gEngine.UseLastKnownVersion := False;
// Adapt to the desired python version - Will only work with this version
- gEngine.RegVersion := '3.9';
- gEngine.DllName := 'python39.dll';
+ var PythonVersionIndex := {$I PythonVersionIndex.inc}; // 7 = 3.9
+ gEngine.RegVersion := PYTHON_KNOWN_VERSIONS[PythonVersionIndex].RegVersion;
+ gEngine.DllName := PYTHON_KNOWN_VERSIONS[PythonVersionIndex].DllName;
gModule := TPythonModule.Create(nil);
gModule.Engine := gEngine;
diff --git a/Modules/DelphiVCL/DelphiVCL.dproj b/Modules/DelphiVCL/DelphiVCL.dproj
index a83e4c47..c4794793 100644
--- a/Modules/DelphiVCL/DelphiVCL.dproj
+++ b/Modules/DelphiVCL/DelphiVCL.dproj
@@ -5,9 +5,9 @@
Release
None
DelphiVCL.dpr
- Win64
+ Win32
{7E56095C-46B8-4F28-87A2-EEA8D9D2448D}
- 19.1
+ 19.2
3
@@ -28,6 +28,18 @@
Base
true
+
+ true
+ Cfg_1
+ true
+ true
+
+
+ true
+ Cfg_1
+ true
+ true
+
true
Base
@@ -41,15 +53,21 @@
DelphiVCL
+ .\dcu\$(Config)\$(Platform)
+ .\pyd\$(Config)\$(Platform)
00400000
System;Xml;Data;Datasnap;Web;Soap;Vcl;$(DCC_Namespace)
+ ..\..\Source;..\..\Source\VCL;$(DCC_UnitSearchPath)
true
CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=
1033
Debug
+ .\dcu\$(Config)\$(Platform)
+ .\pyd\$(Config)\$(Platform)
Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
+ (None)
Debug
@@ -61,6 +79,12 @@
false
0
+
+ (None)
+
+
+ (None)
+
DEBUG;$(DCC_Define)
true
@@ -96,714 +120,15 @@
-
-
-
- true
-
-
-
-
- true
-
-
-
-
- true
-
-
-
-
- DelphiVCL.dll
- true
-
-
-
-
- 1
-
-
- 0
-
-
-
-
- classes
- 1
-
-
- classes
- 1
-
-
-
-
- res\xml
- 1
-
-
- res\xml
- 1
-
-
-
-
- library\lib\armeabi-v7a
- 1
-
-
-
-
- library\lib\armeabi
- 1
-
-
- library\lib\armeabi
- 1
-
-
-
-
- library\lib\armeabi-v7a
- 1
-
-
-
-
- library\lib\mips
- 1
-
-
- library\lib\mips
- 1
-
-
-
-
- library\lib\armeabi-v7a
- 1
-
-
- library\lib\arm64-v8a
- 1
-
-
-
-
- library\lib\armeabi-v7a
- 1
-
-
-
-
- res\drawable
- 1
-
-
- res\drawable
- 1
-
-
-
-
- res\values
- 1
-
-
- res\values
- 1
-
-
-
-
- res\values-v21
- 1
-
-
- res\values-v21
- 1
-
-
-
-
- res\values
- 1
-
-
- res\values
- 1
-
-
-
-
- res\drawable
- 1
-
-
- res\drawable
- 1
-
-
-
-
- res\drawable-xxhdpi
- 1
-
-
- res\drawable-xxhdpi
- 1
-
-
-
-
- res\drawable-ldpi
- 1
-
-
- res\drawable-ldpi
- 1
-
-
-
-
- res\drawable-mdpi
- 1
-
-
- res\drawable-mdpi
- 1
-
-
-
-
- res\drawable-hdpi
- 1
-
-
- res\drawable-hdpi
- 1
-
-
-
-
- res\drawable-xhdpi
- 1
-
-
- res\drawable-xhdpi
- 1
-
-
-
-
- res\drawable-mdpi
- 1
-
-
- res\drawable-mdpi
- 1
-
-
-
-
- res\drawable-hdpi
- 1
-
-
- res\drawable-hdpi
- 1
-
-
-
-
- res\drawable-xhdpi
- 1
-
-
- res\drawable-xhdpi
- 1
-
-
-
-
- res\drawable-xxhdpi
- 1
-
-
- res\drawable-xxhdpi
- 1
-
-
-
-
- res\drawable-xxxhdpi
- 1
-
-
- res\drawable-xxxhdpi
- 1
-
-
-
-
- res\drawable-small
- 1
-
-
- res\drawable-small
- 1
-
-
-
-
- res\drawable-normal
- 1
-
-
- res\drawable-normal
- 1
-
-
-
-
- res\drawable-large
- 1
-
-
- res\drawable-large
- 1
-
-
-
-
- res\drawable-xlarge
- 1
-
-
- res\drawable-xlarge
- 1
-
-
-
-
- res\values
- 1
-
-
- res\values
- 1
-
-
-
-
- 1
-
-
- 1
-
-
- 0
-
-
-
-
- 1
- .framework
-
-
- 1
- .framework
-
-
- 0
-
-
-
-
- 1
- .dylib
-
-
- 1
- .dylib
-
-
- 0
- .dll;.bpl
-
-
-
-
- 1
- .dylib
-
-
- 1
- .dylib
-
-
- 1
- .dylib
-
-
- 1
- .dylib
-
-
- 1
- .dylib
-
-
- 0
- .bpl
-
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
- 1
-
-
- 1
-
-
-
-
-
-
-
- Contents\Resources
- 1
-
-
- Contents\Resources
- 1
-
-
-
-
- library\lib\armeabi-v7a
- 1
-
-
- library\lib\arm64-v8a
- 1
-
-
- 1
-
-
- 1
-
-
- 1
-
-
- 1
-
-
- 1
-
-
- 1
-
-
- 0
-
-
-
-
- library\lib\armeabi-v7a
- 1
-
-
-
-
- 1
-
-
- 1
-
-
-
-
- ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
- 1
-
-
- ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
- 1
-
-
-
-
-
-
-
- 1
-
-
- 1
-
-
- 1
-
-
-
-
- Assets
- 1
-
-
- Assets
- 1
-
-
-
-
- Assets
- 1
-
-
- Assets
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
- ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
- 1
-
-
-
-
-
-
-
-
-
-
-
-
-
+ False
+ False
+ False
+ False
True
True
+ False
+ False
12
diff --git a/Modules/DelphiVCL/PythonVersionIndex.inc b/Modules/DelphiVCL/PythonVersionIndex.inc
new file mode 100644
index 00000000..3169c05c
--- /dev/null
+++ b/Modules/DelphiVCL/PythonVersionIndex.inc
@@ -0,0 +1 @@
+7
diff --git a/Modules/DelphiVCL/uMain.pas b/Modules/DelphiVCL/uMain.pas
index 06d82d7a..b8d63e9d 100644
--- a/Modules/DelphiVCL/uMain.pas
+++ b/Modules/DelphiVCL/uMain.pas
@@ -25,8 +25,9 @@ function PyInit_DelphiVCL: PPyObject;
gEngine.AutoFinalize := False;
gEngine.UseLastKnownVersion := False;
// Adapt to the desired python version - Will only work with this version
- gEngine.RegVersion := '3.9';
- gEngine.DllName := 'python39.dll';
+ var PythonVersionIndex := {$I PythonVersionIndex.inc}; // 7 = 3.9
+ gEngine.RegVersion := PYTHON_KNOWN_VERSIONS[PythonVersionIndex].RegVersion;
+ gEngine.DllName := PYTHON_KNOWN_VERSIONS[PythonVersionIndex].DllName;
gModule := TPythonModule.Create(nil);
gModule.Engine := gEngine;
diff --git a/Modules/PythonFMXandVCL.groupproj b/Modules/PythonFMXandVCL.groupproj
new file mode 100644
index 00000000..d0e15de4
--- /dev/null
+++ b/Modules/PythonFMXandVCL.groupproj
@@ -0,0 +1,48 @@
+
+
+ {8CE82B03-1B21-45C9-8091-DF9D8A8F4E5C}
+
+
+
+
+
+
+
+
+
+
+ Default.Personality.12
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Packages/Delphi/Delphi 10.4+/Python.dpk b/Packages/Delphi/Delphi 10.4+/Python.dpk
index c54cf2e1..e5bb898f 100644
--- a/Packages/Delphi/Delphi 10.4+/Python.dpk
+++ b/Packages/Delphi/Delphi 10.4+/Python.dpk
@@ -45,6 +45,8 @@ contains
WrapDelphiClasses in '..\..\..\Source\WrapDelphiClasses.pas',
WrapDelphiTypes in '..\..\..\Source\WrapDelphiTypes.pas',
WrapDelphiWindows in '..\..\..\Source\WrapDelphiWindows.pas',
- WrapFireDAC in '..\..\..\Source\WrapFireDAC.pas';
+ WrapFireDAC in '..\..\..\Source\WrapFireDAC.pas',
+ WrapActions in '..\..\..\Source\WrapActions.pas',
+ WrapActionList in '..\..\..\Source\WrapActionList.pas';
end.
diff --git a/Packages/Delphi/Delphi 10.4+/PythonFmx.dpk b/Packages/Delphi/Delphi 10.4+/PythonFmx.dpk
index 5bce1043..7b9673f8 100644
--- a/Packages/Delphi/Delphi 10.4+/PythonFmx.dpk
+++ b/Packages/Delphi/Delphi 10.4+/PythonFmx.dpk
@@ -50,6 +50,7 @@ contains
WrapFmxTypes in '..\..\..\Source\fmx\WrapFmxTypes.pas',
WrapDelphiFmx in '..\..\..\Source\fmx\WrapDelphiFmx.pas',
WrapFmxEdit in '..\..\..\Source\fmx\WrapFmxEdit.pas',
- WrapFmxListBox in '..\..\..\Source\fmx\WrapFmxListBox.pas';
+ WrapFmxListBox in '..\..\..\Source\fmx\WrapFmxListBox.pas',
+ WrapFmxMedia in '..\..\..\Source\fmx\WrapFmxMedia.pas';
end.
diff --git a/Packages/Delphi/Delphi 10.4+/PythonVcl.dpk b/Packages/Delphi/Delphi 10.4+/PythonVcl.dpk
index 0cdecfd5..8ef5f7e3 100644
--- a/Packages/Delphi/Delphi 10.4+/PythonVcl.dpk
+++ b/Packages/Delphi/Delphi 10.4+/PythonVcl.dpk
@@ -34,7 +34,9 @@ requires
rtl,
vcl,
Python,
- VclSmp;
+ VclSmp,
+ vclimg,
+ vclwinx;
contains
Vcl.PythonGUIInputOutput in '..\..\..\Source\vcl\Vcl.PythonGUIInputOutput.pas',
@@ -49,6 +51,8 @@ contains
WrapVclGraphics in '..\..\..\Source\vcl\WrapVclGraphics.pas',
WrapVclGrids in '..\..\..\Source\vcl\WrapVclGrids.pas',
WrapVclSamplesSpin in '..\..\..\Source\vcl\WrapVclSamplesSpin.pas',
- WrapVclStdCtrls in '..\..\..\Source\vcl\WrapVclStdCtrls.pas';
+ WrapVclStdCtrls in '..\..\..\Source\vcl\WrapVclStdCtrls.pas',
+ WrapVclWinXCtrls in '..\..\..\Source\vcl\WrapVclWinXCtrls.pas',
+ WrapVclThemes in '..\..\..\Source\vcl\WrapVclThemes.pas';
end.
diff --git a/Source/Definition.Inc b/Source/Definition.Inc
index 8e0b05e2..f65eb914 100644
--- a/Source/Definition.Inc
+++ b/Source/Definition.Inc
@@ -219,6 +219,10 @@
{$ENDIF UNIX}
{$ENDIF FPC}
+{$IFDEF CPU64BITS}
+ {$DEFINE CPUX64}
+{$ENDIF}
+
{$IFDEF DELPHIXE_OR_HIGHER}
{$DEFINE EXTENDED_RTTI}
{$ENDIF DELPHIXE_OR_HIGHER}
diff --git a/Source/MethodCallBack.pas b/Source/MethodCallBack.pas
index 1d242308..d4f0fbd1 100644
--- a/Source/MethodCallBack.pas
+++ b/Source/MethodCallBack.pas
@@ -17,6 +17,7 @@
(* Morgan Martinet (p4d@mmm-experts.com) *)
(* Samuel Iseli (iseli@vertec.ch) *)
(* Andrey Gruzdev (andrey.gruzdev@gmail.com) *)
+(* Lucas Belo (lucas.belo@live.com) *)
(**************************************************************************)
(* This source code is distributed with no WARRANTY, for no reason or use.*)
(* Everyone is allowed to use and change this code free, as long as this *)
@@ -32,7 +33,7 @@ interface
uses SysUtils;
type
- TCallType = (ctSTDCALL, ctCDECL);
+ TCallType = (ctSTDCALL, ctCDECL, ctARMSTD);
TCallBack = procedure of object;
function GetCallBack( self: TObject; method: Pointer;
@@ -258,6 +259,34 @@ function CodeMemPageCount: integer;
end;
end;
+procedure DeleteCallBack( Proc: Pointer);
+begin
+ FreeCodeMem(Proc);
+end;
+
+procedure FreeCallBacks;
+var
+ page, nextpage: PCodeMemPage;
+begin
+ // free each allocated page
+ page := CodeMemPages;
+ while page <> nil do
+ begin
+ nextpage := page^.Next;
+
+ // free the memory
+ {$IFDEF MSWINDOWS}
+ VirtualFree(page, 0, MEM_RELEASE);
+ {$ELSE}
+ //FreeMem(page);
+ munmap(page,PageSize);
+ {$ENDIF}
+
+ page := nextpage;
+ end;
+ CodeMemPages := nil;
+end;
+
function GetOfObjectCallBack( CallBack: TCallBack;
argnum: Integer; calltype: TCallType): Pointer;
begin
@@ -266,15 +295,17 @@ function GetOfObjectCallBack( CallBack: TCallBack;
argnum, calltype);
end;
-{$IFDEF CPUX64}
-{$DEFINE 64_BIT_CALLBACK}
-{$ELSE}
-{$IFDEF MACOS}
-{$DEFINE ALIGNED_32_BIT_CALLBACK}
-{$ELSE}
-{$DEFINE SIMPLE_32_BIT_CALLBACK}
-{$ENDIF MACOS}
-{$ENDIF CPUX64}
+{$IFNDEF CPUARM}
+ {$IFDEF CPUX64}
+ {$DEFINE 64_BIT_CALLBACK}
+ {$ELSE}
+ {$IFDEF MACOS}
+ {$DEFINE ALIGNED_32_BIT_CALLBACK}
+ {$ELSE}
+ {$DEFINE SIMPLE_32_BIT_CALLBACK}
+ {$ENDIF MACOS}
+ {$ENDIF CPUX64}
+{$ENDIF CPUARM}
{$IFDEF SIMPLE_32_BIT_CALLBACK}
// win32 inplementation
@@ -565,35 +596,126 @@ function GetCallBack( self: TObject; method: Pointer;
end;
{$ENDIF}
-procedure DeleteCallBack( Proc: Pointer);
+{$IFDEF CPUARM32}
+function GetCallBack(Self: TObject; Method: Pointer; ArgNum: Integer;
+ CallType: TCallType): Pointer;
+const
+ S1: array[0..123] of byte = (
+//big-endian
+//offset :
+ {+ 0:} $80, $40, $2d, $e9, // push {r7, lr}
+ {+ 4:} $0d, $70, $a0, $e1, // mov r7, sp
+ {+ 8:} $1e, $04, $2d, $e9, // push {r1, r2, r3, r4, sl}
+ {+ c:} $5c, $40, $9f, $e5, // ldr r4, [pc, #92] ; 70
+ {+ 10:} $00, $00, $54, $e3, // cmp r4, #0
+ {+ 14:} $04, $d0, $4d, $c0, // subgt sp, sp, r4
+ {+ 18:} $04, $50, $a0, $c1, // movgt r5, r4
+ {+ 1c:} $04, $50, $85, $c2, // addgt r5, r5, #4
+ {+ 20:} $04, $60, $a0, $c1, // movgt r6, r4
+ {+ 24:} $04, $60, $46, $c2, // subgt r6, r6, #4
+ {+ 28:} $09, $00, $00, $cb, // blgt 54
+ {+ 2c:} $0f, $00, $2d, $e9, // push {r0, r1, r2, r3}
+ {+ 30:} $3c, $00, $9f, $e5, // ldr r0, [pc, #60] ; 74
+ {+ 34:} $0e, $00, $bd, $e8, // pop {r1, r2, r3}
+ {+ 38:} $38, $a0, $9f, $e5, // ldr sl, [pc, #56] ; 78
+ {+ 3c:} $3a, $ff, $2f, $e1, // blx sl
+ {+ 40:} $00, $00, $54, $e3, // cmp r4, #0
+ {+ 44:} $04, $d0, $8d, $c0, // addgt sp, sp, r4
+ {+ 48:} $04, $40, $9d, $e4, // pop {r4} ; (ldr r4, [sp], #4)
+ {+ 4c:} $1e, $04, $bd, $e8, // pop {r1, r2, r3, r4, sl}
+ {+ 50:} $80, $80, $bd, $e8, // pop {r7, pc}
+//offset + 00000054 :
+ {+ 54:} $05, $a0, $97, $e7, // ldr sl, [r7, r5]
+ {+ 58:} $06, $a0, $8d, $e7, // str sl, [sp, r6]
+ {+ 5c:} $04, $50, $45, $e2, // sub r5, r5, #4
+ {+ 60:} $04, $60, $46, $e2, // sub r6, r6, #4
+ {+ 64:} $00, $00, $56, $e3, // cmp r6, #0
+ {+ 68:} $f9, $ff, $ff, $aa, // bge 54
+ {+ 6c:} $1e, $ff, $2f, $e1, // bx lr
+//offset + 00000070
+ {+ 70:} $00, $00, $00, $00, // stack space for stack parameters
+ {+ 74:} $00, $00, $00, $00, // Self
+ {+ 78:} $00, $00, $00, $00 // Method
+);
+const
+ ARM_INSTRUCTION_SIZE = 4;
+ ARM_ARGUMENT_COUNT_IN_REGISTERS = 4;
+var
+ P, Q: PByte;
+ LLiteralPool: TArray;
+ I: Integer;
begin
- FreeCodeMem(Proc);
+ GetCodeMem(Q, SizeOf(S1));
+ P := Q;
+ Move(S1, P^, SizeOf(S1));
+
+ LLiteralPool := TArray.Create(
+ Pointer((ArgNum - ARM_ARGUMENT_COUNT_IN_REGISTERS) * ARM_INSTRUCTION_SIZE),
+ Self,
+ Method);
+
+ Inc(P, Length(S1) - (Length(LLiteralPool) * SizeOf(pointer)));
+ for I := Low(LLiteralPool) to High(LLiteralPool) do begin
+ Move(LLiteralPool[I], P^, SizeOf(pointer));
+ Inc(P, SizeOf(pointer));
+ end;
+
+ Result := Pointer(Q); //set arm mode
end;
+{$ENDIF CPUARM32}
-procedure FreeCallBacks;
+{$IFDEF CPUARM64}
+function GetCallBack(Self: TObject; Method: Pointer; ArgNum: Integer;
+ CallType: TCallType): Pointer;
+const
+ S1: array[0..79] of byte = (
+//big-endian
+//offset <_start>:
+ $fd, $7b, $bf, $a9, // stp x29, x30, [sp, #-16]!
+ $fd, $03, $00, $91, // mov x29, sp
+ $e0, $07, $bf, $a9, // stp x0, x1, [sp, #-16]!
+ $e2, $0f, $bf, $a9, // stp x2, x3, [sp, #-16]!
+ $e4, $17, $bf, $a9, // stp x4, x5, [sp, #-16]!
+ $e6, $1f, $bf, $a9, // stp x6, x7, [sp, #-16]!
+ $0a, $00, $00, $10, // adr x10, #0 <_start+0x18>
+ $40, $15, $40, $f9, // ldr x0, [x10, #40]
+ $49, $19, $40, $f9, // ldr x9, [x10, #48]
+ $e7, $2f, $c1, $a8, // ldp x7, x11, [sp], #16
+ $e5, $1b, $c1, $a8, // ldp x5, x6, [sp], #16
+ $e3, $13, $c1, $a8, // ldp x3, x4, [sp], #16
+ $e1, $0b, $c1, $a8, // ldp x1, x2, [sp], #16
+ $20, $01, $3f, $d6, // blr x9
+ $fd, $7b, $c1, $a8, // ldp x29, x30, [sp], #16
+ $c0, $03, $5f, $d6, // ret
+ $00, $00, $00, $00, // .word 0x00000000 //Self
+ $00, $00, $00, $00, // .word 0x00000000
+ $00, $00, $00, $00, // .word 0x00000000 //Method
+ $00, $00, $00, $00 // .word 0x00000000
+);
var
- page, nextpage: PCodeMemPage;
+ P, Q: PByte;
+ LLiteralPool: TArray;
+ I: Integer;
begin
- // free each allocated page
- page := CodeMemPages;
- while page <> nil do
- begin
- nextpage := page^.Next;
+ GetCodeMem(Q, SizeOf(S1));
+ P := Q;
+ Move(S1, P^, SizeOf(S1));
- // free the memory
- {$IFDEF MSWINDOWS}
- VirtualFree(page, 0, MEM_RELEASE);
- {$ELSE}
- //FreeMem(page);
- munmap(page,PageSize);
- {$ENDIF}
+ LLiteralPool := TArray.Create(Self, Method);
- page := nextpage;
+ Inc(P, Length(S1) - (Length(LLiteralPool) * SizeOf(pointer)));
+ for I := Low(LLiteralPool) to High(LLiteralPool) do begin
+ Move(LLiteralPool[I], P^, SizeOf(pointer));
+ Inc(P, SizeOf(pointer));
end;
- CodeMemPages := nil;
+
+ Result := Pointer(Q); //set arm mode
end;
+{$ENDIF CPUARM64}
initialization
+
finalization
FreeCallBacks;
+
end.
diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas
index fe4aa481..627a7f81 100644
--- a/Source/PythonEngine.pas
+++ b/Source/PythonEngine.pas
@@ -95,7 +95,8 @@ interface
{$IF not Defined(FPC) and (CompilerVersion >= 23)}
const
{$IF CompilerVersion >= 33}
- pidSupportedPlatforms = pidWin32 or pidWin64 or pidOSX32 or pidOSX64 or pidLinux64;
+ pidSupportedPlatforms = pidWin32 or pidWin64 or pidOSX32 or pidOSX64
+ or pidLinux64 or pidAndroid32Arm or pidAndroid64Arm;
{$ELSE}
pidSupportedPlatforms = pidWin32 or pidWin64 or pidOSX32;
{$IFEND}
@@ -154,6 +155,18 @@ TPythonVersionProp = record
(DllName: 'libpython3.10.dylib'; RegVersion: '3.10'; APIVersion: 1013)
);
{$ENDIF}
+{$IFDEF ANDROID}
+ PYTHON_KNOWN_VERSIONS: array[7..7] of TPythonVersionProp =
+ {$IFDEF DEBUG}
+ (
+ (DllName: 'libpython3.9d.so'; RegVersion: '3.9'; APIVersion: 1013)
+ );
+ {$ELSE}
+ (
+ (DllName: 'libpython3.9.so'; RegVersion: '3.9'; APIVersion: 1013)
+ );
+ {$ENDIF}
+{$ENDIF}
COMPILED_FOR_PYTHON_VERSION_INDEX = High(PYTHON_KNOWN_VERSIONS);
@@ -177,6 +190,13 @@ TPythonVersionProp = record
Py_NE = 3;
Py_GT = 4;
Py_GE = 5;
+
+ {$IFDEF CPUARM}
+ DEFAULT_CALLBACK_TYPE: TCallType = TCallType.ctARMSTD;
+ {$ELSE}
+ DEFAULT_CALLBACK_TYPE: TCallType = TCallType.ctCDECL;
+ {$ENDIF CPUARM}
+
type
// Delphi equivalent used by TPyObject
TRichComparisonOpcode = (pyLT, pyLE, pyEQ, pyNE, pyGT, pyGE);
@@ -204,6 +224,7 @@ TPythonVersionProp = record
WCharTString = UnicodeString;
{$ENDIF}
+
const
{
Type flags (tp_flags)
@@ -402,7 +423,7 @@ TPythonVersionProp = record
newfunc = function ( subtype: PPyTypeObject; args, kwds : PPyObject) : PPyObject; cdecl;
allocfunc = function ( self: PPyTypeObject; nitems : NativeInt) : PPyObject; cdecl;
- PyNumberMethods = {$IFNDEF CPUX64}packed{$ENDIF} record
+ PyNumberMethods = {$IFDEF CPUX86}packed{$ENDIF} record
nb_add : binaryfunc;
nb_subtract : binaryfunc;
nb_multiply : binaryfunc;
@@ -442,7 +463,7 @@ TPythonVersionProp = record
end;
PPyNumberMethods = ^PyNumberMethods;
- PySequenceMethods = {$IFNDEF CPUX64}packed{$ENDIF} record
+ PySequenceMethods = {$IFDEF CPUX86}packed{$ENDIF} record
sq_length : lenfunc;
sq_concat : binaryfunc;
sq_repeat : ssizeargfunc;
@@ -456,37 +477,37 @@ TPythonVersionProp = record
end;
PPySequenceMethods = ^PySequenceMethods;
- PyMappingMethods = {$IFNDEF CPUX64}packed{$ENDIF} record
+ PyMappingMethods = {$IFDEF CPUX86}packed{$ENDIF} record
mp_length : lenfunc;
mp_subscript : binaryfunc;
mp_ass_subscript : objobjargproc;
end;
PPyMappingMethods = ^PyMappingMethods;
- Py_complex = {$IFNDEF CPUX64}packed{$ENDIF} record
+ Py_complex = {$IFDEF CPUX86}packed{$ENDIF} record
real : double;
imag : double;
end;
- PyObject = {$IFNDEF CPUX64}packed{$ENDIF} record
+ PyObject = {$IFDEF CPUX86}packed{$ENDIF} record
ob_refcnt: NativeInt;
ob_type: PPyTypeObject;
end;
- _frozen = {$IFNDEF CPUX64}packed{$ENDIF} record
+ _frozen = {$IFDEF CPUX86}packed{$ENDIF} record
name : PAnsiChar;
code : PByte;
size : Integer;
end;
- PySliceObject = {$IFNDEF CPUX64}packed{$ENDIF} record
+ PySliceObject = {$IFDEF CPUX86}packed{$ENDIF} record
ob_refcnt: NativeInt;
ob_type: PPyTypeObject;
start, stop, step: PPyObject;
end;
PPyMethodDef = ^PyMethodDef;
- PyMethodDef = {$IFNDEF CPUX64}packed{$ENDIF} record
+ PyMethodDef = {$IFDEF CPUX86}packed{$ENDIF} record
ml_name: PAnsiChar;
ml_meth: PyCFunction;
ml_flags: Integer;
@@ -495,11 +516,11 @@ TPythonVersionProp = record
// structmember.h
PPyMemberDef = ^PyMemberDef;
- PyMemberDef = {$IFNDEF CPUX64}packed{$ENDIF} record
+ PyMemberDef = {$IFDEF CPUX86}packed{$ENDIF} record
name : PAnsiChar;
_type : integer;
offset : NativeInt;
- flags : integer;
+ flags : Integer;
doc : PAnsiChar;
end;
@@ -511,7 +532,7 @@ TPythonVersionProp = record
setter = function ( obj, value : PPyObject; context : Pointer) : integer; cdecl;
PPyGetSetDef = ^PyGetSetDef;
- PyGetSetDef = {$IFNDEF CPUX64}packed{$ENDIF} record
+ PyGetSetDef = {$IFDEF CPUX86}packed{$ENDIF} record
name : PAnsiChar;
get : getter;
_set : setter;
@@ -522,7 +543,7 @@ TPythonVersionProp = record
wrapperfunc = function (self, args: PPyObject; wrapped : Pointer) : PPyObject; cdecl;
pwrapperbase = ^wrapperbase;
- wrapperbase = {$IFNDEF CPUX64}packed{$ENDIF} record
+ wrapperbase = {$IFDEF CPUX86}packed{$ENDIF} record
name : PAnsiChar;
wrapper : wrapperfunc;
doc : PAnsiChar;
@@ -537,7 +558,7 @@ TPythonVersionProp = record
}
PPyDescrObject = ^PyDescrObject;
- PyDescrObject = {$IFNDEF CPUX64}packed{$ENDIF} record
+ PyDescrObject = {$IFDEF CPUX86}packed{$ENDIF} record
// Start of the Head of an object
ob_refcnt : NativeInt;
ob_type : PPyTypeObject;
@@ -547,7 +568,7 @@ TPythonVersionProp = record
end;
PPyMethodDescrObject = ^PyMethodDescrObject;
- PyMethodDescrObject = {$IFNDEF CPUX64}packed{$ENDIF} record
+ PyMethodDescrObject = {$IFDEF CPUX86}packed{$ENDIF} record
// Start of PyDescr_COMMON
// Start of the Head of an object
ob_refcnt : NativeInt;
@@ -560,7 +581,7 @@ TPythonVersionProp = record
end;
PPyMemberDescrObject = ^PyMemberDescrObject;
- PyMemberDescrObject = {$IFNDEF CPUX64}packed{$ENDIF} record
+ PyMemberDescrObject = {$IFDEF CPUX86}packed{$ENDIF} record
// Start of PyDescr_COMMON
// Start of the Head of an object
ob_refcnt : NativeInt;
@@ -573,7 +594,7 @@ TPythonVersionProp = record
end;
PPyGetSetDescrObject = ^PyGetSetDescrObject;
- PyGetSetDescrObject = {$IFNDEF CPUX64}packed{$ENDIF} record
+ PyGetSetDescrObject = {$IFDEF CPUX86}packed{$ENDIF} record
// Start of PyDescr_COMMON
// Start of the Head of an object
ob_refcnt : NativeInt;
@@ -586,7 +607,7 @@ TPythonVersionProp = record
end;
PPyWrapperDescrObject = ^PyWrapperDescrObject;
- PyWrapperDescrObject = {$IFNDEF CPUX64}packed{$ENDIF} record
+ PyWrapperDescrObject = {$IFDEF CPUX86}packed{$ENDIF} record
// Start of PyDescr_COMMON
// Start of the Head of an object
ob_refcnt : NativeInt;
@@ -600,7 +621,7 @@ TPythonVersionProp = record
end;
PPyModuleDef_Base = ^PyModuleDef_Base;
- PyModuleDef_Base = {$IFNDEF CPUX64}packed{$ENDIF} record
+ PyModuleDef_Base = {$IFDEF CPUX86}packed{$ENDIF} record
// Start of the Head of an object
ob_refcnt : NativeInt;
ob_type : PPyTypeObject;
@@ -611,7 +632,7 @@ TPythonVersionProp = record
end;
PPyModuleDef = ^PyModuleDef;
- PyModuleDef = {$IFNDEF CPUX64}packed{$ENDIF} record
+ PyModuleDef = {$IFDEF CPUX86}packed{$ENDIF} record
m_base : PyModuleDef_Base;
m_name : PAnsiChar;
m_doc : PAnsiChar;
@@ -625,7 +646,7 @@ TPythonVersionProp = record
// object.h
- PyTypeObject = {$IFNDEF CPUX64}packed{$ENDIF} record
+ PyTypeObject = {$IFDEF CPUX86}packed{$ENDIF} record
ob_refcnt: NativeInt;
ob_type: PPyTypeObject;
ob_size: NativeInt; // Number of items in variable part
@@ -724,7 +745,7 @@ TPythonVersionProp = record
// Parse tree node interface
PNode = ^node;
- node = {$IFNDEF CPUX64}packed{$ENDIF} record
+ node = {$IFDEF CPUX86}packed{$ENDIF} record
n_type : smallint;
n_str : PAnsiChar;
n_lineno : integer;
@@ -734,7 +755,7 @@ TPythonVersionProp = record
end;
PPyCompilerFlags = ^PyCompilerFlags;
- PyCompilerFlags = {$IFNDEF CPUX64}packed{$ENDIF} record
+ PyCompilerFlags = {$IFDEF CPUX86}packed{$ENDIF} record
flags : integer;
cf_feature_version : integer; //added in Python 3.8
end;
@@ -769,7 +790,7 @@ TPythonVersionProp = record
PyGILState_UNLOCKED = 1;
type
- PyDateTime_Delta = {$IFNDEF CPUX64}packed{$ENDIF} record
+ PyDateTime_Delta = {$IFDEF CPUX86}packed{$ENDIF} record
// Start of the Head of an object
ob_refcnt : NativeInt;
ob_type : PPyTypeObject;
@@ -781,7 +802,7 @@ TPythonVersionProp = record
end;
PPyDateTime_Delta = ^PyDateTime_Delta;
- PyDateTime_TZInfo = {$IFNDEF CPUX64}packed{$ENDIF} record // a pure abstract base clase
+ PyDateTime_TZInfo = {$IFDEF CPUX86}packed{$ENDIF} record // a pure abstract base clase
// Start of the Head of an object
ob_refcnt : NativeInt;
ob_type : PPyTypeObject;
@@ -803,7 +824,7 @@ TPythonVersionProp = record
* convenient to cast to, when getting at the hastzinfo member of objects
* starting with _PyTZINFO_HEAD.
*}
- _PyDateTime_BaseTZInfo = {$IFNDEF CPUX64}packed{$ENDIF} record
+ _PyDateTime_BaseTZInfo = {$IFDEF CPUX86}packed{$ENDIF} record
// Start of _PyTZINFO_HEAD
// Start of the Head of an object
ob_refcnt : NativeInt;
@@ -826,7 +847,7 @@ TPythonVersionProp = record
unsigned char data[_PyDateTime_TIME_DATASIZE];
}
- _PyDateTime_BaseTime = {$IFNDEF CPUX64}packed{$ENDIF} record // hastzinfo false
+ _PyDateTime_BaseTime = {$IFDEF CPUX86}packed{$ENDIF} record // hastzinfo false
// Start of _PyDateTime_TIMEHEAD
// Start of _PyTZINFO_HEAD
// Start of the Head of an object
@@ -841,7 +862,7 @@ TPythonVersionProp = record
end;
_PPyDateTime_BaseTime = ^_PyDateTime_BaseTime;
- PyDateTime_Time = {$IFNDEF CPUX64}packed{$ENDIF} record // hastzinfo true
+ PyDateTime_Time = {$IFDEF CPUX86}packed{$ENDIF} record // hastzinfo true
// Start of _PyDateTime_TIMEHEAD
// Start of _PyTZINFO_HEAD
// Start of the Head of an object
@@ -864,7 +885,7 @@ TPythonVersionProp = record
* the plain date type is a base class for datetime, so it must also have
* a hastzinfo member (although it's unused there).
*}
- PyDateTime_Date = {$IFNDEF CPUX64}packed{$ENDIF} record
+ PyDateTime_Date = {$IFDEF CPUX86}packed{$ENDIF} record
// Start of _PyTZINFO_HEAD
// Start of the Head of an object
ob_refcnt : NativeInt;
@@ -883,7 +904,7 @@ TPythonVersionProp = record
unsigned char data[_PyDateTime_DATETIME_DATASIZE];
}
- _PyDateTime_BaseDateTime = {$IFNDEF CPUX64}packed{$ENDIF} record // hastzinfo false
+ _PyDateTime_BaseDateTime = {$IFDEF CPUX86}packed{$ENDIF} record // hastzinfo false
// Start of _PyTZINFO_HEAD
// Start of the Head of an object
ob_refcnt : NativeInt;
@@ -896,7 +917,7 @@ TPythonVersionProp = record
end;
_PPyDateTime_BaseDateTime = ^_PyDateTime_BaseDateTime;
- PyDateTime_DateTime = {$IFNDEF CPUX64}packed{$ENDIF} record // hastzinfo true
+ PyDateTime_DateTime = {$IFDEF CPUX86}packed{$ENDIF} record // hastzinfo true
// Start of _PyDateTime_DATETIMEHEAD
// Start of _PyTZINFO_HEAD
// Start of the Head of an object
@@ -1588,10 +1609,13 @@ TPythonInterface=class(TDynamicDll)
Py_GetCopyright : function : PAnsiChar; cdecl;
Py_GetExecPrefix : function : PAnsiChar; cdecl;
Py_GetPath : function : PAnsiChar; cdecl;
+
+ Py_SetPath : procedure (path: PWCharT); cdecl;
+
Py_SetPythonHome : procedure (home : PWCharT); cdecl;
Py_GetPythonHome : function : PWCharT; cdecl;
Py_GetPrefix : function : PAnsiChar; cdecl;
- Py_GetProgramName : function : PAnsiChar; cdecl;
+ Py_GetProgramName : function : PWCharT; cdecl;
PyParser_SimpleParseStringFlags : function ( str : PAnsiChar; start, flags : Integer) : PNode; cdecl;
PyNode_Free : procedure( n : PNode ); cdecl;
@@ -1776,6 +1800,7 @@ TPythonEngine = class(TPythonInterface)
FAutoFinalize: Boolean;
FProgramName: WCharTString;
FPythonHome: WCharTString;
+ FPythonPath: WCharTString;
FInitThreads: Boolean;
FOnPathInitialization: TPathInitializationEvent;
FOnSysPathInit: TSysPathInitEvent;
@@ -1797,6 +1822,8 @@ TPythonEngine = class(TPythonInterface)
FPyDateTime_DateTimeTZType: PPyObject;
function GetPythonHome: UnicodeString;
function GetProgramName: UnicodeString;
+ function GetPythonPath: UnicodeString;
+ procedure SetPythonPath(const Value: UnicodeString);
protected
procedure Initialize;
@@ -1917,6 +1944,7 @@ TPythonEngine = class(TPythonInterface)
property IOPythonModule: TObject read FIOPythonModule; {TPythonModule}
property PythonHome: UnicodeString read GetPythonHome write SetPythonHome;
property ProgramName: UnicodeString read GetProgramName write SetProgramName;
+ property PythonPath: UnicodeString read GetPythonPath write SetPythonPath;
published
property AutoFinalize: Boolean read FAutoFinalize write FAutoFinalize default True;
property VenvPythonExe: string read FVenvPythonExe write FVenvPythonExe;
@@ -2534,7 +2562,8 @@ TPythonType = class(TGetSetContainer)
// methods
///////////////////////////////////////
function NewSubtypeInst( aType: PPyTypeObject; args, kwds : PPyObject) : PPyObject; cdecl;
-
+ public
+ const TYPE_COMP_NAME_SUFFIX = 'Type';
public
constructor Create( AOwner : TComponent ); override;
destructor Destroy; override;
@@ -3560,6 +3589,7 @@ procedure TPythonInterface.MapDll;
Py_GetCopyright := Import('Py_GetCopyright');
Py_GetExecPrefix := Import('Py_GetExecPrefix');
Py_GetPath := Import('Py_GetPath');
+ Py_SetPath := Import('Py_SetPath');
Py_SetPythonHome := Import('Py_SetPythonHome');
Py_GetPythonHome := Import('Py_GetPythonHome');
Py_GetPrefix := Import('Py_GetPrefix');
@@ -4222,8 +4252,10 @@ procedure TPythonEngine.Initialize;
if Assigned(Py_SetProgramName) and (Length(FProgramName) > 0) then
Py_SetProgramName(PWCharT(FProgramName));
AssignPyFlags;
- if Length(FPythonHome) > 0 then
+ if Assigned(Py_SetPythonHome) and (PythonHome <> '') then
Py_SetPythonHome(PWCharT(FPythonHome));
+ if Assigned(Py_SetPath) and (PythonPath <> '') then
+ Py_SetPath(PWCharT(FPythonPath));
Py_Initialize;
if Assigned(Py_IsInitialized) then
FInitialized := Py_IsInitialized() <> 0
@@ -4480,6 +4512,18 @@ function TPythonEngine.GetPythonHome: UnicodeString;
{$ENDIF}
end;
+function TPythonEngine.GetPythonPath: UnicodeString;
+begin
+{$IFDEF POSIX}
+ if (Length(FPythonPath) > 0) then
+ Result := UCS4StringToUnicodeString(FPythonPath)
+ else
+ Result := '';
+{$ELSE}
+ Result := FPythonPath;
+{$ENDIF}
+end;
+
function TPythonEngine.GetProgramName: UnicodeString;
begin
{$IFDEF POSIX}
@@ -4501,6 +4545,15 @@ procedure TPythonEngine.SetPythonHome(const PythonHome: UnicodeString);
{$ENDIF}
end;
+procedure TPythonEngine.SetPythonPath(const Value: UnicodeString);
+begin
+{$IFDEF POSIX}
+ FPythonPath := UnicodeStringToUCS4String(Value);
+{$ELSE}
+ FPythonPath := Value;
+{$ENDIF}
+end;
+
procedure TPythonEngine.SetProgramName(const ProgramName: UnicodeString);
begin
{$IFDEF POSIX}
@@ -5043,7 +5096,7 @@ function TPythonEngine.EncodeWindowsFilePath(const str: string): AnsiString;
Result := AnsiString(str);
end;
-function TPythonEngine.TypeByName( const aTypeName : AnsiString ) : PPyTypeObject;
+function TPythonEngine.TypeByName( const aTypeName : AnsiString ) : PPyTypeObject;
var
i : Integer;
begin
@@ -6258,7 +6311,7 @@ function TMethodsContainer.AddDelphiMethod( AMethodName : PAnsiChar;
ADocString : PAnsiChar ) : PPyMethodDef;
begin
Result := AddMethod( AMethodName,
- GetOfObjectCallBack( TCallBack(ADelphiMethod), 2, ctCDECL),
+ GetOfObjectCallBack( TCallBack(ADelphiMethod), 2, DEFAULT_CALLBACK_TYPE),
ADocString );
end;
@@ -6267,7 +6320,7 @@ function TMethodsContainer.AddDelphiMethodWithKeywords( AMethodName : PAnsiCh
ADocString : PAnsiChar ) : PPyMethodDef;
begin
Result := AddMethod( AMethodName,
- GetOfObjectCallBack( TCallBack(ADelphiMethod), 3, ctCDECL),
+ GetOfObjectCallBack( TCallBack(ADelphiMethod), 3, DEFAULT_CALLBACK_TYPE),
ADocString );
Result^.ml_flags := Result^.ml_flags or METH_KEYWORDS;
end;
@@ -8087,7 +8140,7 @@ procedure TPythonType.InitServices;
begin
tp_init := TPythonType_InitSubtype;
tp_alloc := TPythonType_AllocSubtypeInst;
- tp_new := GetCallBack( Self, @TPythonType.NewSubtypeInst, 3, ctCDECL);
+ tp_new := GetCallBack( Self, @TPythonType.NewSubtypeInst, 3, DEFAULT_CALLBACK_TYPE);
tp_free := FreeSubtypeInst;
tp_methods := MethodsData;
tp_members := MembersData;
@@ -8297,7 +8350,7 @@ procedure TPythonType.AddTypeVar;
begin
meth := CreateMethod;
FCreateFuncDef.ml_name := PAnsiChar(FCreateFuncName);
- FCreateFuncDef.ml_meth := GetOfObjectCallBack( TCallBack(meth), 2, ctCDECL);
+ FCreateFuncDef.ml_meth := GetOfObjectCallBack( TCallBack(meth), 2, DEFAULT_CALLBACK_TYPE);
FCreateFuncDef.ml_flags := METH_VARARGS;
FCreateFuncDef.ml_doc := PAnsiChar(FCreateFuncDoc);
FCreateFunc := Engine.PyCFunction_NewEx(@FCreateFuncDef, nil, nil)
diff --git a/Source/VarPyth.pas b/Source/VarPyth.pas
index 2297d30e..842c58e4 100644
--- a/Source/VarPyth.pas
+++ b/Source/VarPyth.pas
@@ -148,7 +148,7 @@ TNamedParamDesc = record
{$IFDEF DELPHIXE2_OR_HIGHER}
{$DEFINE USESYSTEMDISPINVOKE} //Delphi 2010 DispInvoke is buggy
- {$IF defined(OSX64) or defined(LINUX) or not defined(DELPHI10_4_OR_HIGHER)}
+ {$IF defined(OSX64) or defined(LINUX) or defined(CPUARM) or not defined(DELPHI10_4_OR_HIGHER)}
{$DEFINE PATCHEDSYSTEMDISPINVOKE} //To correct memory leaks
{$IFEND}
{$ENDIF}
@@ -949,7 +949,7 @@ procedure SetClearVarToEmptyParam(var V: TVarData);
CPropertyGet = $02;
CPropertySet = $04;
-{$IF defined(PATCHEDSYSTEMDISPINVOKE) and (defined(OSX64) or defined(LINUX))}
+{$IF defined(PATCHEDSYSTEMDISPINVOKE) and (defined(OSX64) or defined(LINUX) or defined(CPUARM))}
{
Fixes https://quality.embarcadero.com/browse/RSP-28097
}
@@ -964,7 +964,10 @@ procedure _DispInvokeError;
raise EVariantDispatchError.Create(SDispatchError);
end;
+{$IFDEF CPUARM}
+
function GetDispatchInvokeArgs(CallDesc: PCallDesc; Params: Pointer; var Strings: TStringRefList; OrderLTR : Boolean): TVarDataArray;
+{$IF defined(OSX64) or defined(LINUX) or defined(CPUARM64)}
const
{ Parameter type masks - keep in sync with decl.h/ap* enumerations}
atString = $48;
@@ -998,7 +1001,11 @@ function GetDispatchInvokeArgs(CallDesc: PCallDesc; Params: Pointer; var Strings
if (ArgType and atTypeMask) = atString then
begin
PVarData(PVarParm)^.VType := varByRef or varOleStr;
+{$IFDEF NEXTGEN}
+ PVarData(PVarParm)^.VPointer := Strings[StringCount].FromUTF8( PUTF8String(Temp) );
+{$ELSE !NEXTGEN}
PVarData(PVarParm)^.VPointer := Strings[StringCount].FromAnsi( PAnsiString(Temp));
+{$ENDIF NEXTGEN}
Inc(StringCount);
end
else
@@ -1088,6 +1095,18 @@ function GetDispatchInvokeArgs(CallDesc: PCallDesc; Params: Pointer; var Strings
end;
atString:
begin
+{$IFDEF NEXTGEN}
+ PVarParm^.VType := varOleStr;
+ Temp := VarArgGetValue(VAList, Pointer);
+ if PUTF8String(Temp)^ <> '' then
+ begin
+ PVarParm^.VPointer := PWideChar(Strings[StringCount].FromUTF8(PUTF8String(Temp))^);
+ Strings[StringCount].UTF8 := nil;
+ Inc(StringCount);
+ end
+ else
+ PVarParm^.VPointer := _EmptyBSTR;
+{$ELSE !NEXTGEN}
PVarParm^.VType := varOleStr;
Temp := VarArgGetValue(VAList, Pointer);
if AnsiString(Temp) <> '' then
@@ -1102,6 +1121,7 @@ function GetDispatchInvokeArgs(CallDesc: PCallDesc; Params: Pointer; var Strings
end
else
PVarParm^.VPointer := _EmptyBSTR;
+{$ENDIF NEXTGEN}
end;
atUString:
begin
@@ -1129,6 +1149,352 @@ function GetDispatchInvokeArgs(CallDesc: PCallDesc; Params: Pointer; var Strings
end;
end;
end;
+{$ELSE !(defined(OSX64) or defined(LINUX) or defined(CPUARM64))}
+const
+ { Parameter type masks - keep in sync with decl.h/ap* enumerations}
+ atString = $48;
+ atUString = $4A;
+ atVarMask = $3F;
+ atTypeMask = $7F;
+ atByRef = $80;
+var
+ I: Integer;
+ ArgType: Byte;
+ PVarParam: PVarData;
+ StringCount: Integer;
+begin
+ StringCount := 0;
+ SetLength(Result, CallDesc^.ArgCount);
+ for I := 0 to CallDesc^.ArgCount-1 do
+ begin
+ ArgType := CallDesc^.ArgTypes[I];
+
+ if OrderLTR then
+ PVarParam := @Result[I]
+ else
+ PVarParam := @Result[CallDesc^.ArgCount-I-1];
+
+ if (ArgType and atByRef) = atByRef then
+ begin
+ if (ArgType and atTypeMask) = atString then
+ begin
+ PVarData(PVarParam)^.VType := varByRef or varOleStr;
+ PVarData(PVarParam)^.VPointer := Strings[StringCount].FromAnsi(PAnsiString(Params^));
+ Inc(StringCount);
+ end
+ else
+ if (ArgType and atTypeMask) = atUString then
+ begin
+ PVarData(PVarParam)^.VType := varByRef or varOleStr;
+ PVarData(PVarParam)^.VPointer := Strings[StringCount].FromUnicode(PUnicodeString(Params^));
+ Inc(StringCount);
+ end
+ else
+ begin
+ if ((ArgType and atTypeMask) = varVariant) and
+ ((PVarData(Params^)^.VType = varString) or (PVarData(Params^)^.VType = varUString)) then
+ VarCast(PVariant(Params^)^, PVariant(Params^)^, varOleStr);
+ //PVarData(PVarParm)^.VType := varByRef or (ArgType and atTypeMask);
+
+ ArgType := ArgType and atTypeMask;
+ if DispatchUnsignedAsSigned then
+ case ArgType of
+ varUInt64: ArgType := varInt64;
+ varUInt32: ArgType := varInteger;
+ varWord: ArgType := varSmallint;
+ varByte: ArgType := varShortInt;
+ end;
+
+ PVarData(PVarParam)^.VType := varByRef or ArgType;
+
+ PVarData(PVarParam)^.VPointer := PPointer(Params)^;
+
+ var LArgType := PVarData(Params^)^.VType;
+ if LArgType = PythonVariantType.VarType then
+ begin
+ PVarData(PVarParam)^.VType := PythonVariantType.VarType;
+ end;
+ end;
+ Inc(PByte(Params), SizeOf(Pointer));
+ end
+ else // ByVal
+ begin
+ PVarParam^.VType := ArgType;
+ case ArgType of
+ varEmpty, varNull: ; // Only need to set VType
+ varSmallint: PVarParam^.VSmallInt := PSmallInt(Params)^;
+ varInteger: PVarParam^.VInteger := PInteger(Params)^;
+ varSingle: PVarParam^.VSingle := PSingle(Params)^;
+ varDouble: PVarParam^.VDouble := PDouble(Params)^;
+ varCurrency: PVarParam^.VCurrency := PCurrency(Params)^;
+ varDate: PVarParam^.VDate := PDateTime(Params)^;
+ varOleStr: PVarParam^.VPointer := PPointer(Params)^;
+ varDispatch: PVarParam^.VDispatch := PPointer(Params)^;
+ varError: PVarParam^.VError := HRESULT($80020004); //DISP_E_PARAMNOTFOUND;
+ varBoolean: PVarParam^.VBoolean := PBoolean(Params)^;
+ varVariant:
+ begin
+ PVarParam^.VType := varEmpty;
+ {$IFDEF CPUX64}
+ PVariant(PVarParam)^ := PVariant(Params^)^;
+ {$ELSE}
+ PVariant(PVarParam)^ := PVariant(Params^)^; //it arrives here as a pointer for 32bits also
+ {$ENDIF}
+ end;
+ varUnknown: PVarParam^.VUnknown := PPointer(Params)^;
+ varShortInt: PVarParam^.VShortInt := PShortInt(Params)^;
+ varByte: PVarParam^.VByte := PByte(Params)^;
+ varWord:
+ begin
+ if DispatchUnsignedAsSigned then
+ begin
+ PVarParam^.VType := varInteger;
+ PVarParam^.VInteger := Integer(PWord(Params)^);
+ end else
+ PVarParam^.VWord := PWord(Params)^;
+ end;
+ varUInt32:
+ begin
+ if DispatchUnsignedAsSigned then
+ begin
+ PVarParam^.VType := varInteger;
+ PVarParam^.VInteger := Integer(PCardinal(Params)^);
+ end else
+ PVarParam^.VUInt32 := PCardinal(Params)^;
+ end;
+ varInt64: PVarParam^.VInt64 := PInt64(Params)^;
+ varUInt64:
+ begin
+ if DispatchUnsignedAsSigned then
+ begin
+ PVarParam^.VType := varInt64;
+ PVarParam^.VInt64 := Int64(PInt64(Params)^);
+ end else
+ PVarParam^.VUInt64 := PUInt64(Params)^;
+ end;
+ atString:
+ begin
+ PVarParam^.VType := varOleStr;
+ if PAnsiString(Params)^ <> '' then
+ begin
+ PVarParam^.VPointer := PWideChar(Strings[StringCount].FromAnsi(PAnsiString(Params))^);
+ Strings[StringCount].Ansi := nil;
+ Inc(StringCount);
+ end
+ else
+ PVarParam^.VPointer := _EmptyBSTR;
+ end;
+ atUString:
+ begin
+ PVarParam^.VType := varOleStr;
+ if PUnicodeString(Params)^ <> '' then
+ begin
+ PVarParam^.VPointer := PWideChar(Strings[StringCount].FromUnicode(PUnicodeString(Params))^);
+ Strings[StringCount].Unicode := nil;
+ Inc(StringCount);
+ end
+ else
+ PVarParam^.VPointer := _EmptyBSTR;
+ end;
+ else
+ // Unsupported Var Types
+ //varDecimal = $000E; { vt_decimal 14 } {UNSUPPORTED as of v6.x code base}
+ //varUndef0F = $000F; { undefined 15 } {UNSUPPORTED per Microsoft}
+ //varRecord = $0024; { VT_RECORD 36 }
+ //varString = $0100; { Pascal string 256 } {not OLE compatible }
+ //varAny = $0101; { Corba any 257 } {not OLE compatible }
+ //varUString = $0102; { Unicode string 258 } {not OLE compatible }
+ _DispInvokeError;
+ end;
+ case ArgType of
+ varError: ; // don't increase param pointer
+{$IFDEF CPUARM}
+ varDouble, varCurrency, varDate, varInt64, varUInt64:
+ Inc(PByte(Params), 8);
+ varVariant:
+ {$IFDEF CPUX64}
+ Inc(PByte(Params), SizeOf(Variant));
+ {$ELSE}
+ Inc(PByte(Params), SizeOf(Pointer));
+ {$ENDIF CPUX64}
+{$ENDIF CPUARM}
+ else
+ Inc(PByte(Params), SizeOf(Pointer));
+ end;
+ end;
+ end;
+end;
+{$IFEND defined(OSX64) or defined(LINUX) or defined(CPUARM64)}
+
+{$ELSE}
+
+function GetDispatchInvokeArgs(CallDesc: PCallDesc; Params: Pointer; var Strings: TStringRefList; OrderLTR : Boolean): TVarDataArray;
+const
+ { Parameter type masks - keep in sync with decl.h/ap* enumerations}
+ atString = $48;
+ atUString = $4A;
+ atVarMask = $3F;
+ atTypeMask = $7F;
+ atByRef = $80;
+var
+ I: Integer;
+ ArgType: Byte;
+ PVarParm: PVarData;
+ StringCount: Integer;
+ VAList: TVarArgList;
+ Temp: Pointer;
+begin
+ VAList := TVarArgList(Params^);
+ StringCount := 0;
+ SetLength(Result, CallDesc^.ArgCount);
+ for I := 0 to CallDesc^.ArgCount-1 do
+ begin
+ ArgType := CallDesc^.ArgTypes[I];
+
+ if OrderLTR then
+ PVarParm := @Result[I]
+ else
+ PVarParm := @Result[CallDesc^.ArgCount-I-1];
+
+ if (ArgType and atByRef) = atByRef then
+ begin
+ Temp := VarArgGetValue(VAList, Pointer);
+ if (ArgType and atTypeMask) = atString then
+ begin
+ PVarData(PVarParm)^.VType := varByRef or varOleStr;
+ PVarData(PVarParm)^.VPointer := Strings[StringCount].FromAnsi( PAnsiString(Temp));
+ Inc(StringCount);
+ end
+ else
+ if (ArgType and atTypeMask) = atUString then
+ begin
+ PVarData(PVarParm)^.VType := varByRef or varOleStr;
+ PVarData(PVarParm)^.VPointer := Strings[StringCount].FromUnicode(PUnicodeString(Temp));
+ Inc(StringCount);
+ end
+ else
+ begin
+ if ((ArgType and atTypeMask) = varVariant) and
+ ((PVarData(Temp)^.VType = varString) or (PVarData(Temp)^.VType = varUString)) then
+ VarCast(PVariant(Temp)^, PVariant(Temp)^, varOleStr);
+ //PVarData(PVarParm)^.VType := varByRef or (ArgType and atTypeMask);
+
+ ArgType := ArgType and atTypeMask;
+ if DispatchUnsignedAsSigned then
+ case ArgType of
+ varUInt64: ArgType := varInt64;
+ varUInt32: ArgType := varInteger;
+ varWord: ArgType := varSmallint;
+ varByte: ArgType := varShortInt;
+ end;
+ PVarData(PVarParm)^.VType := varByRef or ArgType;
+
+ PVarData(PVarParm)^.VPointer := Temp;
+ end;
+ end
+ else // ByVal
+ begin
+ PVarParm^.VType := ArgType;
+ case ArgType of
+ varEmpty, varNull: ; // Only need to set VType
+ varInteger: PVarParm^.VInteger := VarArgGetValue(VAList, Integer);
+ varSingle: PVarParm^.VSingle := VarArgGetValue(VAList, Single);
+ varDouble: PVarParm^.VDouble := VarArgGetValue(VAList, Double);
+ varCurrency: PVarParm^.VCurrency := VarArgGetValue(VAList, Currency);
+ varDate: PVarParm^.VDate := VarArgGetValue(VAList, TDateTime);
+ varOleStr: PVarParm^.VPointer := VarArgGetValue(VAList, Pointer);
+ varDispatch: PVarParm^.VDispatch := VarArgGetValue(VAList, Pointer);
+ varError: PVarParm^.VError := HRESULT($80020004); //DISP_E_PARAMNOTFOUND;
+ varBoolean: PVarParm^.VBoolean := VarArgGetValue(VAList, Boolean);
+ varVariant:
+ begin
+ PVarParm^.VType := varEmpty;
+{$IFDEF CPUX64}
+
+// PVariant(PVarParm)^ := PVariant(Params^)^;
+ PVariant(PVarParm)^ := VarArgGetValue(VAList, PVariant)^;
+{$ELSE}
+// PVariant(PVarParm)^ := PVariant(Params)^;
+ PVariant(PVarParm)^ := VarArgGetValue(VAList, Variant);
+{$ENDIF}
+ end;
+ varUnknown: PVarParm^.VUnknown := VarArgGetValue(VAList, Pointer);
+ varSmallint: PVarParm^.VSmallInt := VarArgGetValue(VAList, SmallInt);
+ varShortInt: PVarParm^.VShortInt := VarArgGetValue(VAList, ShortInt);
+ varByte: PVarParm^.VByte := VarArgGetValue(VAList, Byte);
+ varWord:
+ begin
+ if DispatchUnsignedAsSigned then
+ begin
+ PVarParm^.VType := varInteger;
+ PVarParm^.VInteger := Integer(VarArgGetValue(VAList, Word));
+ end else
+ PVarParm^.VWord := VarArgGetValue(VAList, Word);
+ end;
+ varUInt32:
+ begin
+ if DispatchUnsignedAsSigned then
+ begin
+ PVarParm^.VType := varInteger;
+ PVarParm^.VInteger := Integer(VarArgGetValue(VAList, Cardinal));
+ end else
+ PVarParm^.VUInt32 := VarArgGetValue(VAList, Cardinal);
+ end;
+ varInt64: PVarParm^.VInt64 := VarArgGetValue(VAList, Int64);
+ varUInt64:
+ begin
+ if DispatchUnsignedAsSigned then
+ begin
+ PVarParm^.VType := varInt64;
+ PVarParm^.VInt64 := VarArgGetValue(VAList, Int64); //Int64(PInt64(Params)^);
+ end else
+ PVarParm^.VUInt64 := VarArgGetValue(VAList, UInt64); //PUInt64(Params)^;
+ end;
+ atString:
+ begin
+ PVarParm^.VType := varOleStr;
+ Temp := VarArgGetValue(VAList, Pointer);
+ if AnsiString(Temp) <> '' then
+ begin
+ {
+ This line causes a crash and is replaced with the one below in line with unicode strings
+ PVarParm^.VPointer := PWideChar(Strings[StringCount].FromAnsi(PAnsiString(Temp))^);
+ }
+ PVarParm^.VPointer := PWideChar(Strings[StringCount].FromAnsi(@AnsiString(Temp))^);
+ Strings[StringCount].Ansi := nil;
+ Inc(StringCount);
+ end
+ else
+ PVarParm^.VPointer := _EmptyBSTR;
+ end;
+ atUString:
+ begin
+ PVarParm^.VType := varOleStr;
+ Temp := VarArgGetValue(VAList, Pointer);
+ if UnicodeString(Temp) <> '' then
+ begin
+ PVarParm^.VPointer := PWideChar(Strings[StringCount].FromUnicode(@UnicodeString(Temp))^);
+ Strings[StringCount].Unicode := nil;
+ Inc(StringCount);
+ end
+ else
+ PVarParm^.VPointer := _EmptyBSTR;
+ end;
+ else
+ // Unsupported Var Types
+ //varDecimal = $000E; { vt_decimal 14 } {UNSUPPORTED as of v6.x code base}
+ //varUndef0F = $000F; { undefined 15 } {UNSUPPORTED per Microsoft}
+ //varRecord = $0024; { VT_RECORD 36 }
+ //varString = $0100; { Pascal string 256 } {not OLE compatible }
+ //varAny = $0101; { Corba any 257 } {not OLE compatible }
+ //varUString = $0102; { Unicode string 258 } {not OLE compatible }
+ _DispInvokeError;
+ end;
+ end;
+ end;
+end;
+{$ENDIF CPUARM}
+
{$IFEND}
{$IFDEF DELPHIXE7_OR_HIGHER}
@@ -1295,6 +1661,7 @@ procedure TPythonVariantType.DispInvoke(Dest: PVarData;
Var
NewCallDesc : TCallDesc;
begin
+
if CallDesc^.NamedArgCount > 0 then GetNamedParams;
try
if (CallDesc^.CallType = CPropertyGet) and (CallDesc^.ArgCount = 1) then begin
@@ -2404,8 +2771,8 @@ function TVarPyEnumerator.GetCurrent: Variant;
function TVarPyEnumerator.MoveNext: Boolean;
begin
- Result := True;
try
+ Result := True;
FCurrent := BuiltinModule.next(FIterator);
except
on E: EPyStopIteration do
@@ -2419,7 +2786,7 @@ function TVarPyEnumerator.MoveNext: Boolean;
function VarPyIterate(const AValue: Variant): TVarPyEnumerateHelper;
begin
- Result.Create(AValue);
+ Result := TVarPyEnumerateHelper.Create(AValue);
end;
{ TVarPyEnumerateHelper }
@@ -2431,11 +2798,13 @@ constructor TVarPyEnumerateHelper.Create(const AValue: Variant);
function TVarPyEnumerateHelper.GetEnumerator: TVarPyEnumerator;
begin
- Result.Create(FIterable);
+ Result := TVarPyEnumerator.Create(FIterable);
end;
initialization
PythonVariantType := TPythonVariantType.Create;
+
finalization
FreeAndNil(PythonVariantType);
+
end.
diff --git a/Source/WrapActionList.pas b/Source/WrapActionList.pas
new file mode 100644
index 00000000..940e708b
--- /dev/null
+++ b/Source/WrapActionList.pas
@@ -0,0 +1,240 @@
+unit WrapActionList;
+
+interface
+
+uses
+ System.TypInfo, WrapDelphi, PythonEngine, WrapDelphiClasses, System.Actions,
+ System.Classes;
+
+type
+ TActionEventHandler = class(TEventHandler)
+ protected
+ procedure DoEvent(Action: TBasicAction; var Handled: Boolean);
+ public
+ constructor Create(PyDelphiWrapper : TPyDelphiWrapper; Component : TObject;
+ PropertyInfo : PPropInfo; Callable : PPyObject); override;
+ class function GetTypeInfo : PTypeInfo; override;
+ end;
+
+ TActionListAccess = class(TContainerAccess)
+ private
+ function GetContainer: TContainedActionList;
+ public
+ function GetItem(AIndex: Integer): PPyObject; override;
+ function GetSize: Integer; override;
+ function IndexOf(AValue: PPyObject): Integer; override;
+ class function ExpectedContainerClass: TClass; override;
+ class function SupportsIndexOf: Boolean; override;
+ class function Name: string; override;
+ property Container: TContainedActionList read GetContainer;
+ end;
+
+ TPyDelphiContainedActionList = class(TPyDelphiComponent)
+ private
+ function GetDelphiObject: TContainedActionList;
+ procedure SetDelphiObject(const Value: TContainedActionList);
+ protected
+ function Get_ActionCount(AContext: Pointer): PPyObject; cdecl;
+ function Get_Actions(AContext: Pointer): PPyObject; cdecl;
+ public
+ class function DelphiObjectClass: TClass; override;
+ class procedure RegisterGetSets(PythonType: TPythonType); override;
+ class function GetContainerAccessClass: TContainerAccessClass; override;
+
+ property DelphiObject: TContainedActionList read GetDelphiObject
+ write SetDelphiObject;
+ end;
+
+implementation
+
+type
+ TActnListRegistration = class(TRegisteredUnit)
+ public
+ function Name: string; override;
+ procedure RegisterWrappers(APyDelphiWrapper: TPyDelphiWrapper); override;
+ procedure DefineVars(APyDelphiWrapper: TPyDelphiWrapper); override;
+ end;
+
+{ TActnListRegistration }
+
+procedure TActnListRegistration.DefineVars(APyDelphiWrapper: TPyDelphiWrapper);
+begin
+ inherited;
+end;
+
+function TActnListRegistration.Name: string;
+begin
+ Result := 'ActnList';
+end;
+
+procedure TActnListRegistration.RegisterWrappers(
+ APyDelphiWrapper: TPyDelphiWrapper);
+begin
+ inherited;
+ APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiContainedActionList);
+
+ APyDelphiWrapper.EventHandlers.RegisterHandler(TActionEventHandler);
+end;
+
+{ TActionListAccess }
+
+class function TActionListAccess.ExpectedContainerClass: TClass;
+begin
+ Result := TContainedActionList;
+end;
+
+function TActionListAccess.GetContainer: TContainedActionList;
+begin
+ Result := TContainedActionList(inherited Container);
+end;
+
+function TActionListAccess.GetItem(AIndex: Integer): PPyObject;
+begin
+ Result := Wrap(Container.Actions[AIndex]);
+end;
+
+function TActionListAccess.GetSize: Integer;
+begin
+ Result := Container.ActionCount;
+end;
+
+function TActionListAccess.IndexOf(AValue: PPyObject): Integer;
+var
+ i: Integer;
+ _obj: TPyObject;
+ _item: TContainedAction;
+begin
+ Result := -1;
+ with GetPythonEngine do
+ begin
+ if IsDelphiObject(AValue) then
+ begin
+ _obj := PythonToDelphi(AValue);
+ if (_obj is TPyDelphiObject) and
+ (TPyDelphiObject(_obj).DelphiObject is TContainedAction) then
+ begin
+ _item := TContainedAction(TPyDelphiObject(_obj).DelphiObject);
+ for i := 0 to Container.ActionCount - 1 do
+ if Container.Actions[i] = _item then
+ begin
+ Result := i;
+ Break;
+ end;
+ end;
+ end;
+ end;
+end;
+
+class function TActionListAccess.Name: string;
+begin
+ Result := 'TContainedActionList.Actions';
+end;
+
+class function TActionListAccess.SupportsIndexOf: Boolean;
+begin
+ Result := True;
+end;
+
+
+{ TPyDelphiContainedActionList }
+
+class function TPyDelphiContainedActionList.DelphiObjectClass: TClass;
+begin
+ Result := TContainedActionList;
+end;
+
+class function TPyDelphiContainedActionList.GetContainerAccessClass: TContainerAccessClass;
+begin
+ Result := TActionListAccess;
+end;
+
+function TPyDelphiContainedActionList.GetDelphiObject: TContainedActionList;
+begin
+ Result := TContainedActionList(inherited DelphiObject);
+end;
+
+function TPyDelphiContainedActionList.Get_ActionCount(
+ AContext: Pointer): PPyObject;
+begin
+ Adjust(@Self);
+ Result := GetPythonEngine.PyLong_FromLong(DelphiObject.ActionCount);
+end;
+
+function TPyDelphiContainedActionList.Get_Actions(AContext: Pointer): PPyObject;
+begin
+ Adjust(@Self);
+ Result := PyDelphiWrapper.DefaultContainerType.CreateInstance;
+ with PythonToDelphi(Result) as TPyDelphiContainer do
+ Setup(Self.PyDelphiWrapper, TActionListAccess.Create(Self.PyDelphiWrapper,
+ Self.DelphiObject));
+end;
+
+class procedure TPyDelphiContainedActionList.RegisterGetSets(
+ PythonType: TPythonType);
+begin
+ inherited;
+ with PythonType do
+ begin
+ AddGetSet('ActionCount', @TPyDelphiContainedActionList.Get_ActionCount, nil,
+ 'Indicates the number of actions in the action list.', nil);
+ AddGetSet('Actions', @TPyDelphiContainedActionList.Get_Actions, nil,
+ 'Lists the actions maintained by the action list.', nil);
+ end;
+end;
+
+procedure TPyDelphiContainedActionList.SetDelphiObject(
+ const Value: TContainedActionList);
+begin
+ inherited DelphiObject := Value;
+end;
+
+{ TActionEventHandler }
+
+constructor TActionEventHandler.Create(PyDelphiWrapper: TPyDelphiWrapper;
+ Component: TObject; PropertyInfo: PPropInfo; Callable: PPyObject);
+var
+ Method : TMethod;
+begin
+ inherited;
+ Method.Code := @TActionEventHandler.DoEvent;
+ Method.Data := Self;
+ SetMethodProp(Component, PropertyInfo, Method);
+end;
+
+procedure TActionEventHandler.DoEvent(Action: TBasicAction; var Handled: Boolean);
+var
+ PyAction, PyTuple, PyResult, PyHandled : PPyObject;
+ LVarParam : TPyDelphiVarParameter;
+begin
+ Assert(Assigned(PyDelphiWrapper));
+ if Assigned(Callable) and PythonOK then
+ with GetPythonEngine do begin
+ PyAction := PyDelphiWrapper.Wrap(Action);
+ PyHandled := CreateVarParam(PyDelphiWrapper, Handled);
+ LVarParam := PythonToDelphi(PyHandled) as TPyDelphiVarParameter;
+ PyTuple := PyTuple_New(2);
+ GetPythonEngine.PyTuple_SetItem(PyTuple, 0, PyAction);
+ GetPythonEngine.PyTuple_SetItem(PyTuple, 1, PyHandled);
+ try
+ PyResult := PyObject_CallObject(Callable, PyTuple);
+ if Assigned(PyResult) then
+ begin
+ Py_DECREF(PyResult);
+ Handled := PyObject_IsTrue(LVarParam.Value) = 1;
+ end;
+ finally
+ Py_DECREF(PyTuple);
+ end;
+ CheckError;
+ end;
+end;
+
+class function TActionEventHandler.GetTypeInfo: PTypeInfo;
+begin
+ Result := System.TypeInfo(TActionEvent);
+end;
+
+initialization
+ RegisteredUnits.Add(TActnListRegistration.Create());
+
+end.
diff --git a/Source/WrapActions.pas b/Source/WrapActions.pas
new file mode 100644
index 00000000..2f615368
--- /dev/null
+++ b/Source/WrapActions.pas
@@ -0,0 +1,66 @@
+unit WrapActions;
+
+interface
+
+uses
+ WrapDelphiClasses, System.Classes, System.Actions;
+
+type
+ TPyDelphiContainedAction = class(TPyDelphiBasicAction)
+ private
+ function GetDelphiObject: TContainedAction;
+ procedure SetDelphiObject(const Value: TContainedAction);
+ public
+ class function DelphiObjectClass: TClass; override;
+ property DelphiObject: TContainedAction read GetDelphiObject
+ write SetDelphiObject;
+ end;
+
+implementation
+
+uses
+ WrapDelphi;
+
+type
+ TActionsRegistration = class(TRegisteredUnit)
+ public
+ function Name : string; override;
+ procedure RegisterWrappers(APyDelphiWrapper : TPyDelphiWrapper); override;
+ end;
+
+{ TClassesRegistration }
+
+function TActionsRegistration.Name: string;
+begin
+ Result := 'Actions';
+end;
+
+procedure TActionsRegistration.RegisterWrappers(
+ APyDelphiWrapper: TPyDelphiWrapper);
+begin
+ inherited;
+ APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiContainedAction);
+end;
+
+{ TPyDelphiContainedAction }
+
+class function TPyDelphiContainedAction.DelphiObjectClass: TClass;
+begin
+ Result := TContainedAction;
+end;
+
+function TPyDelphiContainedAction.GetDelphiObject: TContainedAction;
+begin
+ Result := TContainedAction(inherited DelphiObject);
+end;
+
+procedure TPyDelphiContainedAction.SetDelphiObject
+ (const Value: TContainedAction);
+begin
+ inherited DelphiObject := Value;
+end;
+
+initialization
+ RegisteredUnits.Add(TActionsRegistration.Create());
+
+end.
diff --git a/Source/WrapDelphi.pas b/Source/WrapDelphi.pas
index 07bb031b..82ebe77b 100644
--- a/Source/WrapDelphi.pas
+++ b/Source/WrapDelphi.pas
@@ -919,8 +919,8 @@ implementation
rs_NotPublished = 'Event handling is available only for published properties';
rs_ExpectedObject = 'Expected a Pascal object';
rs_ExpectedRecord = 'Expected a Pascal record';
- rs_ExpectedInterface = 'Expected a Pascal interface';
rs_ExpectedClass = 'Expected a Pascal class';
+ rs_ExpectedInterface = 'Expected a Pascal interface';
rs_InvalidClass = 'Invalid class';
rs_ErrEventNotReg = 'No Registered EventHandler for events of type "%s';
rs_ErrEventNoSuport = 'Class %s does not support events because it must '+
@@ -2140,7 +2140,7 @@ class procedure TPyRttiObject.SetupType(PythonType: TPythonType);
begin
inherited;
PythonType.TypeName := 'RttiObject';
- PythonType.Name := string(PythonType.TypeName) + 'Type';
+ PythonType.Name := string(PythonType.TypeName + TPythonType.TYPE_COMP_NAME_SUFFIX);
PythonType.GenerateCreateFunction := False;
PythonType.DocString.Text := 'Wrapper of a Pascal record';
PythonType.Services.Basic := [bsGetAttrO, bsSetAttrO, bsRepr, bsStr];
@@ -2165,7 +2165,7 @@ class procedure TPyPascalRecord.SetupType(PythonType: TPythonType);
begin
inherited;
PythonType.TypeName := 'PascalRecord';
- PythonType.Name := string(PythonType.TypeName) + 'Type';
+ PythonType.Name := string(PythonType.TypeName + TPythonType.TYPE_COMP_NAME_SUFFIX);
end;
{ TPyPascalInterface }
@@ -2179,7 +2179,7 @@ class procedure TPyPascalInterface.SetupType(PythonType: TPythonType);
begin
inherited;
PythonType.TypeName := 'PascalInterface';
- PythonType.Name := string(PythonType.TypeName) + 'Type';
+ PythonType.Name := string(PythonType.TypeName + TPythonType.TYPE_COMP_NAME_SUFFIX);
end;
{$ENDIF}
@@ -2675,7 +2675,7 @@ class procedure TPyDelphiObject.SetupType(PythonType: TPythonType);
begin
inherited;
PythonType.TypeName := AnsiString(GetTypeName);
- PythonType.Name := string(PythonType.TypeName) + 'Type';
+ PythonType.Name := string(PythonType.TypeName + TPythonType.TYPE_COMP_NAME_SUFFIX);
PythonType.GenerateCreateFunction := False;
PythonType.DocString.Text := 'Wrapper for Delphi ' + DelphiObjectClass.ClassName;
PythonType.Services.Basic := [bsGetAttrO, bsSetAttrO, bsRepr, bsStr, bsRichCompare];
@@ -3140,7 +3140,7 @@ class procedure TPyDelphiVarParameter.SetupType(PythonType: TPythonType);
begin
inherited;
PythonType.TypeName := 'VarParameter';
- PythonType.Name := string(PythonType.TypeName) + 'Type';
+ PythonType.Name := string(PythonType.TypeName + TPythonType.TYPE_COMP_NAME_SUFFIX);
PythonType.GenerateCreateFunction := False;
PythonType.DocString.Text := 'Container object allowing modification of Delphi var parameters from Python';
PythonType.Services.Basic := [bsGetAttrO, bsSetAttrO, bsRepr, bsStr, bsRichCompare];
diff --git a/Source/WrapFireDAC.pas b/Source/WrapFireDAC.pas
index 3d07f962..d768d0f3 100644
--- a/Source/WrapFireDAC.pas
+++ b/Source/WrapFireDAC.pas
@@ -10,7 +10,7 @@ interface
uses
Classes, SysUtils, Variants, PythonEngine, WrapDelphi, WrapDelphiClasses,
- Windows, System.AnsiStrings, System.Rtti, DB,
+ System.AnsiStrings, System.Rtti, DB,
FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Error, FireDAC.UI.Intf,
FireDAC.Phys.Intf, FireDAC.Stan.Def, FireDAC.Stan.Pool, FireDAC.Stan.Async,
FireDAC.Phys, FireDAC.Stan.Param, FireDAC.DatS,
diff --git a/Source/fmx/FMX.PythonGUIInputOutput.pas b/Source/fmx/FMX.PythonGUIInputOutput.pas
index 3bb5e82c..38afae86 100644
--- a/Source/fmx/FMX.PythonGUIInputOutput.pas
+++ b/Source/fmx/FMX.PythonGUIInputOutput.pas
@@ -15,7 +15,8 @@ interface
const
PID_SUPPORTED_PLATFORMS = pidWin32 or pidWin64
or pidOSX32 or pidOSX64
- or pidLinux64;
+ or pidLinux64
+ or pidAndroid32Arm or pidAndroid64Arm;
type
[ComponentPlatformsAttribute(PID_SUPPORTED_PLATFORMS)]
diff --git a/Source/fmx/WrapDelphiFmx.pas b/Source/fmx/WrapDelphiFmx.pas
index fd2efc20..dc3d70c5 100644
--- a/Source/fmx/WrapDelphiFmx.pas
+++ b/Source/fmx/WrapDelphiFmx.pas
@@ -7,7 +7,9 @@ implementation
uses
WrapDelphiTypes,
WrapDelphiClasses,
+ {$IFDEF Windows}
WrapDelphiWindows,
+ {$ENDIF Windows}
WrapFireDac,
WrapFmxTypes,
WrapFmxStdCtrls,
@@ -20,6 +22,7 @@ implementation
WrapFmxShapes,
WrapFmxLayouts,
WrapFmxScrollBox,
- WrapFmxGrids;
+ WrapFmxGrids,
+ WrapFmxMedia;
end.
diff --git a/Source/fmx/WrapFmxActnList.pas b/Source/fmx/WrapFmxActnList.pas
index 90b4ded3..9b0adb12 100644
--- a/Source/fmx/WrapFmxActnList.pas
+++ b/Source/fmx/WrapFmxActnList.pas
@@ -1,61 +1,52 @@
{$I ..\Definition.Inc}
-
unit WrapFmxActnList;
interface
uses
- System.Classes, FMX.ActnList, PythonEngine, WrapDelphi, WrapDelphiClasses;
+ System.Classes, FMX.ActnList, PythonEngine, WrapDelphi, WrapDelphiClasses,
+ System.Actions, WrapActions, WrapActionList;
type
- {
- Access to the Action items of the TCustomActionList collection.
- }
- TActionListAccess = class(TContainerAccess)
+ TPyDelphiCustomActionList = class(TPyDelphiContainedActionList)
private
- function GetContainer: TCustomActionList;
+ function GetDelphiObject: TCustomActionList;
+ procedure SetDelphiObject(const Value: TCustomActionList);
public
- function GetItem(AIndex : Integer) : PPyObject; override;
- function GetSize : Integer; override;
- function IndexOf(AValue : PPyObject) : Integer; override;
-
- class function ExpectedContainerClass : TClass; override;
- class function SupportsIndexOf : Boolean; override;
- class function Name : string; override;
-
- property Container : TCustomActionList read GetContainer;
+ class function DelphiObjectClass: TClass; override;
+ property DelphiObject: TCustomActionList read GetDelphiObject
+ write SetDelphiObject;
end;
- {
- PyObject wrapping TCustomActionList
- Exposes properties ActionCount and Actions
- }
- TPyDelphiCustomActionList = class (TPyDelphiComponent)
+ TPyDelphiActionList = class(TPyDelphiCustomActionList)
private
- function GetDelphiObject: TCustomActionList;
- procedure SetDelphiObject(const Value: TCustomActionList);
- protected
- // property getters
- function Get_ActionCount(AContext : Pointer) : PPyObject; cdecl;
- function Get_Actions(AContext : Pointer) : PPyObject; cdecl;
+ function GetDelphiObject: TActionList;
+ procedure SetDelphiObject(const Value: TActionList);
public
// Class methods
- class function DelphiObjectClass : TClass; override;
- class procedure RegisterGetSets( PythonType : TPythonType ); override;
- class function GetContainerAccessClass : TContainerAccessClass; override;
+ class function DelphiObjectClass: TClass; override;
// Properties
- property DelphiObject: TCustomActionList read GetDelphiObject write SetDelphiObject;
+ property DelphiObject: TActionList read GetDelphiObject
+ write SetDelphiObject;
end;
- TPyDelphiActionList = class (TPyDelphiCustomActionList)
+ TPyDelphiCustomAction = class(TPyDelphiContainedAction)
private
- function GetDelphiObject: TActionList;
- procedure SetDelphiObject(const Value: TActionList);
+ function GetDelphiObject: TCustomAction;
+ procedure SetDelphiObject(const Value: TCustomAction);
public
- // Class methods
- class function DelphiObjectClass : TClass; override;
- // Properties
- property DelphiObject: TActionList read GetDelphiObject write SetDelphiObject;
+ class function DelphiObjectClass: TClass; override;
+ property DelphiObject: TCustomAction read GetDelphiObject
+ write SetDelphiObject;
+ end;
+
+ TPyDelphiAction = class(TPyDelphiContainedAction)
+ private
+ function GetDelphiObject: TAction;
+ procedure SetDelphiObject(const Value: TAction);
+ public
+ class function DelphiObjectClass: TClass; override;
+ property DelphiObject: TAction read GetDelphiObject write SetDelphiObject;
end;
implementation
@@ -64,13 +55,12 @@ implementation
type
TActnListRegistration = class(TRegisteredUnit)
public
- function Name : string; override;
- procedure RegisterWrappers(APyDelphiWrapper : TPyDelphiWrapper); override;
- procedure DefineVars(APyDelphiWrapper : TPyDelphiWrapper); override;
+ function Name: string; override;
+ procedure RegisterWrappers(APyDelphiWrapper: TPyDelphiWrapper); override;
+ procedure DefineVars(APyDelphiWrapper: TPyDelphiWrapper); override;
end;
-{ TActnListRegistration }
-
+ { TActnListRegistration }
procedure TActnListRegistration.DefineVars(APyDelphiWrapper: TPyDelphiWrapper);
begin
inherited;
@@ -78,142 +68,88 @@ procedure TActnListRegistration.DefineVars(APyDelphiWrapper: TPyDelphiWrapper);
function TActnListRegistration.Name: string;
begin
- Result := 'ActnList';
+ Result := 'FMX ActnList';
end;
-procedure TActnListRegistration.RegisterWrappers(APyDelphiWrapper: TPyDelphiWrapper);
+procedure TActnListRegistration.RegisterWrappers(APyDelphiWrapper
+ : TPyDelphiWrapper);
begin
inherited;
APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiCustomActionList);
APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiActionList);
+ APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiCustomAction);
+ APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiAction);
end;
{ TPyDelphiCustomActionList }
-
class function TPyDelphiCustomActionList.DelphiObjectClass: TClass;
begin
Result := TCustomActionList;
end;
-class function TPyDelphiCustomActionList.GetContainerAccessClass: TContainerAccessClass;
-begin
- Result := TActionListAccess;
-end;
-
function TPyDelphiCustomActionList.GetDelphiObject: TCustomActionList;
begin
Result := TCustomActionList(inherited DelphiObject);
end;
-function TPyDelphiCustomActionList.Get_ActionCount(AContext: Pointer): PPyObject;
-begin
- Adjust(@Self);
- Result := GetPythonEngine.PyLong_FromLong(DelphiObject.ActionCount);
-end;
-
-function TPyDelphiCustomActionList.Get_Actions(AContext: Pointer): PPyObject;
-begin
- Adjust(@Self);
- Result := PyDelphiWrapper.DefaultContainerType.CreateInstance;
- with PythonToDelphi(Result) as TPyDelphiContainer do
- Setup(Self.PyDelphiWrapper, TActionListAccess.Create(Self.PyDelphiWrapper, Self.DelphiObject));
-end;
-
-class procedure TPyDelphiCustomActionList.RegisterGetSets(
- PythonType: TPythonType);
-begin
- inherited;
- with PythonType do
- begin
- AddGetSet('ActionCount', @TPyDelphiCustomActionList.Get_ActionCount, nil,
- 'Indicates the number of actions in the action list.', nil);
- AddGetSet('Actions', @TPyDelphiCustomActionList.Get_Actions, nil,
- 'Lists the actions maintained by the action list.', nil);
- end;
-end;
-
-procedure TPyDelphiCustomActionList.SetDelphiObject(
- const Value: TCustomActionList);
+procedure TPyDelphiCustomActionList.SetDelphiObject
+ (const Value: TCustomActionList);
begin
inherited DelphiObject := Value;
end;
-{ TActionListAccess }
+{ TPyDelphiActionList }
-class function TActionListAccess.ExpectedContainerClass: TClass;
+class function TPyDelphiActionList.DelphiObjectClass: TClass;
begin
- Result := TCustomActionList;
+ Result := TActionList;
end;
-function TActionListAccess.GetContainer: TCustomActionList;
+function TPyDelphiActionList.GetDelphiObject: TActionList;
begin
- Result := TCustomActionList(inherited Container);
+ Result := TActionList(inherited DelphiObject);
end;
-function TActionListAccess.GetItem(AIndex: Integer): PPyObject;
+procedure TPyDelphiActionList.SetDelphiObject(const Value: TActionList);
begin
- Result := Wrap(Container.Actions[AIndex]);
+ inherited DelphiObject := Value;
end;
-function TActionListAccess.GetSize: Integer;
-begin
- Result := Container.ActionCount;
-end;
+{ TPyDelphiCustomAction }
-function TActionListAccess.IndexOf(AValue: PPyObject): Integer;
-var
- i : Integer;
- _obj : TPyObject;
- _item : TBasicAction;
+class function TPyDelphiCustomAction.DelphiObjectClass: TClass;
begin
- Result := -1;
- with GetPythonEngine do
- begin
- if IsDelphiObject(AValue) then
- begin
- _obj := PythonToDelphi(AValue);
- if (_obj is TPyDelphiObject) and (TPyDelphiObject(_obj).DelphiObject is TBasicAction) then
- begin
- _item := TBasicAction(TPyDelphiObject(_obj).DelphiObject);
- for i := 0 to Container.ActionCount-1 do
- if Container.Actions[i] = _item then
- begin
- Result := i;
- Break;
- end;
- end;
- end;
- end;
+ Result := TCustomAction;
end;
-class function TActionListAccess.Name: string;
+function TPyDelphiCustomAction.GetDelphiObject: TCustomAction;
begin
- Result := 'TCustomActionList.Actions';
+ Result := TCustomAction(inherited DelphiObject);
end;
-class function TActionListAccess.SupportsIndexOf: Boolean;
+procedure TPyDelphiCustomAction.SetDelphiObject(const Value: TCustomAction);
begin
- Result := True;
+ inherited DelphiObject := Value;
end;
-{ TPyDelphiActionList }
+{ TPyDelphiAction }
-class function TPyDelphiActionList.DelphiObjectClass: TClass;
+class function TPyDelphiAction.DelphiObjectClass: TClass;
begin
- Result := TActionList;
+ Result := TAction;
end;
-function TPyDelphiActionList.GetDelphiObject: TActionList;
+function TPyDelphiAction.GetDelphiObject: TAction;
begin
- Result := TActionList(inherited DelphiObject);
+ Result := TAction(inherited DelphiObject);
end;
-procedure TPyDelphiActionList.SetDelphiObject(const Value: TActionList);
+procedure TPyDelphiAction.SetDelphiObject(const Value: TAction);
begin
inherited DelphiObject := Value;
end;
initialization
- RegisteredUnits.Add( TActnListRegistration.Create );
+ RegisteredUnits.Add(TActnListRegistration.Create());
end.
diff --git a/Source/fmx/WrapFmxComCtrls.pas b/Source/fmx/WrapFmxComCtrls.pas
index 4012d6e5..f4f752d1 100644
--- a/Source/fmx/WrapFmxComCtrls.pas
+++ b/Source/fmx/WrapFmxComCtrls.pas
@@ -18,6 +18,16 @@ TPyDelphiTabControl = class(TPyDelphiStyledControl)
property DelphiObject: TTabControl read GetDelphiObject write SetDelphiObject;
end;
+ TPyDelphiTabItem = class(TPyDelphiTextControl)
+ private
+ function GetDelphiObject: TTabItem;
+ procedure SetDelphiObject(const Value: TTabItem);
+ public
+ class function DelphiObjectClass: TClass; override;
+ // Properties
+ property DelphiObject: TTabItem read GetDelphiObject write SetDelphiObject;
+ end;
+
TPyDelphiCustomMultiView = class(TPyDelphiPresentedControl)
private
function GetDelphiObject: TCustomMultiView;
@@ -69,6 +79,7 @@ procedure TComCtrlsRegistration.RegisterWrappers(
begin
inherited;
APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiTabControl);
+ APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiTabItem);
APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiCustomMultiView);
APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiMultiView);
end;
@@ -90,7 +101,24 @@ procedure TPyDelphiTabControl.SetDelphiObject(const Value: TTabControl);
inherited DelphiObject := Value;
end;
- { TPyDelphiCustomMultiView }
+{ TPyDelphiTabItem }
+
+class function TPyDelphiTabItem.DelphiObjectClass: TClass;
+begin
+ Result := TTabItem;
+end;
+
+function TPyDelphiTabItem.GetDelphiObject: TTabItem;
+begin
+ Result := TTabItem(inherited DelphiObject);
+end;
+
+procedure TPyDelphiTabItem.SetDelphiObject(const Value: TTabItem);
+begin
+ inherited DelphiObject := Value;
+end;
+
+{ TPyDelphiCustomMultiView }
class function TPyDelphiCustomMultiView.DelphiObjectClass: TClass;
begin
diff --git a/Source/fmx/WrapFmxForms.pas b/Source/fmx/WrapFmxForms.pas
index b642c0d9..a6954a83 100644
--- a/Source/fmx/WrapFmxForms.pas
+++ b/Source/fmx/WrapFmxForms.pas
@@ -6,7 +6,8 @@ interface
uses
System.Classes, System.SysUtils, FMX.Forms,
- PythonEngine, WrapFmxTypes, WrapDelphiClasses, WrapFmxControls;
+ PythonEngine, WrapFmxTypes, WrapDelphiClasses, WrapFmxControls, WrapDelphi,
+ System.TypInfo, System.UITypes;
type
TPyDelphiApplication = class(TPyDelphiComponent)
@@ -20,6 +21,24 @@ TPyDelphiApplication = class(TPyDelphiComponent)
property DelphiObject: TApplication read GetDelphiObject write SetDelphiObject;
end;
+ TCloseQueryEventHandler = class(TEventHandler)
+ protected
+ procedure DoEvent(Sender: TObject; var CanClose : Boolean);
+ public
+ constructor Create(PyDelphiWrapper : TPyDelphiWrapper; Component : TObject;
+ PropertyInfo : PPropInfo; Callable : PPyObject); override;
+ class function GetTypeInfo : PTypeInfo; override;
+ end;
+
+ TCloseEventHandler = class(TEventHandler)
+ protected
+ procedure DoEvent(Sender: TObject; var Action: TCloseAction);
+ public
+ constructor Create(PyDelphiWrapper : TPyDelphiWrapper; Component : TObject;
+ PropertyInfo : PPropInfo; Callable : PPyObject); override;
+ class function GetTypeInfo : PTypeInfo; override;
+ end;
+
TPyDelphiCommonCustomForm = class(TPyDelphiFmxObject)
private
function GetDelphiObject: TCommonCustomForm;
@@ -93,7 +112,7 @@ EInvalidFormClass = class(Exception);
implementation
uses
- WrapDelphi, System.Types;
+ System.Types;
{ Register the wrappers, the globals and the constants }
type
@@ -137,6 +156,9 @@ procedure TFormsRegistration.RegisterWrappers(
APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiForm);
APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiFrame);
APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiScreen);
+
+ APyDelphiWrapper.EventHandlers.RegisterHandler(TCloseQueryEventHandler);
+ APyDelphiWrapper.EventHandlers.RegisterHandler(TCloseEventHandler);
end;
{ TPyDelphiApplication }
@@ -156,6 +178,101 @@ procedure TPyDelphiApplication.SetDelphiObject(const Value: TApplication);
inherited DelphiObject := Value;
end;
+{ TCloseQueryEventHandler }
+
+constructor TCloseQueryEventHandler.Create(PyDelphiWrapper: TPyDelphiWrapper;
+ Component: TObject; PropertyInfo: PPropInfo; Callable: PPyObject);
+var
+ LMethod : TMethod;
+begin
+ inherited;
+ LMethod.Code := @TCloseQueryEventHandler.DoEvent;
+ LMethod.Data := Self;
+ SetMethodProp(Component, PropertyInfo, LMethod);
+end;
+
+procedure TCloseQueryEventHandler.DoEvent(Sender: TObject;
+ var CanClose: Boolean);
+var
+ LPyObject, LPyTuple, LPyResult, LPyCanClose : PPyObject;
+ LVarParam : TPyDelphiVarParameter;
+begin
+ Assert(Assigned(PyDelphiWrapper));
+ if Assigned(Callable) and PythonOK then
+ with GetPythonEngine do begin
+ LPyObject := PyDelphiWrapper.Wrap(Sender);
+ LPyCanClose := CreateVarParam(PyDelphiWrapper, CanClose);
+ LVarParam := PythonToDelphi(LPyCanClose) as TPyDelphiVarParameter;
+ LPyTuple := PyTuple_New(2);
+ GetPythonEngine.PyTuple_SetItem(LPyTuple, 0, LPyObject);
+ GetPythonEngine.PyTuple_SetItem(LPyTuple, 1, LPyCanClose);
+ try
+ LPyResult := PyObject_CallObject(Callable, LPyTuple);
+ if Assigned(LPyResult) then
+ begin
+ Py_DECREF(LPyResult);
+ CanClose := PyObject_IsTrue(LVarParam.Value) = 1;
+ end;
+ finally
+ Py_DECREF(LPyTuple);
+ end;
+ CheckError;
+ end;
+end;
+
+class function TCloseQueryEventHandler.GetTypeInfo: PTypeInfo;
+begin
+ Result := System.TypeInfo(TCloseQueryEvent);
+end;
+
+{ TCloseEventHandler }
+
+constructor TCloseEventHandler.Create(PyDelphiWrapper: TPyDelphiWrapper;
+ Component: TObject; PropertyInfo: PPropInfo; Callable: PPyObject);
+var
+ LMethod : TMethod;
+begin
+ inherited;
+ LMethod.Code := @TCloseEventHandler.DoEvent;
+ LMethod.Data := Self;
+ SetMethodProp(Component, PropertyInfo, LMethod);
+end;
+
+procedure TCloseEventHandler.DoEvent(Sender: TObject; var Action: TCloseAction);
+var
+ LPyObject, LPyTuple, LPyResult, LPyAction : PPyObject;
+ LVarParam : TPyDelphiVarParameter;
+begin
+ Assert(Assigned(PyDelphiWrapper));
+ if Assigned(Callable) and PythonOK then
+ with GetPythonEngine do begin
+ LPyObject := PyDelphiWrapper.Wrap(Sender);
+ LPyAction := CreateVarParam(PyDelphiWrapper, NativeInt(Action));
+ LVarParam := PythonToDelphi(LPyAction) as TPyDelphiVarParameter;
+ LPyTuple := PyTuple_New(2);
+ GetPythonEngine.PyTuple_SetItem(LPyTuple, 0, LPyObject);
+ GetPythonEngine.PyTuple_SetItem(LPyTuple, 1, LPyAction);
+ try
+ LPyResult := PyObject_CallObject(Callable, LPyTuple);
+ if Assigned(LPyResult) then
+ begin
+ Py_DECREF(LPyResult);
+ if PyLong_Check(LVarParam.Value) and
+ CheckEnum('TCloseAction', PyLong_AsLong(LVarParam.Value), Ord(Low(TCloseAction)), Ord(High(TCloseAction))) then
+ Action := TCloseAction(PyLong_AsLong(LVarParam.Value));
+ end;
+ finally
+ Py_DECREF(LPyTuple);
+ end;
+ CheckError;
+ end;
+end;
+
+class function TCloseEventHandler.GetTypeInfo: PTypeInfo;
+begin
+ Result := System.TypeInfo(TCloseEvent);
+end;
+
{ TPyDelphiCommonCustomForm }
function TPyDelphiCommonCustomForm.CreateComponent(
@@ -312,7 +429,7 @@ procedure TPyDelphiScreen.SetDelphiObject(const Value: TScreen);
inherited DelphiObject := Value;
end;
-initialization
+Initialization
RegisteredUnits.Add(TFormsRegistration.Create);
end.
diff --git a/Source/fmx/WrapFmxLayouts.pas b/Source/fmx/WrapFmxLayouts.pas
index 965c7d2e..4c4b0543 100644
--- a/Source/fmx/WrapFmxLayouts.pas
+++ b/Source/fmx/WrapFmxLayouts.pas
@@ -5,7 +5,7 @@
interface
uses
- FMX.Layouts, FMX.BufferedLayout, WrapDelphi, WrapFmxControls;
+ FMX.Layouts, {$IFNDEF LINUX}FMX.BufferedLayout,{$ENDIF LINUX} WrapDelphi, WrapFmxControls;
type
TPyDelphiLayout = class(TPyDelphiControl)
@@ -118,6 +118,7 @@ TPyDelphiFlowLayout = class(TPyDelphiControl)
property DelphiObject: TFlowLayout read GetDelphiObject write SetDelphiObject;
end;
+ {$IFNDEF LINUX}
TPyDelphiCustomBufferedLayout = class(TPyDelphiLayout)
private
function GetDelphiObject: TCustomBufferedLayout;
@@ -137,6 +138,7 @@ TPyDelphiBufferedLayout = class(TPyDelphiCustomBufferedLayout)
// Properties
property DelphiObject: TBufferedLayout read GetDelphiObject write SetDelphiObject;
end;
+ {$ENDIF LINUX}
implementation
@@ -176,8 +178,10 @@ procedure TLayoutsRegistration.RegisterWrappers(
APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiGridLayout);
APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiGridPanelLayout);
APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiFlowLayout);
+ {$IFNDEF LINUX}
APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiCustomBufferedLayout);
APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiBufferedLayout);
+ {$ENDIF LINUX}
end;
{ TPyDelphiLayout }
@@ -371,6 +375,7 @@ procedure TPyDelphiFlowLayout.SetDelphiObject(const Value: TFlowLayout);
inherited DelphiObject := Value;
end;
+{$IFNDEF LINUX}
{ TPyDelphiCustomBufferedLayout }
class function TPyDelphiCustomBufferedLayout.DelphiObjectClass: TClass;
@@ -405,6 +410,7 @@ procedure TPyDelphiBufferedLayout.SetDelphiObject(const Value: TBufferedLayout);
begin
inherited DelphiObject := Value;
end;
+{$ENDIF LINUX}
initialization
RegisteredUnits.Add(TLayoutsRegistration.Create);
diff --git a/Source/fmx/WrapFmxMedia.pas b/Source/fmx/WrapFmxMedia.pas
new file mode 100644
index 00000000..f63e19d8
--- /dev/null
+++ b/Source/fmx/WrapFmxMedia.pas
@@ -0,0 +1,139 @@
+{$I ..\Definition.Inc}
+unit WrapFmxMedia;
+
+interface
+
+uses
+ PythonEngine, WrapFmxTypes, FMX.Media, WrapDelphi, System.TypInfo;
+
+type
+ TSampleBufferReadyEventHandler = class(TEventHandler)
+ protected
+ procedure DoEvent(Sender: TObject; const ATime: TMediaTime);
+ public
+ constructor Create(PyDelphiWrapper: TPyDelphiWrapper; Component: TObject;
+ PropertyInfo: PPropInfo; Callable: PPyObject); override;
+ class function GetTypeInfo: PTypeInfo; override;
+ end;
+
+ TPyDelphiCameraComponent = class(TPyDelphiFmxObject)
+ private
+ function GetDelphiObject: TCameraComponent;
+ procedure SetDelphiObject(const Value: TCameraComponent);
+ public
+ class function DelphiObjectClass: TClass; override;
+ class procedure RegisterGetSets(PythonType: TPythonType); override;
+ class procedure RegisterMethods(PythonType: TPythonType); override;
+ public
+ property DelphiObject: TCameraComponent read GetDelphiObject
+ write SetDelphiObject;
+ end;
+
+implementation
+
+type
+ TFMXMediaRegistration = class(TRegisteredUnit)
+ public
+ function Name: string; override;
+ procedure RegisterWrappers(APyDelphiWrapper: TPyDelphiWrapper); override;
+ procedure DefineVars(APyDelphiWrapper: TPyDelphiWrapper); override;
+ end;
+
+ { TFMXMediaRegistration }
+
+function TFMXMediaRegistration.Name: string;
+begin
+ Result := 'Media';
+end;
+
+procedure TFMXMediaRegistration.DefineVars(APyDelphiWrapper: TPyDelphiWrapper);
+begin
+ inherited;
+end;
+
+procedure TFMXMediaRegistration.RegisterWrappers(APyDelphiWrapper
+ : TPyDelphiWrapper);
+begin
+ inherited;
+ APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiCameraComponent);
+
+ APyDelphiWrapper.EventHandlers.RegisterHandler(TSampleBufferReadyEventHandler);
+end;
+
+{ TSampleBufferReadyEventHandler }
+
+constructor TSampleBufferReadyEventHandler.Create(PyDelphiWrapper
+ : TPyDelphiWrapper; Component: TObject; PropertyInfo: PPropInfo;
+ Callable: PPyObject);
+var
+ Method : TMethod;
+begin
+ inherited;
+ Method.Code := @TSampleBufferReadyEventHandler.DoEvent;
+ Method.Data := Self;
+ SetMethodProp(Component, PropertyInfo, Method);
+end;
+
+procedure TSampleBufferReadyEventHandler.DoEvent(Sender: TObject;
+ const ATime: TMediaTime);
+var
+ PySender, PyTuple, PyResult, PyTime : PPyObject;
+begin
+ Assert(Assigned(PyDelphiWrapper));
+ if Assigned(Callable) and PythonOK then
+ with GetPythonEngine do begin
+ PySender := PyDelphiWrapper.Wrap(Sender);
+ PyTime := PyLong_FromLong(ATime);
+ PyTuple := PyTuple_New(2);
+ GetPythonEngine.PyTuple_SetItem(PyTuple, 0, PySender);
+ GetPythonEngine.PyTuple_SetItem(PyTuple, 1, PyTime);
+ try
+ PyResult := PyObject_CallObject(Callable, PyTuple);
+ Py_XDECREF(PyResult);
+ finally
+ Py_DECREF(PyTuple);
+ end;
+ CheckError;
+ end;
+end;
+
+class function TSampleBufferReadyEventHandler.GetTypeInfo: PTypeInfo;
+begin
+ Result := System.TypeInfo(TSampleBufferReadyEvent);
+end;
+
+{ TPyDelphiCameraComponent }
+
+class function TPyDelphiCameraComponent.DelphiObjectClass: TClass;
+begin
+ Result := TCameraComponent;
+end;
+
+class procedure TPyDelphiCameraComponent.RegisterGetSets
+ (PythonType: TPythonType);
+begin
+ inherited;
+end;
+
+class procedure TPyDelphiCameraComponent.RegisterMethods
+ (PythonType: TPythonType);
+begin
+ inherited;
+end;
+
+function TPyDelphiCameraComponent.GetDelphiObject: TCameraComponent;
+begin
+ Result := TCameraComponent(inherited DelphiObject);
+end;
+
+procedure TPyDelphiCameraComponent.SetDelphiObject
+ (const Value: TCameraComponent);
+begin
+ inherited DelphiObject := Value;
+end;
+
+initialization
+
+RegisteredUnits.Add(TFMXMediaRegistration.Create());
+
+end.
diff --git a/Source/vcl/WrapDelphiVCL.pas b/Source/vcl/WrapDelphiVCL.pas
index 7aba27f2..241f9c2d 100644
--- a/Source/vcl/WrapDelphiVCL.pas
+++ b/Source/vcl/WrapDelphiVCL.pas
@@ -22,6 +22,8 @@ implementation
WrapVclExtCtrls,
WrapVclButtons,
WrapVclGrids,
- WrapVclSamplesSpin;
+ WrapVclSamplesSpin,
+ WrapVclWinXCtrls,
+ WrapVclThemes;
end.
diff --git a/Source/vcl/WrapVclComCtrls.pas b/Source/vcl/WrapVclComCtrls.pas
index c70bd46e..cfe66f7a 100644
--- a/Source/vcl/WrapVclComCtrls.pas
+++ b/Source/vcl/WrapVclComCtrls.pas
@@ -103,6 +103,16 @@ TPyDelphiPageControl = class (TPyDelphiWinControl)
property DelphiObject: TPageControl read GetDelphiObject write SetDelphiObject;
end;
+ TPyDelphiTrackBar = class (TPyDelphiWinControl)
+ private
+ function GetDelphiObject: TTrackBar;
+ procedure SetDelphiObject(const Value: TTrackBar);
+ public
+ class function DelphiObjectClass : TClass; override;
+ // Properties
+ property DelphiObject: TTrackBar read GetDelphiObject write SetDelphiObject;
+ end;
+
implementation
uses
@@ -137,6 +147,7 @@ procedure TComCtrlsRegistration.RegisterWrappers(APyDelphiWrapper: TPyDelphiWrap
{$ENDIF FPC}
APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiPageControl);
APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiTabSheet);
+ APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiTrackBar);
APyDelphiWrapper.EventHandlers.RegisterHandler(TTabChangingEventHandler);
end;
@@ -613,6 +624,23 @@ class function TTabChangingEventHandler.GetTypeInfo: PTypeInfo;
Result := System.TypeInfo(TTabChangingEvent);
end;
+{ TPyDelphiTrackBar }
+
+class function TPyDelphiTrackBar.DelphiObjectClass: TClass;
+begin
+ Result := TTrackBar;
+end;
+
+function TPyDelphiTrackBar.GetDelphiObject: TTrackBar;
+begin
+ Result := TTrackBar(inherited DelphiObject);
+end;
+
+procedure TPyDelphiTrackBar.SetDelphiObject(const Value: TTrackBar);
+begin
+ inherited DelphiObject := Value;
+end;
+
initialization
RegisteredUnits.Add( TComCtrlsRegistration.Create );
{$IFNDEF FPC}
diff --git a/Source/vcl/WrapVclThemes.pas b/Source/vcl/WrapVclThemes.pas
new file mode 100644
index 00000000..6288ddb0
--- /dev/null
+++ b/Source/vcl/WrapVclThemes.pas
@@ -0,0 +1,165 @@
+{$I ..\Definition.Inc}
+unit WrapVclThemes;
+
+interface
+
+uses
+ PythonEngine, WrapDelphi, Vcl.Themes;
+
+type
+ TPyDelphiStyleManager = class(TPyDelphiObject)
+ private
+ function GetDelphiObject: TStyleManager;
+ procedure SetDelphiObject(const Value: TStyleManager);
+ protected
+ function Get_StyleNames(AContext: Pointer): PPyObject; cdecl;
+ function Get_ActiveStyle(AContext: Pointer): PPyObject; cdecl;
+ public
+ constructor Create( APythonType : TPythonType ); override;
+ constructor CreateWith(APythonType: TPythonType; args: PPyObject); override;
+
+ class function DelphiObjectClass : TClass; override;
+ class procedure RegisterGetSets(PythonType: TPythonType); override;
+ class procedure RegisterMethods(PythonType: TPythonType); override;
+
+ property DelphiObject: TStyleManager read GetDelphiObject write SetDelphiObject;
+ end;
+
+ TStyleManagerStyleNamesAccess = class(TContainerAccess)
+ private
+ function GetContainer: TStyleManager;
+ public
+ class function ExpectedContainerClass: TClass; override;
+ class function Name: string; override;
+
+ function GetItem(AIndex: Integer): PPyObject; override;
+ function GetSize: Integer; override;
+
+ property Container : TStyleManager read GetContainer;
+ end;
+
+implementation
+
+uses
+ Vcl.Controls;
+
+{ Register the wrappers, the globals and the constants }
+type
+ TVclThemesRegistration = class(TRegisteredUnit)
+ public
+ function Name: string; override;
+ procedure RegisterWrappers(APyDelphiWrapper: TPyDelphiWrapper); override;
+ procedure DefineVars(APyDelphiWrapper: TPyDelphiWrapper); override;
+ end;
+
+{ TVclThemesRegistration }
+
+procedure TVclThemesRegistration.DefineVars(APyDelphiWrapper: TPyDelphiWrapper);
+begin
+ inherited;
+end;
+
+function TVclThemesRegistration.Name: string;
+begin
+ Result := 'VclThemes';
+end;
+
+procedure TVclThemesRegistration.RegisterWrappers(
+ APyDelphiWrapper: TPyDelphiWrapper);
+begin
+ inherited;
+ APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiStyleManager);
+end;
+
+{ TPyDelphiStyleManager }
+
+constructor TPyDelphiStyleManager.Create(APythonType: TPythonType);
+begin
+ inherited;
+end;
+
+constructor TPyDelphiStyleManager.CreateWith(APythonType: TPythonType;
+ args: PPyObject);
+begin
+ inherited;
+ DelphiObject := TStyleManager.Create();
+end;
+
+class function TPyDelphiStyleManager.DelphiObjectClass: TClass;
+begin
+ Result := TStyleManager;
+end;
+
+function TPyDelphiStyleManager.GetDelphiObject: TStyleManager;
+begin
+ Result := TStyleManager(inherited DelphiObject);
+end;
+
+function TPyDelphiStyleManager.Get_ActiveStyle(
+ AContext: Pointer): PPyObject;
+begin
+ Adjust(@Self);
+ Result := Wrap(DelphiObject.ActiveStyle);
+end;
+
+function TPyDelphiStyleManager.Get_StyleNames(AContext: Pointer): PPyObject;
+begin
+ Adjust(@Self);
+ Result := Self.PyDelphiWrapper.DefaultContainerType.CreateInstance;
+ with PythonToDelphi(Result) as TPyDelphiContainer do
+ Setup(Self.PyDelphiWrapper,
+ TStyleManagerStyleNamesAccess.Create(Self.PyDelphiWrapper, Self.DelphiObject));
+end;
+
+class procedure TPyDelphiStyleManager.RegisterGetSets(PythonType: TPythonType);
+begin
+ inherited;
+ with PythonType do begin
+ AddGetSet('StyleNames', @TPyDelphiStyleManager.Get_StyleNames, nil,
+ 'Provides access to the VCL style names.', nil);
+ AddGetSet('ActiveStyle', @TPyDelphiStyleManager.Get_ActiveStyle, nil,
+ 'Returns the current style.', nil);
+ end;
+end;
+
+class procedure TPyDelphiStyleManager.RegisterMethods(PythonType: TPythonType);
+begin
+ inherited;
+end;
+
+procedure TPyDelphiStyleManager.SetDelphiObject(const Value: TStyleManager);
+begin
+ inherited DelphiObject := Value;
+end;
+
+{ TStyleManagerStyleNamesAccess }
+
+class function TStyleManagerStyleNamesAccess.ExpectedContainerClass: TClass;
+begin
+ Result := TStyleManager;
+end;
+
+function TStyleManagerStyleNamesAccess.GetContainer: TStyleManager;
+begin
+ Result := TStyleManager(inherited Container);
+end;
+
+function TStyleManagerStyleNamesAccess.GetItem(AIndex: Integer): PPyObject;
+begin
+ Result := GetPythonEngine().PyUnicodeFromString(Container.StyleNames[AIndex]);
+end;
+
+function TStyleManagerStyleNamesAccess.GetSize: Integer;
+begin
+ Result := Length(Container.StyleNames);
+end;
+
+class function TStyleManagerStyleNamesAccess.Name: string;
+begin
+ Result := 'TStyleManager.StyleNames';
+end;
+
+initialization
+ RegisteredUnits.Add(TVclThemesRegistration.Create());
+
+end.
diff --git a/Source/vcl/WrapVclWinXCtrls.pas b/Source/vcl/WrapVclWinXCtrls.pas
new file mode 100644
index 00000000..ab1f1418
--- /dev/null
+++ b/Source/vcl/WrapVclWinXCtrls.pas
@@ -0,0 +1,101 @@
+{$I ..\Definition.Inc}
+unit WrapVclWinXCtrls;
+
+interface
+
+uses
+ Vcl.WinXCtrls, WrapVclControls;
+
+type
+ TPyDelphiCustomActivityIndicator = class (TPyDelphiCustomControl)
+ private
+ function GetDelphiObject: TCustomActivityIndicator;
+ procedure SetDelphiObject(const Value: TCustomActivityIndicator);
+ public
+ class function DelphiObjectClass : TClass; override;
+ property DelphiObject: TCustomActivityIndicator read GetDelphiObject write SetDelphiObject;
+ end;
+
+ TPyDelphiActivityIndicator = class (TPyDelphiCustomActivityIndicator)
+ private
+ function GetDelphiObject: TActivityIndicator;
+ procedure SetDelphiObject(const Value: TActivityIndicator);
+ public
+ class function DelphiObjectClass : TClass; override;
+ property DelphiObject: TActivityIndicator read GetDelphiObject write SetDelphiObject;
+ end;
+
+implementation
+
+uses
+ WrapDelphi;
+
+{ Register the wrappers, the globals and the constants }
+type
+ TWinXCtrlsRegistration = class(TRegisteredUnit)
+ public
+ function Name: string; override;
+ procedure RegisterWrappers(APyDelphiWrapper: TPyDelphiWrapper); override;
+ procedure DefineVars(APyDelphiWrapper: TPyDelphiWrapper); override;
+ end;
+
+{ TComCtrlsRegistration }
+
+procedure TWinXCtrlsRegistration.DefineVars(APyDelphiWrapper: TPyDelphiWrapper);
+begin
+ inherited;
+end;
+
+function TWinXCtrlsRegistration.Name: string;
+begin
+ Result := 'WinXCtrls';
+end;
+
+procedure TWinXCtrlsRegistration.RegisterWrappers(
+ APyDelphiWrapper: TPyDelphiWrapper);
+begin
+ inherited;
+ APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiCustomActivityIndicator);
+ APyDelphiWrapper.RegisterDelphiWrapper(TPyDelphiActivityIndicator);
+end;
+
+{ TPyDelphiCustomActivityIndicator }
+
+class function TPyDelphiCustomActivityIndicator.DelphiObjectClass: TClass;
+begin
+ Result := TCustomActivityIndicator;
+end;
+
+function TPyDelphiCustomActivityIndicator.GetDelphiObject: TCustomActivityIndicator;
+begin
+ Result := TCustomActivityIndicator(inherited DelphiObject);
+end;
+
+procedure TPyDelphiCustomActivityIndicator.SetDelphiObject(
+ const Value: TCustomActivityIndicator);
+begin
+ inherited DelphiObject := Value;
+end;
+
+{ TPyDelphiActivityIndicator }
+
+class function TPyDelphiActivityIndicator.DelphiObjectClass: TClass;
+begin
+ Result := TActivityIndicator;
+end;
+
+function TPyDelphiActivityIndicator.GetDelphiObject: TActivityIndicator;
+begin
+ Result := TActivityIndicator(inherited DelphiObject);
+end;
+
+procedure TPyDelphiActivityIndicator.SetDelphiObject(
+ const Value: TActivityIndicator);
+begin
+ inherited DelphiObject := Value;
+end;
+
+initialization
+ RegisteredUnits.Add(TWinXCtrlsRegistration.Create());
+
+end.
diff --git a/Tests/FMX/Android/MethodCallBackTest.pas b/Tests/FMX/Android/MethodCallBackTest.pas
new file mode 100644
index 00000000..f4d2044f
--- /dev/null
+++ b/Tests/FMX/Android/MethodCallBackTest.pas
@@ -0,0 +1,262 @@
+(**************************************************************************)
+(* *)
+(* Module: Unit 'MethodCallbackTest' Copyright (c) 2021 *)
+(* *)
+(* Lucas Moura Belo - lmbelo *)
+(* lucas.belo@live.com *)
+(* BH, Brazil *)
+(* *)
+(* PyScripter *)
+(* e-mail: pyscripter@gmail.com *)
+(* *)
+(* Project pages: https://github.com/Embarcadero/python4delphi *)
+(* https://github.com/pyscripter/python4delphi *)
+(**************************************************************************)
+(* Functionality: Test unit for MethodCallback *)
+(* *)
+(* *)
+(**************************************************************************)
+(* This source code is distributed with no WARRANTY, for no reason or use.*)
+(* Everyone is allowed to use and change this code free for his own tasks *)
+(* and projects, as long as this header and its copyright text is intact. *)
+(* For changed versions of this code, which are public distributed the *)
+(* following additional conditions have to be fullfilled: *)
+(* 1) The header has to contain a comment on the change and the author of *)
+(* it. *)
+(* 2) A copy of the changed source has to be sent to the above E-Mail *)
+(* address or my then valid address, if this is possible to the *)
+(* author. *)
+(* The second condition has the target to maintain an up to date central *)
+(* version of the component. If this condition is not acceptable for *)
+(* confidential or legal reasons, everyone is free to derive a component *)
+(* or to generate a diff file to my or other original sources. *)
+(**************************************************************************)
+
+unit MethodCallBackTest;
+
+interface
+
+uses
+ DUnitX.TestFramework,
+ MethodCallback,
+ PythonLoad;
+
+implementation
+
+type
+ TTwoArgArmStdFunction = function (arg1, arg2: string): integer;
+ TThreeArgArmStdProcedure = procedure (arg1, arg2, arg3: string);
+
+ TFourArgArmStdFunction = function(arg1, arg2, arg3, arg4: integer): integer;
+ TFiveArgArmStdFunction = function(arg1, arg2, arg3, arg4, arg5: integer): integer;
+
+ TMyFuncCallback = function(arg1, arg2: string): integer of object;
+ TMyProcCallback = procedure (arg1, arg2, arg3: string) of object;
+
+ TTestObj = class
+ public
+ Argument1: string;
+ Argument2: string;
+ Argument3: string;
+ function TwoArgArmStdFunction(arg1, arg2: string): integer;
+ procedure ThreeArgArmStdProcedure(arg1, arg2, arg3: string);
+ function FourArgArmStdFunction(arg1, arg2, arg3, arg4: integer): integer;
+ function FiveArgArmStdFunction(arg1, arg2, arg3, arg4, arg5: integer): integer;
+ end;
+
+ [TestFixture]
+ TMethodCallbackTest = class
+ private
+ fTestObj: TTestObj;
+ public
+ [SetupFixture]
+ procedure SetupFixture;
+ [TearDownFixture]
+ procedure Teardown;
+ [Test]
+ procedure TestDeleteOnEmptyAllocator;
+ [Test]
+ procedure TestCallBackArmStd;
+ [Test]
+ procedure TestOfObjectCallBackArmStd;
+ [Test]
+ procedure TestDeleteCallBack;
+ [Test]
+ procedure TestFourArgArmStdFunction;
+ [Test]
+ procedure TestFiveArgArmStdFunction;
+ [Test]
+ procedure TestMemoryMgmt;
+ end;
+
+{ TTestObj }
+
+function TTestObj.FiveArgArmStdFunction(arg1, arg2, arg3, arg4,
+ arg5: integer): integer;
+begin
+ Result := arg1 * arg4 + arg2 * arg5 + arg3;
+end;
+
+function TTestObj.FourArgArmStdFunction(arg1, arg2, arg3, arg4: integer): integer;
+begin
+ Result := arg1 * arg3 + arg2 * arg4;
+end;
+
+procedure TTestObj.ThreeArgArmStdProcedure(arg1, arg2, arg3: string);
+begin
+ Argument1:=arg1;
+ Argument2:=arg2;
+ Argument3:=arg3;
+end;
+
+function TTestObj.TwoArgArmStdFunction(arg1, arg2: string): integer;
+begin
+ Argument1:=arg1;
+ Argument2:=arg2;
+ result:=1;
+end;
+
+{ TMethodCallbackTest }
+
+procedure TMethodCallbackTest.SetupFixture;
+begin
+ fTestObj:=TTestObj.Create;
+end;
+
+procedure TMethodCallbackTest.Teardown;
+begin
+ fTestObj.Free;
+ FreeCallBacks;
+end;
+
+procedure TMethodCallbackTest.TestMemoryMgmt;
+const
+ AllocCount = {$IFDEF CPUARM}
+ {$IFDEF CPUARM32}
+ 31
+ {$ELSE}
+ 46
+ {$ENDIF CPUARM32}
+ {$ELSE}
+ {$IFDEF CPUX64}
+ {$IFDEF MSWINDOWS}
+ 51
+ {$ELSE}
+ 88
+ {$ENDIF}
+ {$ELSE}
+ 90
+ {$ENDIF}
+ {$ENDIF};
+var
+ i: integer;
+ ptr: Pointer;
+begin
+ //---Test the code-memory manager
+
+ FreeCallBacks;
+ Assert.AreEqual(0, CodeMemPageCount);
+
+ for i:=1 to AllocCount do
+ ptr:=GetCallBack(fTestObj, @TTestObj.ThreeArgArmStdProcedure, 5, ctArmStd);
+
+ // there should still be 1 page allocated
+ Assert.AreEqual(1, CodeMemPageCount);
+
+ // get one callback more and we should have 2 pages
+ ptr:=GetCallBack(fTestObj, @TTestObj.ThreeArgArmStdProcedure, 5, ctArmStd);
+ // getting CodeMemPageCount would crash as the next page pointer was overwritten by the
+ // last allocation
+ Assert.AreEqual(2, CodeMemPageCount);
+end;
+
+procedure TMethodCallbackTest.TestCallBackArmStd;
+var
+ ptr: pointer;
+ func: TTwoArgArmStdFunction;
+begin
+ ptr:=GetCallBack(fTestObj, @TTestObj.TwoArgArmStdFunction, 2, ctArmStd);
+
+ //---call method through pointer
+ func:=TTwoArgArmStdFunction(ptr);
+
+ Assert.AreEqual(1, func('first arg', 'second arg'));
+ Assert.AreEqual(string('first arg'), fTestObj.Argument1);
+ Assert.AreEqual(string('second arg'), fTestObj.Argument2);
+end;
+
+procedure TMethodCallbackTest.TestDeleteCallBack;
+var
+ ptr1, ptr2, ptr3: Pointer;
+ proc: TThreeArgArmStdProcedure;
+ func: TTwoArgArmStdFunction;
+begin
+ //---we create 3 callbacks and delete them.
+ // if there aren't any AV, we assume it works...
+ ptr1:=GetCallBack(fTestObj, @TTestObj.ThreeArgArmStdProcedure, 3, ctArmStd);
+ ptr2:=GetCallBack(fTestObj, @TTestObj.TwoArgArmStdFunction, 2, ctArmStd);
+ DeleteCallBack(ptr1);
+ ptr1:=GetCallBack(fTestObj, @TTestObj.TwoArgArmStdFunction, 2, ctArmStd);
+ ptr3:=GetCallBack(fTestObj, @TTestObj.ThreeArgArmStdProcedure, 3, ctArmStd);
+
+ func:=TTwoArgArmStdFunction(ptr1);
+ func('arg1', 'arg2');
+ func:=TTwoArgArmStdFunction(ptr2);
+ func('arg1', 'arg2');
+ proc:=TThreeArgArmStdProcedure(ptr3);
+ proc('arg1', 'arg2', 'arg3');
+
+ DeleteCallBack(ptr1);
+ DeleteCallBack(ptr2);
+ DeleteCallback(ptr3);
+ Assert.Pass;
+end;
+
+procedure TMethodCallbackTest.TestDeleteOnEmptyAllocator;
+var
+ ptr1 : Pointer;
+begin
+ ptr1 := nil;
+ DeleteCallBack(ptr1);
+ Assert.Pass();
+end;
+
+procedure TMethodCallbackTest.TestFiveArgArmStdFunction;
+Var
+ CallBack : TFiveArgArmStdFunction;
+begin
+ CallBack := GetCallBack(fTestObj, @TTestObj.FiveArgArmStdFunction, 5, ctArmStd);
+ Assert.AreEqual(CallBack(1,2,3,4,5), 1*4+2*5+3);
+ DeleteCallBack(@CallBack);
+end;
+
+procedure TMethodCallbackTest.TestFourArgArmStdFunction;
+Var
+ CallBack : TFourArgArmStdFunction;
+begin
+ CallBack := GetCallBack(fTestObj, @TTestObj.FourArgArmStdFunction, 4, ctArmStd);
+ Assert.AreEqual(CallBack(1,2,3,4), 1*3+2*4);
+ DeleteCallBack(@CallBack);
+end;
+
+procedure TMethodCallbackTest.TestOfObjectCallBackArmStd;
+var
+ ptr: pointer;
+ func: TTwoArgArmStdFunction;
+ cb: TMyFuncCallBack;
+begin
+ cb:=fTestObj.TwoArgArmStdFunction;
+ ptr:=GetOfObjectCallBack(TCallBack(cb), 2, ctARMSTD);
+
+ //---call method through pointer
+ func:=TTwoArgArmStdFunction(ptr);
+
+ Assert.AreEqual(1, func('first arg', 'second arg'));
+ Assert.AreEqual('first arg', fTestObj.Argument1);
+ Assert.AreEqual('second arg', fTestObj.Argument2);
+end;
+
+initialization
+ TDUnitX.RegisterTestFixture(TMethodCallBackTest);
+
+end.
diff --git a/Tests/FMX/Android/NumberServicesTest.pas b/Tests/FMX/Android/NumberServicesTest.pas
new file mode 100644
index 00000000..d9d3ccfc
--- /dev/null
+++ b/Tests/FMX/Android/NumberServicesTest.pas
@@ -0,0 +1,822 @@
+(**************************************************************************)
+(* *)
+(* Module: Unit 'NumberServicesTest' Copyright (c) 2021 *)
+(* *)
+(* Lucas Moura Belo - lmbelo *)
+(* lucas.belo@live.com *)
+(* BH, Brazil *)
+(* *)
+(* PyScripter *)
+(* e-mail: pyscripter@gmail.com *)
+(* *)
+(* Project pages: https://github.com/Embarcadero/python4delphi *)
+(* https://github.com/pyscripter/python4delphi *)
+(**************************************************************************)
+(* Functionality: Test unit for numeric operations *)
+(* *)
+(* *)
+(**************************************************************************)
+(* This source code is distributed with no WARRANTY, for no reason or use.*)
+(* Everyone is allowed to use and change this code free for his own tasks *)
+(* and projects, as long as this header and its copyright text is intact. *)
+(* For changed versions of this code, which are public distributed the *)
+(* following additional conditions have to be fullfilled: *)
+(* 1) The header has to contain a comment on the change and the author of *)
+(* it. *)
+(* 2) A copy of the changed source has to be sent to the above E-Mail *)
+(* address or my then valid address, if this is possible to the *)
+(* author. *)
+(* The second condition has the target to maintain an up to date central *)
+(* version of the component. If this condition is not acceptable for *)
+(* confidential or legal reasons, everyone is free to derive a component *)
+(* or to generate a diff file to my or other original sources. *)
+(**************************************************************************)
+
+unit NumberServicesTest;
+
+interface
+
+uses
+ DUnitX.TestFramework,
+ PythonEngine;
+
+type
+ TRandomInteger = class(TObject)
+ strict private
+ FValue: Integer;
+ private
+ procedure SetValue(const Value: Integer);
+ public
+ constructor Create;
+ property Value: Integer read FValue write SetValue;
+ end;
+
+ PyTRandomInteger = class(TPyObject)
+ private
+ FRandomInteger: TRandomInteger;
+
+ public
+ constructor CreateWith(PythonType: TPythonType; args: PPyObject); override;
+
+ // Basic services
+ function Repr: PPyObject; override;
+
+ // Number services
+ function NbAdd(obj: PPyObject): PPyObject; override; // 0
+ function NbSubtract(obj: PPyObject): PPyObject; override; // 1
+ function NbMultiply(obj: PPyObject): PPyObject; override; // 2
+ function NbRemainder(obj: PPyObject): PPyObject; override; // 4 {3 is for obsolete nsDivide}
+ function NbDivmod(obj: PPyObject): PPyObject; override; // 5
+ function NbPower(ob1, ob2: PPyObject): PPyObject; override; // 6
+ function NbNegative: PPyObject; override; // 7
+ function NbPositive: PPyObject; override; // 8
+ function NbAbsolute: PPyObject; override; // 9
+ function NbInvert: PPyObject; override; // 11 (10 for obsolete nsNonZero)
+ function NbLShift(obj: PPyObject): PPyObject; override; // 12
+ function NbRShift(obj: PPyObject): PPyObject; override; // 13
+ function NbAnd(obj: PPyObject): PPyObject; override; // 14
+ function NbXor(obj: PPyObject): PPyObject; override; // 15
+ function NbOr(obj: PPyObject): PPyObject; override; // 16
+ function NbInt : PPyObject; override; // 18 (17 is for obsolete nsCoerce)
+ function NbFloat : PPyObject; override; // 20 (19 is for obsolete nsLong)
+ function NbFloorDivide(obj: PPyObject): PPyObject; override; // 23 (21 is for obsolete nsOct, 22 for nsHex)
+ function NbTrueDivide(obj: PPyObject): PPyObject; override; // 24
+ function NbMatrixMultiply(obj: PPyObject): PPyObject; override; // 25
+ function NbBool: Integer; override; // 26
+ private
+ function PerformArithmeticOp(obj: PPyObject; op: string): PPyObject;
+ public
+ destructor Destroy; override;
+ end;
+
+ [TestFixture]
+ TTestNumberServices = class(TObject)
+ private
+ PythonType_TRndInt: TPythonType;
+ FPythonModule : TPythonModule;
+ PythonEngine : TPythonEngine;
+ pdvainteger: integer;
+ pdvbinteger: integer;
+ pdvc : TPythonDelphiVar;
+ public
+ [SetupFixture]
+ procedure SetupFixture;
+
+ [TearDownFixture]
+ procedure TearDownFixture;
+
+ [Test]
+ procedure TestAdd; // 0
+ [Test]
+ procedure TestSubtract; // 1
+ [Test]
+ procedure TestMultiply; // 2
+ [Test]
+ procedure TestRemainder; // 4
+ [Test]
+ procedure TestDivMod; // 5
+ [Test]
+ procedure TestPower; // 6
+ [Test]
+ procedure TestNegative; // 7
+ [Test]
+ procedure TestPositive; // 8
+ [Test]
+ procedure TestAbsolute; // 9
+ [Test]
+ procedure TestInvert; // 11
+ [Test]
+ procedure TestLShift; // 12
+ [Test]
+ procedure TestRShift; // 13
+ [Test]
+ procedure TestAnd; // 14
+ [Test]
+ procedure TestXor; // 15
+ [Test]
+ procedure TestOr; // 16
+ [Test]
+ procedure TestInt; // 18
+ [Test]
+ procedure TestFloat; // 20
+ [Test]
+ procedure TestFloorDivide; // 23
+ [Test]
+ procedure TestTrueDivide; // 24
+ [Test]
+ procedure TestMatrixMultiply; // 25
+ [Test]
+ procedure TestBool; // 26
+ end;
+
+var PrintResults: Boolean = False;
+
+implementation
+
+uses
+ System.Variants,
+ System.SysUtils,
+ System.Math,
+ PythonLoad;
+
+procedure AddPythonType(var PythonType: TPythonType;
+ Name: string;
+ TypeName: AnsiString;
+ Engine: TPythonEngine;
+ Module: TPythonModule;
+ PyObjectClass: TPyObjectClass;
+ Basic: TBasicServices;
+ Number: TNumberServices);
+begin
+ if not Assigned(PythonType) then
+ begin
+ PythonType := TPythonType.Create(Module);
+ PythonType.Engine := Engine;
+ PythonType.Module := Module;
+ PythonType.Name := Name;
+ PythonType.Services.Basic := Basic;
+ PythonType.Services.Mapping := [];
+ PythonType.Services.Sequence := [];
+ PythonType.Services.Number := Number;
+ PythonType.TypeName := TypeName;
+ PythonType.PyObjectClass := PyObjectClass;
+ PythonType.GenerateCreateFunction := False;
+
+ PythonType.Initialize;
+ end;
+end;
+
+ function GetVal(AModule : PPyObject; AVarName : AnsiString) : PPyObject;
+ begin
+ with GetPythonEngine do
+ begin
+ Result := PyObject_GetAttrString(AModule, PAnsiChar(AVarName));
+ if PyErr_Occurred <> nil then
+ PyErr_Clear
+ else
+ Py_XDecRef(Result); // keep a borrowed reference.
+ end
+ end;
+
+procedure TTestNumberServices.SetupFixture;
+var
+ Py : PPyObject;
+ valpy: TPyObject;
+ val: PyTRandomInteger;
+begin
+ PythonEngine := TPythonEngine.Create(nil);
+ PythonEngine.Name := 'PythonEngine';
+ TPythonLoad.Configure(PythonEngine);
+ PythonEngine.LoadDll;
+
+ // python module
+ FPythonModule := TPythonModule.Create(GetPythonEngine);
+ FPythonModule.Engine := GetPythonEngine;
+ FPythonModule.ModuleName := 'testing123';
+ FPythonModule.Initialize;
+
+ PythonType_TRndInt := nil;
+ AddPythonType(PythonType_TRndInt, 'PythonType_RndInt', 'TRandomInteger',
+ GetPythonEngine, FPythonModule, PyTRandomInteger,
+ [ bsGetAttrO, bsSetAttrO, bsRepr ],
+ [ nsAdd,
+ nsSubtract,
+ nsMultiply,
+ nsTrueDivide,
+ nsRemainder,
+ nsDivmod,
+ nsPower,
+ nsNegative,
+ nsPositive,
+ nsAbsolute,
+ nsInvert,
+ nsLShift,
+ nsRShift,
+ nsAnd,
+ nsXor,
+ nsOr,
+ nsInt,
+ nsFloat,
+ nsFloorDivide,
+ nsMatrixMultiply,
+ nsBool ]);
+
+ // import our module
+ GetPythonEngine.Run_CommandAsString('import ' + FPythonModule.ModuleName, single_input);
+
+ pdvc := TPythonDelphiVar.Create(nil);
+ pdvc.Engine := GetPythonEngine;
+ pdvc.Module := '__main__';
+ pdvc.VarName := 'c';
+ pdvc.Initialize;
+
+ GetPythonEngine.Run_CommandAsString('aa = testing123.TRandomInteger()', single_input);
+ GetPythonEngine.Run_CommandAsString('bb = testing123.TRandomInteger()', single_input);
+
+ py := GetVal(GetPythonEngine.GetMainModule, 'aa');
+ valpy := PythonToDelphi(py);
+ val := valpy as PyTRandomInteger;
+ if Assigned(Py) then
+ begin
+ pdvainteger := val.FRandomInteger.Value;
+ end;
+
+ py := GetVal(GetPythonEngine.GetMainModule, 'bb');
+ valpy := PythonToDelphi(py);
+ val := valpy as PyTRandomInteger;
+ if Assigned(Py) then
+ begin
+ pdvbinteger := val.FRandomInteger.Value;
+ end;
+end;
+
+{ PyTRandomInteger }
+
+function PythonToTRandomInteger(obj: PPyObject): TRandomInteger;
+begin
+ if obj = GetPythonEngine.Py_None then
+ Result := nil
+ else
+ Result := TRandomInteger(PyTRandomInteger(PythonToDelphi(obj)).FRandomInteger);
+end;
+
+function PyTRandomInteger.Repr: PPyObject;
+var
+ info: string;
+begin
+ with GetPythonEngine do
+ begin
+ info := 'NIL';
+
+ // regular
+ if Assigned(FRandomInteger) then
+ begin
+ info := IntToStr(FRandomInteger.Value);
+ end;
+
+ Result := VariantAsPyObject(info);
+ end;
+end;
+
+
+{ PyTRandomInteger }
+
+constructor PyTRandomInteger.CreateWith(PythonType: TPythonType;
+ args: PPyObject);
+var
+ val1: PPyObject;
+begin
+ with GetPythonEngine do
+ begin
+ try
+ inherited;
+
+ // create object
+ FRandomInteger := TRandomInteger.Create;
+
+ // try to parse the parameter
+ val1 := nil;
+ if Assigned(args) then
+ // try to parse
+ if (PyArg_ParseTuple(args, '|O:CreateWith', @val1) <> 0) and Assigned(val1) then
+ FRandomInteger.Value := PythonToTRandomInteger(val1).Value;
+ except
+ on e: Exception do
+ PyErr_SetString(PyExc_Exception^, PAnsiChar(AnsiString(e.Message)));
+ end;
+ end;
+end;
+
+function PyTRandomInteger.NbAdd(obj: PPyObject): PPyObject; // 0
+begin
+ Result := PerformArithmeticOp(obj, '+');
+end;
+
+function PyTRandomInteger.NbSubtract(obj: PPyObject): PPyObject; // 1
+begin
+ Result := PerformArithmeticOp(obj, '-');
+end;
+
+function PyTRandomInteger.NbMultiply(obj: PPyObject): PPyObject; // 2
+begin
+ Result := PerformArithmeticOp(obj, '*');
+end;
+
+function PyTRandomInteger.NbRemainder(obj: PPyObject): PPyObject; // 4
+begin
+ Result := PerformArithmeticOp(obj, '%');
+end;
+
+function PyTRandomInteger.NbDivmod(obj: PPyObject): PPyObject; // 5
+begin
+ Result := PerformArithmeticOp(obj, 'divmod');
+end;
+
+function PyTRandomInteger.NbPower(ob1, ob2: PPyObject): PPyObject; // 6
+begin
+ Result := PerformArithmeticOp(ob1, '^');
+end;
+
+function PyTRandomInteger.NbNegative: PPyObject; // 7
+var
+ arg1: Integer;
+begin
+ with GetPythonEngine do
+ begin
+ arg1 := FRandomInteger.Value;
+ Result := VariantAsPyObject(-arg1);
+ end
+end;
+
+function PyTRandomInteger.NbPositive: PPyObject; // 8
+var
+ arg1: Integer;
+begin
+ with GetPythonEngine do
+ begin
+ arg1 := FRandomInteger.Value;
+ Result := VariantAsPyObject(+arg1);
+ end
+end;
+
+destructor PyTRandomInteger.Destroy;
+begin
+ FRandomInteger.Free;
+ inherited;
+end;
+
+function PyTRandomInteger.NbAbsolute: PPyObject; // 9
+begin
+ with GetPythonEngine do
+ begin
+ Result := VariantAsPyObject(Abs(FRandomInteger.Value));
+ end;
+end;
+
+function PyTRandomInteger.NbInvert: PPyObject; // 11
+begin
+ with GetPythonEngine do
+ begin
+ Result := VariantAsPyObject(1-(FRandomInteger.Value+1));
+ end;
+end;
+
+function PyTRandomInteger.NbLShift(obj: PPyObject): PPyObject; // 12
+begin
+ Result := PerformArithmeticOp(obj, '<<');
+end;
+
+function PyTRandomInteger.NbRShift(obj: PPyObject): PPyObject; // 13
+begin
+ Result := PerformArithmeticOp(obj, '>>');
+end;
+
+function PyTRandomInteger.NbAnd(obj: PPyObject): PPyObject; // 14
+begin
+ Result := PerformArithmeticOp(obj, 'and');
+end;
+
+function PyTRandomInteger.NbXor(obj: PPyObject): PPyObject; // 15
+begin
+ Result := PerformArithmeticOp(obj, 'xor');
+end;
+
+function PyTRandomInteger.NbOr(obj: PPyObject): PPyObject; // 16
+begin
+ Result := PerformArithmeticOp(obj, 'or');
+end;
+
+function PyTRandomInteger.NbInt: PPyObject; // 18
+begin
+ with GetPythonEngine do
+ begin
+ Result := VariantAsPyObject(FRandomInteger.Value);
+ end;
+end;
+
+function PyTRandomInteger.NbFloat: PPyObject; // 20
+begin
+ with GetPythonEngine do
+ begin
+ Result := VariantAsPyObject(Single(FRandomInteger.Value));
+ end;
+end;
+
+function PyTRandomInteger.nbFloorDivide(obj: PPyObject): PPyObject; // 23
+begin
+ Result := PerformArithmeticOp(obj, 'floordivide');
+end;
+
+function PyTRandomInteger.NbTrueDivide(obj: PPyObject) : PPyObject; // 24
+begin
+ Result := PerformArithmeticOp(obj, '/');
+end;
+
+function PyTRandomInteger.NbMatrixMultiply(obj: PPyObject): PPyObject; // 25
+begin
+ Result := PerformArithmeticOp(obj, '@');
+end;
+
+
+function PyTRandomInteger.NbBool: Integer; // 26
+begin
+ with GetPythonEngine do
+ begin
+ Result := IfThen(FRandomInteger.Value=0, Ord(False), Ord(True));
+ end;
+end;
+
+
+function PyTRandomInteger.PerformArithmeticOp(obj: PPyObject; op: string): PPyObject;
+var
+ val: TPyObject;
+ arg1, arg2: Integer;
+ VarArray: Variant;
+begin
+ with GetPythonEngine do
+ begin
+ Result := ReturnNone;
+ // convert to delphi object
+ val := PythonToDelphi(obj);
+ // we can only add the same type
+ if (val.PythonType = Self.PythonType) then
+ begin
+ arg1 := FRandomInteger.Value;
+ arg2 := PyTRandomInteger(val).FRandomInteger.Value;
+ case op[1] of
+ '+': Result := VariantAsPyObject(arg1 + arg2);
+ '-': Result := VariantAsPyObject(arg1 - arg2);
+ '/': Result := VariantAsPyObject(arg1 div arg2);
+ '*': Result := VariantAsPyObject(arg1 * arg2);
+ '@': Result := VariantAsPyObject(not (arg1 * arg2)); // intentionally different from '*'
+ '%': Result := VariantAsPyObject(arg1 mod arg2);
+ '^': Result := VariantAsPyObject(System.Math.Power(Double(arg1), Double(arg2)));
+ else
+ begin
+ if op='divmod' then
+ begin
+ VarArray := VarArrayCreate([0, 1], varInteger);
+ VarArrayPut(VarArray, arg1 div arg2, [0]);
+ VarArrayPut(VarArray, arg1 mod arg2, [1]);
+ Result := VariantAsPyObject(VarArray);
+ end
+
+ else if op='>>' then
+ begin
+ Result := VariantAsPyObject(arg1 shr arg2);
+ end
+
+ else if op='<<' then
+ begin
+ Result := VariantAsPyObject(arg1 shl arg2);
+ end
+
+ else if op='and' then
+ begin
+ Result := VariantAsPyObject(arg1 and arg2);
+ end
+
+ else if op='xor' then
+ begin
+ Result := VariantAsPyObject(arg1 xor arg2);
+ end
+
+ else if op='or' then
+ begin
+ Result := VariantAsPyObject(arg1 or arg2);
+ end
+
+ else if op='floordivide' then
+ begin
+ Result := VariantAsPyObject(arg1 div arg2);
+ end;
+ end;
+ end;
+ end
+ else // the arguments were not right
+ Result := nil;
+ end;
+end;
+
+{ TRandomInteger }
+
+constructor TRandomInteger.Create;
+begin
+ inherited;
+ FValue := 1+Random(100); // Result interval [1, 101] so safe to test division
+end;
+
+procedure TRandomInteger.SetValue(const Value: Integer);
+begin
+ FValue := Value;
+end;
+
+procedure TTestNumberServices.TearDownFixture;
+begin
+ PythonEngine.Free;
+ pdvc.Free;
+end;
+
+// nsAdd
+procedure TTestNumberServices.TestAdd; // 0
+var
+ pdvinteger: integer;
+begin
+ GetPythonEngine.Run_CommandAsString('c.Value=(aa+bb)', single_input);
+ if PrintResults then GetPythonEngine.Run_CommandAsString('print(c)', single_input);
+
+ pdvinteger := pdvc.Value;
+ Assert.AreEqual(pdvinteger, pdvainteger+pdvbinteger);
+end;
+
+// nsSubtract
+procedure TTestNumberServices.TestSubtract; // 1
+var
+ pdvinteger: integer;
+begin
+ GetPythonEngine.Run_CommandAsString('c.Value=(aa-bb)', single_input);
+ if PrintResults then GetPythonEngine.Run_CommandAsString('print(c)', single_input);
+
+ pdvinteger := pdvc.Value;
+ Assert.AreEqual(pdvinteger, pdvainteger-pdvbinteger);
+end;
+
+// nsMultiply
+procedure TTestNumberServices.TestMultiply; // 2
+var
+ pdvinteger: integer;
+begin
+ GetPythonEngine.Run_CommandAsString('c.Value=(aa*bb)', single_input);
+ if PrintResults then GetPythonEngine.Run_CommandAsString('print(c)', single_input);
+
+ pdvinteger := pdvc.Value;
+ Assert.AreEqual(pdvinteger, pdvainteger*pdvbinteger);
+end;
+
+// nsRemainder
+procedure TTestNumberServices.TestRemainder; // 4
+var
+ pdvinteger: integer;
+begin
+ GetPythonEngine.Run_CommandAsString('c.Value=(aa%bb)', single_input);
+ if PrintResults then GetPythonEngine.Run_CommandAsString('print(c)', single_input);
+
+ pdvinteger := pdvc.Value;
+ Assert.AreEqual(pdvinteger, pdvainteger mod pdvbinteger);
+end;
+
+// nsDivmod
+procedure TTestNumberServices.TestDivMod; // 5
+var
+ VarArr: Variant;
+ res0, res1: Integer;
+begin
+ GetPythonEngine.Run_CommandAsString('c.Value=divmod(aa,bb)', single_input);
+ if PrintResults then GetPythonEngine.Run_CommandAsString('print(c)', single_input);
+
+ VarArr := pdvc.Value;
+ res0 := VarArr[0];
+ res1 := VarArr[1];
+
+ Assert.AreEqual(res0, pdvainteger div pdvbinteger);
+ Assert.AreEqual(res1, pdvainteger mod pdvbinteger);
+end;
+
+// nsPower
+procedure TTestNumberServices.TestPower; // 6
+var
+ pdvdouble: double;
+begin
+ GetPythonEngine.Run_CommandAsString('c.Value=float(aa**bb)', single_input);
+ if PrintResults then GetPythonEngine.Run_CommandAsString('print(c)', single_input);
+
+ pdvdouble := pdvc.Value;
+ Assert.AreEqual(Double(pdvdouble), {Round}(System.Math.Power(Double(pdvainteger), Double(pdvbinteger))));
+
+end;
+
+// nsNegative
+procedure TTestNumberServices.TestNegative; // 7
+var
+ pdvinteger: integer;
+begin
+ GetPythonEngine.Run_CommandAsString('c.Value=(-aa)', single_input);
+ if PrintResults then GetPythonEngine.Run_CommandAsString('print(c)', single_input);
+
+ pdvinteger := pdvc.Value;
+ Assert.AreEqual(pdvinteger, -pdvainteger);
+end;
+
+// nsPositive
+procedure TTestNumberServices.TestPositive; // 8
+var
+ pdvinteger: integer;
+begin
+ GetPythonEngine.Run_CommandAsString('c.Value=int(+aa)', single_input);
+ if PrintResults then GetPythonEngine.Run_CommandAsString('print(c)', single_input);
+
+ pdvinteger := pdvc.Value;
+ Assert.AreEqual(pdvinteger, +pdvainteger);
+end;
+
+// nsAbsolute
+procedure TTestNumberServices.TestAbsolute; // 9
+var
+ pdvinteger: integer;
+begin
+ GetPythonEngine.Run_CommandAsString('c.Value=abs(-aa)', single_input);
+ if PrintResults then GetPythonEngine.Run_CommandAsString('print(c)', single_input);
+
+ pdvinteger := pdvc.Value;
+ Assert.AreEqual(pdvinteger, +pdvainteger);
+end;
+
+// nsInvert
+procedure TTestNumberServices.TestInvert; // 11
+var
+ pdvinteger: Integer;
+begin
+ GetPythonEngine.Run_CommandAsString('c.Value=~aa', single_input);
+ if PrintResults then GetPythonEngine.Run_CommandAsString('print(c)', single_input);
+
+ pdvinteger := pdvc.Value;
+ Assert.AreEqual(pdvinteger, 1-(pdvainteger+1));
+end;
+
+// nsLShift
+procedure TTestNumberServices.TestLShift; // 12
+var
+ pdvinteger: integer;
+begin
+ GetPythonEngine.Run_CommandAsString('c.Value=(aa<>bb)', single_input);
+ if PrintResults then GetPythonEngine.Run_CommandAsString('print(c)', single_input);
+
+ pdvinteger := pdvc.Value;
+ Assert.AreEqual(pdvinteger, pdvainteger shr pdvbinteger);
+end;
+
+// nsAnd
+procedure TTestNumberServices.TestAnd; // 14
+var
+ pdvinteger: integer;
+begin
+ GetPythonEngine.Run_CommandAsString('c.Value=(aa&bb)', single_input);
+ if PrintResults then GetPythonEngine.Run_CommandAsString('print(c)', single_input);
+
+ pdvinteger := pdvc.Value;
+ Assert.AreEqual(pdvinteger, pdvainteger and pdvbinteger);
+end;
+
+// nsXor
+procedure TTestNumberServices.TestXor; // 15
+var
+ pdvinteger: integer;
+begin
+ GetPythonEngine.Run_CommandAsString('c.Value=(aa^bb)', single_input);
+ if PrintResults then GetPythonEngine.Run_CommandAsString('print(c)', single_input);
+
+ pdvinteger := pdvc.Value;
+ Assert.AreEqual(pdvinteger, pdvainteger xor pdvbinteger);
+end;
+
+// nsOr
+procedure TTestNumberServices.TestOr; // 16
+var
+ pdvinteger: integer;
+begin
+ GetPythonEngine.Run_CommandAsString('c.Value=(aa|bb)', single_input);
+ if PrintResults then GetPythonEngine.Run_CommandAsString('print(c)', single_input);
+
+ pdvinteger := pdvc.Value;
+ Assert.AreEqual(pdvinteger, pdvainteger or pdvbinteger);
+end;
+
+// nsInt
+procedure TTestNumberServices.TestInt; // 18
+var
+ pdvinteger: Integer;
+begin
+ GetPythonEngine.Run_CommandAsString('c.Value=int(aa)', single_input);
+ if PrintResults then GetPythonEngine.Run_CommandAsString('print(c)', single_input);
+
+ pdvinteger := pdvc.Value;
+ Assert.AreEqual(pdvinteger, pdvainteger);
+end;
+
+// nsFloat
+procedure TTestNumberServices.TestFloat; // 20
+var
+ pdvsingle: Single;
+begin
+ GetPythonEngine.Run_CommandAsString('c.Value=float(aa)', single_input);
+ if PrintResults then GetPythonEngine.Run_CommandAsString('print(c)', single_input);
+
+ pdvsingle := pdvc.Value;
+ Assert.AreEqual(pdvsingle, single(pdvainteger));
+end;
+
+// nsFloorDivide
+procedure TTestNumberServices.TestFloorDivide; // 23
+var
+ pdvinteger: integer;
+begin
+ GetPythonEngine.Run_CommandAsString('c.Value=(aa//bb)', single_input);
+ if PrintResults then GetPythonEngine.Run_CommandAsString('print(c)', single_input);
+
+ pdvinteger := pdvc.Value;
+ Assert.AreEqual(pdvinteger, pdvainteger div pdvbinteger);
+end;
+
+// nsTrueDivide
+procedure TTestNumberServices.TestTrueDivide; // 24
+var
+ pdvinteger: integer;
+begin
+ GetPythonEngine.Run_CommandAsString('c.Value=(aa/bb)', single_input);
+ if PrintResults then GetPythonEngine.Run_CommandAsString('print(c)', single_input);
+
+ pdvinteger := pdvc.Value;
+ Assert.AreEqual(pdvinteger, pdvainteger div pdvbinteger);
+end;
+
+// nsMatrixMultiply
+procedure TTestNumberServices.TestMatrixMultiply; // 25
+var
+ pdvinteger: integer;
+begin
+ GetPythonEngine.Run_CommandAsString('c.Value=(aa @ bb)', single_input);
+ if PrintResults then GetPythonEngine.Run_CommandAsString('print(c)', single_input);
+
+ pdvinteger := pdvc.Value;
+ Assert.AreEqual(pdvinteger, not (pdvainteger * pdvbinteger)); // not really a matrix mult, but who cares!
+end;
+
+// nsBool
+procedure TTestNumberServices.TestBool; // 26
+var
+ pdvinteger: Integer;
+begin
+ GetPythonEngine.Run_CommandAsString('c.Value= bool(aa)', single_input);
+ if PrintResults then GetPythonEngine.Run_CommandAsString('print(c)', single_input);
+
+ pdvinteger := pdvc.Value;
+ Assert.AreEqual(pdvinteger=0, pdvainteger=0)
+end;
+
+initialization
+ TDUnitX.RegisterTestFixture(TTestNumberServices);
+ ReportMemoryLeaksOnShutdown := True;
+
+end.
diff --git a/Tests/FMX/Android/P4DAndroidTest.dpr b/Tests/FMX/Android/P4DAndroidTest.dpr
new file mode 100644
index 00000000..c711bef2
--- /dev/null
+++ b/Tests/FMX/Android/P4DAndroidTest.dpr
@@ -0,0 +1,18 @@
+program P4DAndroidTest;
+uses
+ System.StartUpCopy,
+ FMX.Forms,
+ DUNitX.Loggers.MobileGUI,
+ MethodCallBackTest in 'MethodCallBackTest.pas',
+ NumberServicesTest in 'NumberServicesTest.pas',
+ PyEnvTest in 'PyEnvTest.pas',
+ PythonLoad in 'PythonLoad.pas',
+ VarPythTest in 'VarPythTest.pas',
+ WrapDelphiTest in 'WrapDelphiTest.pas';
+
+{$R *.res}
+begin
+ Application.Initialize;
+ Application.CreateForm(TMobileGUITestRunner, MobileGUITestRunner);
+ Application.Run;
+end.
diff --git a/Tests/FMX/Android/P4DAndroidTest.dproj b/Tests/FMX/Android/P4DAndroidTest.dproj
new file mode 100644
index 00000000..c82d4739
--- /dev/null
+++ b/Tests/FMX/Android/P4DAndroidTest.dproj
@@ -0,0 +1,1800 @@
+
+
+ {652D9A8E-1625-4F00-9B29-2E3D31D7A186}
+ 19.2
+ FMX
+ True
+ Debug
+ Android
+ 37915
+ Application
+ P4DAndroidTest.dpr
+
+
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Cfg_1
+ true
+ true
+
+
+ true
+ Cfg_1
+ true
+ true
+
+
+ true
+ Cfg_1
+ true
+ true
+
+
+ true
+ Cfg_1
+ true
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Cfg_2
+ true
+ true
+
+
+ true
+ Cfg_2
+ true
+ true
+
+
+ true
+ Cfg_2
+ true
+ true
+
+
+ true
+ Cfg_2
+ true
+ true
+
+
+ .\$(Platform)\$(Config)
+ .\$(Platform)\$(Config)
+ false
+ false
+ false
+ false
+ false
+ System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ true
+ $(BDS)\bin\delphi_PROJECTICON.ico
+ $(BDS)\bin\delphi_PROJECTICNS.icns
+ P4DAndroidTest
+
+
+ DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;bindcompfmx;fmx;FireDACIBDriver;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
+ package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=
+ Debug
+ true
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png
+ android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar
+
+
+ DBXSqliteDriver;RESTComponents;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;bindcompfmx;fmx;FireDACIBDriver;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
+ package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=
+ Debug
+ true
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png
+ $(BDS)\bin\Artwork\Android\FM_LauncherIcon_192x192.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png
+ $(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_24x24.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_36x36.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_48x48.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_72x72.png
+ $(BDS)\bin\Artwork\Android\FM_NotificationIcon_96x96.png
+ android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar
+
+
+ DBXSqliteDriver;RESTComponents;fmxase;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;bindcompfmx;fmx;FireDACIBDriver;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
+ CFBundleName=$(MSBuildProjectName);CFBundleDevelopmentRegion=en;CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleInfoDictionaryVersion=7.1;CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;LSRequiresIPhoneOS=true;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);UIDeviceFamily=iPhone & iPad;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user;NSLocationAlwaysAndWhenInUseUsageDescription=The reason for accessing the location information of the user;UIBackgroundModes=;NSContactsUsageDescription=The reason for accessing the contacts;NSPhotoLibraryUsageDescription=The reason for accessing the photo library;NSPhotoLibraryAddUsageDescription=The reason for adding to the photo library;NSCameraUsageDescription=The reason for accessing the camera;NSFaceIDUsageDescription=The reason for accessing the face id;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSSiriUsageDescription=The reason for accessing Siri;ITSAppUsesNonExemptEncryption=false;NSBluetoothAlwaysUsageDescription=The reason for accessing bluetooth;NSBluetoothPeripheralUsageDescription=The reason for accessing bluetooth peripherals;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSMotionUsageDescription=The reason for accessing the accelerometer;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers
+ iPhoneAndiPad
+ true
+ Debug
+ $(MSBuildProjectName)
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_1024x1024.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_180x180.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_2x.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImageDark_2x.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_3x.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImageDark_3x.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_120x120.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_SettingIcon_58x58.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_SettingIcon_87x87.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_NotificationIcon_40x40.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_NotificationIcon_60x60.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_167x167.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImage_2x.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageDark_2x.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_SettingIcon_58x58.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_NotificationIcon_40x40.png
+
+
+ DBXSqliteDriver;RESTComponents;fmxase;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;bindcompfmx;fmx;FireDACIBDriver;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;CloudService;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;soaprtl;DbxCommonDriver;xmlrtl;soapmidas;DataSnapNativeClient;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;bindcomp;IndyIPClient;dbxcds;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;$(DCC_UsePackage)
+ CFBundleName=$(MSBuildProjectName);CFBundleDevelopmentRegion=en;CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleInfoDictionaryVersion=7.1;CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;LSRequiresIPhoneOS=true;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);UIDeviceFamily=iPhone & iPad;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user;NSLocationAlwaysAndWhenInUseUsageDescription=The reason for accessing the location information of the user;UIBackgroundModes=;NSContactsUsageDescription=The reason for accessing the contacts;NSPhotoLibraryUsageDescription=The reason for accessing the photo library;NSPhotoLibraryAddUsageDescription=The reason for adding to the photo library;NSCameraUsageDescription=The reason for accessing the camera;NSFaceIDUsageDescription=The reason for accessing the face id;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSSiriUsageDescription=The reason for accessing Siri;ITSAppUsesNonExemptEncryption=false;NSBluetoothAlwaysUsageDescription=The reason for accessing bluetooth;NSBluetoothPeripheralUsageDescription=The reason for accessing bluetooth peripherals;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSMotionUsageDescription=The reason for accessing the accelerometer;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers
+ iPhoneAndiPad
+ true
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_1024x1024.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_180x180.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_2x.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImageDark_2x.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImage_3x.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_LaunchImageDark_3x.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_120x120.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_SettingIcon_58x58.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_SettingIcon_87x87.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_NotificationIcon_40x40.png
+ $(BDS)\bin\Artwork\iOS\iPhone\FM_NotificationIcon_60x60.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_167x167.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImage_2x.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageDark_2x.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_SettingIcon_58x58.png
+ $(BDS)\bin\Artwork\iOS\iPad\FM_NotificationIcon_40x40.png
+ 10.0
+
+
+ DBXSqliteDriver;RESTComponents;fmxase;DBXInterBaseDriver;emsclientfiredac;tethering;DataSnapFireDAC;FireDACMSSQLDriver;bindcompfmx;DBXOracleDriver;inetdb;fmx;FireDACIBDriver;fmxdae;FireDACDBXDriver;dbexpress;IndyCore;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;soapserver;bindengine;DBXMySQLDriver;CloudService;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;IndyIPServer;IndySystem;fmxFireDAC;FireDAC;FireDACSqliteDriver;FireDACPgDriver;FireDACASADriver;FireDACTDataDriver;soaprtl;DbxCommonDriver;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;FireDACDSDriver;rtl;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;bindcomp;DBXInformixDriver;IndyIPClient;dbxcds;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage)
+ CFBundleName=$(MSBuildProjectName);CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleVersion=1.0.0;CFBundleShortVersionString=1.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);NSHighResolutionCapable=true;LSApplicationCategoryType=public.app-category.utilities;NSLocationUsageDescription=The reason for accessing the location information of the user;NSContactsUsageDescription=The reason for accessing the contacts;NSCalendarsUsageDescription=The reason for accessing the calendar data;NSRemindersUsageDescription=The reason for accessing the reminders;NSCameraUsageDescription=The reason for accessing the camera;NSMicrophoneUsageDescription=The reason for accessing the microphone;NSMotionUsageDescription=The reason for accessing the accelerometer;NSDesktopFolderUsageDescription=The reason for accessing the Desktop folder;NSDocumentsFolderUsageDescription=The reason for accessing the Documents folder;NSDownloadsFolderUsageDescription=The reason for accessing the Downloads folder;NSNetworkVolumesUsageDescription=The reason for accessing files on a network volume;NSRemovableVolumesUsageDescription=The reason for accessing files on a removable volume;NSSpeechRecognitionUsageDescription=The reason for requesting to send user data to Apple's speech recognition servers
+ Debug
+ true
+
+
+ DBXSqliteDriver;RESTComponents;fmxase;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;bindcompvclsmp;emsclientfiredac;tethering;svnui;DataSnapFireDAC;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;svn;DBXOracleDriver;inetdb;emsedge;fmx;FireDACIBDriver;fmxdae;vcledge;FireDACDBXDriver;dbexpress;IndyCore;vclx;Python;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;vcl;IndyIPServer;DBXSybaseASEDriver;IndySystem;FireDACDb2Driver;bindcompvclwinx;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;soaprtl;DbxCommonDriver;PythonVcl;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;FireDACDSDriver;rtl;emsserverresource;DbxClientDriver;PythonFmx;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage)
+ Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
+ Debug
+ true
+ CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
+ 1033
+ $(BDS)\bin\default_app.manifest
+ $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
+ $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
+
+
+ DBXSqliteDriver;RESTComponents;fmxase;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;bindcompvclsmp;emsclientfiredac;tethering;DataSnapFireDAC;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;DBXOracleDriver;inetdb;emsedge;fmx;FireDACIBDriver;fmxdae;vcledge;FireDACDBXDriver;dbexpress;IndyCore;vclx;Python;dsnap;emsclient;DataSnapCommon;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACOracleDriver;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;DataSnapClient;inet;IndyIPCommon;bindcompdbx;vcl;IndyIPServer;DBXSybaseASEDriver;IndySystem;FireDACDb2Driver;bindcompvclwinx;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;soaprtl;DbxCommonDriver;PythonVcl;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;FireDACDSDriver;rtl;emsserverresource;DbxClientDriver;PythonFmx;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;DataSnapServerMidas;$(DCC_UsePackage)
+ Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)
+ Debug
+ true
+ CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=
+ 1033
+ $(BDS)\bin\default_app.manifest
+ $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png
+ $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png
+
+
+ DEBUG;$(DCC_Define)
+ true
+ false
+ true
+ true
+ true
+
+
+ 1
+ C:\Users\User\Documents\Embarcadero\Studio\Projects\Embarcadero\python4delphi\Source\;$(Debugger_DebugSourcePath)
+ #000000
+
+
+ 1
+ #000000
+
+
+ false
+ true
+ PerMonitorV2
+
+
+ true
+ PerMonitorV2
+
+
+ false
+ RELEASE;$(DCC_Define)
+ 0
+ 0
+
+
+ 1
+ #000000
+
+
+ 1
+ #000000
+
+
+ true
+ PerMonitorV2
+
+
+ true
+ PerMonitorV2
+
+
+
+ MainSource
+
+
+
+
+
+
+
+ Cfg_2
+ Base
+
+
+ Base
+
+
+ Cfg_1
+ Base
+
+
+
+ Delphi.Personality.12
+ Application
+
+
+
+ P4DAndroidTest.dpr
+
+
+ Microsoft Office 2000 Sample Automation Server Wrapper Components
+ Microsoft Office XP Sample Automation Server Wrapper Components
+
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ library\lib\arm64-v8a\
+ libpython3.9d.so
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ library\lib\armeabi-v7a\
+ libpython3.9d.so
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ classes.dex
+ true
+
+
+
+
+ styles.xml
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ true
+
+
+
+
+ library\lib\armeabi-v7a\
+ libpython3.9.so
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ libP4DAndroidTest.so
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ .\assets\internal
+ build.zip
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ .\assets\internal
+ build.zip
+ false
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ classes.dex
+ true
+
+
+
+
+ classes.dex
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ styles.xml
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ styles.xml
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ libP4DAndroidTest.so
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ libP4DAndroidTest.so
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ .\assets\internal
+ build.zip
+ false
+
+
+
+
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ P4DAndroidTest.exe
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ classes.dex
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ .\assets\internal
+ build.zip
+ true
+
+
+
+
+ library\lib\arm64-v8a\
+ libpython3.9.so
+ true
+
+
+
+
+ true
+
+
+
+
+ true
+
+
+
+
+ true
+
+
+
+
+ true
+
+
+
+
+ ic_notification.png
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ true
+
+
+
+
+ splash_image.png
+ true
+
+
+
+
+ true
+
+
+
+
+ libP4DAndroidTest.so
+ true
+
+
+
+
+ libPyLoad.so
+ true
+
+
+
+
+ ic_launcher.png
+ true
+
+
+
+
+ styles.xml
+ true
+
+
+
+
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ 0
+
+
+
+
+ classes
+ 1
+
+
+ classes
+ 1
+
+
+
+
+ res\xml
+ 1
+
+
+ res\xml
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+
+
+ library\lib\armeabi
+ 1
+
+
+ library\lib\armeabi
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+
+
+ library\lib\mips
+ 1
+
+
+ library\lib\mips
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+ library\lib\arm64-v8a
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+
+
+ res\drawable
+ 1
+
+
+ res\drawable
+ 1
+
+
+
+
+ res\values
+ 1
+
+
+ res\values
+ 1
+
+
+
+
+ res\values-v21
+ 1
+
+
+ res\values-v21
+ 1
+
+
+
+
+ res\values
+ 1
+
+
+ res\values
+ 1
+
+
+
+
+ res\drawable
+ 1
+
+
+ res\drawable
+ 1
+
+
+
+
+ res\drawable-xxhdpi
+ 1
+
+
+ res\drawable-xxhdpi
+ 1
+
+
+
+
+ res\drawable-xxxhdpi
+ 1
+
+
+ res\drawable-xxxhdpi
+ 1
+
+
+
+
+ res\drawable-ldpi
+ 1
+
+
+ res\drawable-ldpi
+ 1
+
+
+
+
+ res\drawable-mdpi
+ 1
+
+
+ res\drawable-mdpi
+ 1
+
+
+
+
+ res\drawable-hdpi
+ 1
+
+
+ res\drawable-hdpi
+ 1
+
+
+
+
+ res\drawable-xhdpi
+ 1
+
+
+ res\drawable-xhdpi
+ 1
+
+
+
+
+ res\drawable-mdpi
+ 1
+
+
+ res\drawable-mdpi
+ 1
+
+
+
+
+ res\drawable-hdpi
+ 1
+
+
+ res\drawable-hdpi
+ 1
+
+
+
+
+ res\drawable-xhdpi
+ 1
+
+
+ res\drawable-xhdpi
+ 1
+
+
+
+
+ res\drawable-xxhdpi
+ 1
+
+
+ res\drawable-xxhdpi
+ 1
+
+
+
+
+ res\drawable-xxxhdpi
+ 1
+
+
+ res\drawable-xxxhdpi
+ 1
+
+
+
+
+ res\drawable-small
+ 1
+
+
+ res\drawable-small
+ 1
+
+
+
+
+ res\drawable-normal
+ 1
+
+
+ res\drawable-normal
+ 1
+
+
+
+
+ res\drawable-large
+ 1
+
+
+ res\drawable-large
+ 1
+
+
+
+
+ res\drawable-xlarge
+ 1
+
+
+ res\drawable-xlarge
+ 1
+
+
+
+
+ res\values
+ 1
+
+
+ res\values
+ 1
+
+
+
+
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ 0
+
+
+
+
+ Contents\MacOS
+ 1
+ .framework
+
+
+ Contents\MacOS
+ 1
+ .framework
+
+
+ 0
+
+
+
+
+ 1
+ .dylib
+
+
+ 1
+ .dylib
+
+
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ 0
+ .dll;.bpl
+
+
+
+
+ 1
+ .dylib
+
+
+ 1
+ .dylib
+
+
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ Contents\MacOS
+ 1
+ .dylib
+
+
+ 0
+ .bpl
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ Contents\Resources\StartUp\
+ 0
+
+
+ Contents\Resources\StartUp\
+ 0
+
+
+ 0
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+ ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
+ 1
+
+
+ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
+ 1
+
+
+
+
+ ..\
+ 1
+
+
+ ..\
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).launchscreen
+ 64
+
+
+ ..\$(PROJECTNAME).launchscreen
+ 64
+
+
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF
+ 1
+
+
+
+
+ ..\
+ 1
+
+
+ ..\
+ 1
+
+
+
+
+ Contents
+ 1
+
+
+ Contents
+ 1
+
+
+
+
+ Contents\Resources
+ 1
+
+
+ Contents\Resources
+ 1
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+ library\lib\arm64-v8a
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ Contents\MacOS
+ 1
+
+
+ 0
+
+
+
+
+ library\lib\armeabi-v7a
+ 1
+
+
+
+
+ 1
+
+
+ 1
+
+
+
+
+ Assets
+ 1
+
+
+ Assets
+ 1
+
+
+
+
+ Assets
+ 1
+
+
+ Assets
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ True
+ True
+ True
+ True
+ True
+
+
+ 12
+
+
+
+
+
diff --git a/Tests/FMX/Android/PyEnvTest.pas b/Tests/FMX/Android/PyEnvTest.pas
new file mode 100644
index 00000000..d76098b2
--- /dev/null
+++ b/Tests/FMX/Android/PyEnvTest.pas
@@ -0,0 +1,106 @@
+(**************************************************************************)
+(* *)
+(* Module: Unit 'PyEnvTest' Copyright (c) 2021 *)
+(* *)
+(* Lucas Moura Belo - lmbelo *)
+(* lucas.belo@live.com *)
+(* BH, Brazil *)
+(* *)
+(* PyScripter *)
+(* e-mail: pyscripter@gmail.com *)
+(* *)
+(* Project pages: https://github.com/Embarcadero/python4delphi *)
+(* https://github.com/pyscripter/python4delphi *)
+(**************************************************************************)
+(* Functionality: Test unit for Python's environment *)
+(* *)
+(* *)
+(**************************************************************************)
+(* This source code is distributed with no WARRANTY, for no reason or use.*)
+(* Everyone is allowed to use and change this code free for his own tasks *)
+(* and projects, as long as this header and its copyright text is intact. *)
+(* For changed versions of this code, which are public distributed the *)
+(* following additional conditions have to be fullfilled: *)
+(* 1) The header has to contain a comment on the change and the author of *)
+(* it. *)
+(* 2) A copy of the changed source has to be sent to the above E-Mail *)
+(* address or my then valid address, if this is possible to the *)
+(* author. *)
+(* The second condition has the target to maintain an up to date central *)
+(* version of the component. If this condition is not acceptable for *)
+(* confidential or legal reasons, everyone is free to derive a component *)
+(* or to generate a diff file to my or other original sources. *)
+(**************************************************************************)
+
+unit PyEnvTest;
+
+interface
+
+uses
+ DUnitX.TestFramework, PythonEngine;
+
+type
+ [TestFixture]
+ TPyEnvTest = class
+ private
+ FPythonEngine: TPythonEngine;
+ public
+ [SetupFixture]
+ procedure SetupFixture;
+ [TearDownFixture]
+ procedure TearDownFixture;
+ [Test]
+ procedure TestLibFile();
+ [Test]
+ procedure TestZipFile();
+ [Test]
+ procedure TestExtraction();
+ [Test]
+ procedure TestConfigure();
+ end;
+
+implementation
+
+uses
+ PythonLoad;
+
+{ TPyEnvTest }
+
+procedure TPyEnvTest.SetupFixture;
+begin
+ FPythonEngine := TPythonEngine.Create(nil);
+ FPythonEngine.Name := 'PythonEngine';
+end;
+
+procedure TPyEnvTest.TearDownFixture;
+begin
+ FPythonEngine.Free();
+end;
+
+procedure TPyEnvTest.TestConfigure;
+begin
+ TPythonLoad.Configure(FPythonEngine);
+ FPythonEngine.LoadDll;
+ Assert.IsTrue(FPythonEngine.IsHandleValid());
+end;
+
+procedure TPyEnvTest.TestExtraction;
+begin
+ TPythonLoad.Extract();
+ Assert.IsTrue(TPythonLoad.HasPythonDist());
+end;
+
+procedure TPyEnvTest.TestLibFile;
+begin
+ Assert.IsTrue(TPythonLoad.HasPythonLib());
+end;
+
+procedure TPyEnvTest.TestZipFile;
+begin
+ Assert.IsTrue(TPythonLoad.HasPythonZip());
+end;
+
+initialization
+ TDUnitX.RegisterTestFixture(TPyEnvTest);
+
+end.
diff --git a/Tests/FMX/Android/PythonLoad.pas b/Tests/FMX/Android/PythonLoad.pas
new file mode 100644
index 00000000..30562a00
--- /dev/null
+++ b/Tests/FMX/Android/PythonLoad.pas
@@ -0,0 +1,135 @@
+(**************************************************************************)
+(* *)
+(* Module: Unit 'PythonLoad' Copyright (c) 2021 *)
+(* *)
+(* Lucas Moura Belo - lmbelo *)
+(* lucas.belo@live.com *)
+(* BH, Brazil *)
+(* *)
+(* PyScripter *)
+(* e-mail: pyscripter@gmail.com *)
+(* *)
+(* Project pages: https://github.com/Embarcadero/python4delphi *)
+(* https://github.com/pyscripter/python4delphi *)
+(**************************************************************************)
+(* Functionality: Load python distribution *)
+(* *)
+(* *)
+(**************************************************************************)
+(* This source code is distributed with no WARRANTY, for no reason or use.*)
+(* Everyone is allowed to use and change this code free for his own tasks *)
+(* and projects, as long as this header and its copyright text is intact. *)
+(* For changed versions of this code, which are public distributed the *)
+(* following additional conditions have to be fullfilled: *)
+(* 1) The header has to contain a comment on the change and the author of *)
+(* it. *)
+(* 2) A copy of the changed source has to be sent to the above E-Mail *)
+(* address or my then valid address, if this is possible to the *)
+(* author. *)
+(* The second condition has the target to maintain an up to date central *)
+(* version of the component. If this condition is not acceptable for *)
+(* confidential or legal reasons, everyone is free to derive a component *)
+(* or to generate a diff file to my or other original sources. *)
+(**************************************************************************)
+
+unit PythonLoad;
+
+interface
+
+uses
+ System.SysUtils, System.Zip, PythonEngine;
+
+type
+ TExtractEvent = reference to procedure(const AFolderExists: boolean; var AReplaceFiles: boolean);
+ TPythonLoad = class
+ public
+ class function GetPyZip(): string; static;
+ class function GetPyRoot(): string; static;
+ class function GetPyHome(): string; static;
+ class function GetPyBin(): string; static;
+ class function GetPyLib(): string; static;
+
+ class function HasPythonLib(): boolean; static;
+ class function HasPythonZip(): boolean; static;
+ class function HasPythonDist(): boolean; static;
+ class procedure Extract(); static;
+ class procedure Configure(const APythonEngine: TPythonEngine); static;
+ end;
+
+implementation
+
+uses
+ System.IOUtils;
+
+const
+ PY_KNOWN_VER = 1;
+
+{ TPythonLoad }
+
+class procedure TPythonLoad.Extract();
+begin
+ var LPyRoot := TPythonLoad.GetPyRoot();
+ var LPyZip := TPythonLoad.GetPyZip();
+
+ if not TDirectory.Exists(LPyRoot) then
+ TZipFile.ExtractZipFile(LPyZip, LPyRoot, nil);
+end;
+
+class function TPythonLoad.GetPyBin: string;
+begin
+ Result := TPath.Combine(GetPyHome(), 'bin');
+end;
+
+class function TPythonLoad.GetPyHome: string;
+begin
+ Result := TPath.Combine(GetPyRoot(), 'usr');
+end;
+
+class function TPythonLoad.GetPyLib: string;
+begin
+ Result := TPath.Combine(GetPyHome(), 'lib');
+end;
+
+class function TPythonLoad.GetPyRoot: string;
+begin
+ Result := TPath.Combine(TPath.GetDocumentsPath(), 'build');
+end;
+
+class function TPythonLoad.GetPyZip: string;
+begin
+ Result := TPath.Combine(TPath.GetDocumentsPath(), 'build.zip');
+end;
+
+class function TPythonLoad.HasPythonDist: boolean;
+begin
+ Result := TDirectory.Exists(TPythonLoad.GetPyRoot());
+end;
+
+class function TPythonLoad.HasPythonLib: boolean;
+begin
+ Result := TFile.Exists(TPath.Combine(TPath.GetLibraryPath(),
+ PYTHON_KNOWN_VERSIONS[PY_KNOWN_VER].DllName));
+end;
+
+class function TPythonLoad.HasPythonZip: boolean;
+begin
+ Result := TFile.Exists(TPythonLoad.GetPyZip());
+end;
+
+class procedure TPythonLoad.Configure(const APythonEngine: TPythonEngine);
+begin
+ APythonEngine.AutoLoad := False;
+ APythonEngine.UseLastKnownVersion := false;
+ APythonEngine.ProgramName := TPythonLoad.GetPyBin();
+ APythonEngine.PythonHome := TPythonLoad.GetPyHome();
+ APythonEngine.RegVersion := PYTHON_KNOWN_VERSIONS[PY_KNOWN_VER].RegVersion;
+ APythonEngine.DllName := PYTHON_KNOWN_VERSIONS[PY_KNOWN_VER].DllName;
+ APythonEngine.APIVersion := PYTHON_KNOWN_VERSIONS[PY_KNOWN_VER].APIVersion;
+ APythonEngine.FatalAbort := False;
+ APythonEngine.FatalMsgDlg := False;
+ APythonEngine.AutoFinalize := True;
+ APythonEngine.InitThreads := True;
+ APythonEngine.PyFlags := [pfInteractive];
+end;
+
+end.
diff --git a/Tests/FMX/Android/VarPythTest.pas b/Tests/FMX/Android/VarPythTest.pas
new file mode 100644
index 00000000..ca1e0043
--- /dev/null
+++ b/Tests/FMX/Android/VarPythTest.pas
@@ -0,0 +1,1084 @@
+(**************************************************************************)
+(* *)
+(* Module: Unit 'VarPythTest' Copyright (c) 2021 *)
+(* *)
+(* Lucas Moura Belo - lmbelo *)
+(* lucas.belo@live.com *)
+(* BH, Brazil *)
+(* *)
+(* PyScripter *)
+(* e-mail: pyscripter@gmail.com *)
+(* *)
+(* Project pages: https://github.com/Embarcadero/python4delphi *)
+(* https://github.com/pyscripter/python4delphi *)
+(**************************************************************************)
+(* Functionality: Test unit for variants *)
+(* *)
+(* *)
+(**************************************************************************)
+(* This source code is distributed with no WARRANTY, for no reason or use.*)
+(* Everyone is allowed to use and change this code free for his own tasks *)
+(* and projects, as long as this header and its copyright text is intact. *)
+(* For changed versions of this code, which are public distributed the *)
+(* following additional conditions have to be fullfilled: *)
+(* 1) The header has to contain a comment on the change and the author of *)
+(* it. *)
+(* 2) A copy of the changed source has to be sent to the above E-Mail *)
+(* address or my then valid address, if this is possible to the *)
+(* author. *)
+(* The second condition has the target to maintain an up to date central *)
+(* version of the component. If this condition is not acceptable for *)
+(* confidential or legal reasons, everyone is free to derive a component *)
+(* or to generate a diff file to my or other original sources. *)
+(**************************************************************************)
+
+unit VarPythTest;
+
+interface
+
+uses
+ DUnitX.TestFramework,
+ PythonEngine,
+ PythonLoad;
+
+type
+ {$M+}
+ [TestFixture]
+ TVarPythTest = class
+ private
+ FPythonEngine: TPythonEngine;
+ public
+ [SetupFixture]
+ procedure SetupFixture;
+ [TearDownFixture]
+ procedure TearDownFixture;
+ [Test]
+ procedure TestIterator;
+ [Test]
+ procedure TestIntegers;
+ [Test]
+ procedure TestFloats;
+ [Test]
+ procedure TestStrings;
+ [Test]
+ procedure TestSequences;
+ [Test]
+ procedure TestMappings;
+ [Test]
+ procedure TestDates;
+ [Test]
+ procedure TestObjects;
+ end;
+
+implementation
+
+uses
+ SysUtils, StrUtils,
+ Variants,
+ VarPyth;
+
+{ TVarPythTest }
+
+procedure TVarPythTest.SetupFixture;
+begin
+ FPythonEngine := TPythonEngine.Create(nil);
+ FPythonEngine.Name := 'PythonEngine';
+ TPythonLoad.Configure(FPythonEngine);
+ FPythonEngine.LoadDll;
+end;
+procedure TVarPythTest.TearDownFixture;
+begin
+ FPythonEngine.Free();
+end;
+procedure TVarPythTest.TestDates;
+var
+ a, b, _timeMod : Variant;
+ c : Variant;
+ _date, _date2 : TDateTime;
+ _year, _month, _day : Word;
+ _year2, _month2, _day2 : Word;
+ _hour, _min, _sec, _msec : Word;
+ _hour2, _min2, _sec2, _msec2 : Word;
+begin
+ _timeMod := Import('time'); // get the time module of Python
+ _date := Now;
+ DecodeDate( _date, _year, _month, _day );
+ DecodeTime( _date, _hour, _min, _sec, _msec );
+ b := _timeMod.localtime(_timeMod.time()); // same as Now in Delphi
+ a := VarPythonCreate(_date);
+ Assert.IsTrue( a.Length = 9 );
+ Assert.IsTrue( a.GetItem(0) = _year );
+ Assert.IsTrue( a.GetItem(1) = _month );
+ Assert.IsTrue( a.GetItem(2) = _day );
+ Assert.IsTrue( a.GetItem(3) = _hour );
+ Assert.IsTrue( a.GetItem(4) = _min );
+ Assert.IsTrue( a.GetItem(5) = _sec );
+ Assert.IsTrue( b.Length = 9 );
+ Assert.IsTrue( b.GetItem(0) = a.GetItem(0) );
+ Assert.IsTrue( b.GetItem(1) = a.GetItem(1) );
+ Assert.IsTrue( b.GetItem(2) = a.GetItem(2) );
+ Assert.IsTrue( b.GetItem(3) = a.GetItem(3) );
+ Assert.IsTrue( b.GetItem(4) = a.GetItem(4) );
+ Assert.IsTrue( b.GetItem(5) = a.GetItem(5) );
+ Assert.IsTrue( b.GetItem(6) = a.GetItem(6) );
+ Assert.IsTrue( b.GetItem(7) = a.GetItem(7) );
+ // don't test the 9th item of the tuple, because it's the daylight saving,
+ // and it's not computed by the Python for Delphi.
+ //Assert.IsTrue( b.GetItem(8) = a.GetItem(8) );
+ _date2 := b;
+ DecodeDate( _date2, _year2, _month2, _day2 );
+ DecodeTime( _date2, _hour2, _min2, _sec2, _msec2 );
+ Assert.IsTrue( _year2 = _year );
+ Assert.IsTrue( _month2 = _month );
+ Assert.IsTrue( _day2 = _day );
+ Assert.IsTrue( _hour2 = _hour );
+ Assert.IsTrue( _min2 = _min );
+ Assert.IsTrue( _sec2 = _sec );
+ // test new datetime module
+ _timeMod := Import('datetime'); // get the datetime module of Python
+ //or _timeMod := DatetimeModule; // get the datetime module of Python
+ a := _timeMod.datetime(2002, 12, 30, 22, 15, 38, 827738);
+ Assert.IsTrue(VarIsPythonDateTime(a));
+ Assert.IsTrue(VarIsPythonDate(a));
+ Assert.IsTrue(not VarIsPythonTime(a));
+ Assert.IsTrue(not VarIsPythonDateTimeDelta(a));
+ Assert.IsTrue(a.year = 2002);
+ Assert.IsTrue(a.month = 12);
+ Assert.IsTrue(a.day = 30);
+ Assert.IsTrue(a.hour = 22);
+ Assert.IsTrue(a.minute = 15);
+ Assert.IsTrue(a.second = 38);
+ Assert.IsTrue(a.microsecond = 827738);
+ _date := a;
+ DecodeDate( _date, _year, _month, _day );
+ DecodeTime( _date, _hour, _min, _sec, _msec );
+ Assert.IsTrue(_year = 2002);
+ Assert.IsTrue(_month = 12);
+ Assert.IsTrue(_day = 30);
+ Assert.IsTrue(_hour = 22);
+ Assert.IsTrue(_min = 15);
+ Assert.IsTrue(_sec = 38);
+ Assert.IsTrue(_msec = 827738 div 1000);
+ a := _timeMod.date(2002, 12, 30);
+ Assert.IsTrue(not VarIsPythonDateTime(a));
+ Assert.IsTrue(VarIsPythonDate(a));
+ Assert.IsTrue(not VarIsPythonTime(a));
+ Assert.IsTrue(not VarIsPythonDateTimeDelta(a));
+ _date := a;
+ DecodeDate( _date, _year, _month, _day );
+ DecodeTime( _date, _hour, _min, _sec, _msec );
+ Assert.IsTrue(_year = 2002);
+ Assert.IsTrue(_month = 12);
+ Assert.IsTrue(_day = 30);
+ Assert.IsTrue(_hour = 0);
+ Assert.IsTrue(_min = 0);
+ Assert.IsTrue(_sec = 0);
+ Assert.IsTrue(_msec = 0);
+ Assert.IsTrue(a.year = 2002);
+ Assert.IsTrue(a.month = 12);
+ Assert.IsTrue(a.day = 30);
+ a := _timeMod.time(22, 15, 38, 827738);
+ Assert.IsTrue(not VarIsPythonDateTime(a));
+ Assert.IsTrue(not VarIsPythonDate(a));
+ Assert.IsTrue(VarIsPythonTime(a));
+ Assert.IsTrue(not VarIsPythonDateTimeDelta(a));
+ Assert.IsTrue(a.hour = 22);
+ Assert.IsTrue(a.minute = 15);
+ Assert.IsTrue(a.second = 38);
+ Assert.IsTrue(a.microsecond = 827738);
+ _date := a;
+ DecodeTime( _date, _hour, _min, _sec, _msec );
+ Assert.IsTrue(_hour = 22);
+ Assert.IsTrue(_min = 15);
+ Assert.IsTrue(_sec = 38);
+ Assert.IsTrue(_msec = 827738 div 1000);
+ a := DatetimeModule.datetime(2002, 12, 30, 22, 15, 38, 827738);
+ b := _timeMod.datetime(2002, 12, 30, 22, 16, 38, 827738);
+ c := b - a;
+ Assert.IsTrue(VarIsPythonDateTimeDelta(c));
+ Assert.IsTrue(c.days = 0);
+ Assert.IsTrue(c.seconds = 60);
+ Assert.IsTrue(c.microseconds = 0);
+ _date := c;
+ Assert.IsTrue(Trunc(_date)=0);
+ DecodeTime( _date, _hour, _min, _sec, _msec );
+ Assert.IsTrue(_hour = 0);
+ Assert.IsTrue(_min = 1);
+ Assert.IsTrue(_sec = 0);
+ Assert.IsTrue(_msec = 0);
+ c := a - b;
+ Assert.IsTrue(VarIsPythonDateTimeDelta(c));
+ Assert.IsTrue(c.days = -1);
+ Assert.IsTrue(c.seconds = 86340);
+ Assert.IsTrue(c.microseconds = 0);
+ _date := c;
+ Assert.IsTrue(Trunc(_date)=0);
+ Assert.IsTrue(_date<0);
+ DecodeTime( _date, _hour, _min, _sec, _msec );
+ Assert.IsTrue(_hour = 0);
+ Assert.IsTrue(_min = 1);
+ Assert.IsTrue(_sec = 0);
+ Assert.IsTrue(_msec = 0);
+ c := a + (b-a);
+ Assert.IsTrue(VarIsPythonDateTime(c));
+ Assert.IsTrue(c = b);
+ Assert.IsTrue(c <> a);
+ Assert.IsTrue(a < b);
+ Assert.IsTrue(b > a);
+ GetPythonEngine.DatetimeConversionMode := dcmToDatetime;
+ try
+ _date := EncodeDate(2003, 01, 28) + EncodeTime(12, 22, 33, 450);
+ a := VarPythonCreate(_date);
+ Assert.IsTrue(VarIsPythonDateTime(c));
+ _date2 := a;
+ DecodeDate( _date, _year, _month, _day );
+ DecodeTime( _date, _hour, _min, _sec, _msec );
+ DecodeDate( _date2, _year2, _month2, _day2 );
+ DecodeTime( _date2, _hour2, _min2, _sec2, _msec2 );
+ Assert.IsTrue( _year2 = _year );
+ Assert.IsTrue( _month2 = _month );
+ Assert.IsTrue( _day2 = _day );
+ Assert.IsTrue( _hour2 = _hour );
+ Assert.IsTrue( _min2 = _min );
+ Assert.IsTrue( _sec2 = _sec );
+ Assert.IsTrue( _msec2 = _msec );
+ Assert.IsTrue(a.year = 2003);
+ Assert.IsTrue(a.month = 01);
+ Assert.IsTrue(a.day = 28);
+ Assert.IsTrue(a.hour = 12);
+ Assert.IsTrue(a.minute = 22);
+ Assert.IsTrue(a.second = 33);
+ Assert.IsTrue(a.microsecond = 450000);
+ finally
+ GetPythonEngine.DatetimeConversionMode := dcmToTuple;
+ end;
+end;
+procedure TVarPythTest.TestFloats;
+var
+ a, b, c : Variant;
+ dbl_a, dbl_b, dbl_c : Double;
+ int : Integer;
+begin
+ // initialize the operands
+ dbl_a := 2.5;
+ a := VarPythonCreate(dbl_a);
+ Assert.IsTrue(VarIsPython(a));
+ Assert.IsTrue(VarIsPythonNumber(a));
+ Assert.IsTrue(VarIsPythonFloat(a));
+ Assert.IsTrue(Double(a) = 2.5);
+ dbl_b := 3.2;
+ b := VarPythonCreate(dbl_b);
+ Assert.IsTrue(VarIsPython(b));
+ Assert.IsTrue(VarIsPythonNumber(b));
+ Assert.IsTrue(VarIsPythonFloat(b));
+ Assert.IsTrue(Double(b) = dbl_b); // note that Assert.IsTrue(Double(b) = 3.2) fails.
+ // arithmetic operations
+ //----------------------
+ // addition
+ c := a + b;
+ // check result of operation
+ Assert.IsTrue( Double(c) = (dbl_a + dbl_b) );
+ // check that operation did not change the content of operands.
+ Assert.IsTrue(Double(a) = dbl_a);
+ Assert.IsTrue(Double(b) = dbl_b);
+ // now with a litteral
+ c := a + b + 1;
+ Assert.IsTrue( Double(c) = (dbl_a+dbl_b+1) );
+ c := a + 1 + b;
+ Assert.IsTrue( Double(c) = (dbl_a+1+dbl_b) );
+ c := 1 + a + b;
+ Assert.IsTrue( Double(c) = (1+dbl_a+dbl_b) );
+ // substraction
+ c := b - a;
+ Assert.IsTrue( Double(c) = (dbl_b - dbl_a) );
+ // now with a litteral
+ c := b - a - 1;
+ Assert.IsTrue( Double(c) = (dbl_b-dbl_a-1) );
+ c := b - 1 - a;
+ Assert.IsTrue( Double(c) = (dbl_b-1-dbl_a) );
+ c := 1 - b - a;
+ Assert.IsTrue( Double(c) = (1-dbl_b-dbl_a) );
+ // multiplication
+ c := a * b;
+ dbl_c := dbl_a * dbl_b;
+ Assert.IsTrue( Double(c) = dbl_c );
+ // now with a litteral
+ c := a * b * 2;
+ dbl_c := dbl_a * dbl_b * 2;
+ Assert.IsTrue( Double(c) = dbl_c );
+ c := a * 2 * b;
+ dbl_c := dbl_a * 2 * dbl_b;
+ Assert.IsTrue( Double(c) = dbl_c );
+ c := 2 * a * b;
+ dbl_c := 2 * dbl_a * dbl_b;
+ Assert.IsTrue( Double(c) = dbl_c );
+ // division: in Python a division between 2 integers is the same as the integer division
+ c := b / a;
+ dbl_c := dbl_b / dbl_a;
+ Assert.IsTrue( Double(c) = dbl_c );
+ // negation
+ c := -a;
+ Assert.IsTrue( Double(c) = -dbl_a );
+ // comparisons
+ //------------
+ // equal
+ c := a = b;
+ Assert.IsTrue(c = False);
+ c := a = a;
+ Assert.IsTrue(c = True);
+ Assert.IsTrue( a = dbl_a);
+ // not equal
+ c := a <> b;
+ Assert.IsTrue(c = True);
+ Assert.IsTrue( not (c = b) );
+ c := a <> a;
+ Assert.IsTrue(c = False);
+ Assert.IsTrue( a = dbl_a);
+ // greater than
+ c := a > b; Assert.IsTrue(c = False);
+ c := b > a; Assert.IsTrue(c = True);
+ Assert.IsTrue( a > (dbl_a-1));
+ // greater or equal than
+ c := a >= b; Assert.IsTrue(c = False);
+ c := b >= a; Assert.IsTrue(c = True);
+ c := a >= a; Assert.IsTrue(c = True);
+ Assert.IsTrue( a >= dbl_a );
+ // less than
+ c := a < b; Assert.IsTrue(c = True);
+ c := b < a; Assert.IsTrue(c = False);
+ Assert.IsTrue( a < dbl_b);
+ // less or equal than
+ c := a <= b; Assert.IsTrue(c = True);
+ c := b <= a; Assert.IsTrue(c = False);
+ c := a <= a; Assert.IsTrue(c = True);
+ Assert.IsTrue( a <= dbl_a);
+ // parenthesis
+ c := a * ((a * b) / b);
+ dbl_c := dbl_a * ((dbl_a * dbl_b) / dbl_b);
+ Assert.IsTrue( c = dbl_c );
+ // copy
+ c := a;
+ Assert.IsTrue( c = a);
+ Assert.IsTrue( VarIsSame(c, a) ); // checks if 2 variants share the same Python object.
+ // casts
+ int := a;
+ Assert.IsTrue(int = 2);
+end;
+procedure TVarPythTest.TestIntegers;
+var
+ a, b, c : Variant;
+ big : Int64;
+begin
+ // initialize the operands
+ a := VarPythonCreate(2);
+ Assert.IsTrue(VarIsPython(a));
+ Assert.IsTrue(VarIsPythonNumber(a));
+ Assert.IsTrue(VarIsPythonInteger(a));
+ Assert.IsTrue(Integer(a) = 2);
+ b := VarPythonCreate(3);
+ Assert.IsTrue(VarIsPython(b));
+ Assert.IsTrue(VarIsPythonNumber(b));
+ Assert.IsTrue(VarIsPythonInteger(b));
+ Assert.IsTrue(Integer(b) = 3);
+ // arithmetic operations
+ //----------------------
+ // addition
+ c := a + b;
+ // check result of operation
+ Assert.IsTrue( Integer(c) = 5 );
+ // check that operation did not change the content of operands.
+ Assert.IsTrue(Integer(a) = 2);
+ Assert.IsTrue(Integer(b) = 3);
+ // now with a litteral
+ c := a + b + 1;
+ Assert.IsTrue( Integer(c) = 6 );
+ c := a + 1 + b;
+ Assert.IsTrue( Integer(c) = 6 );
+ c := 1 + a + b;
+ Assert.IsTrue( Integer(c) = 6 );
+ // substraction
+ c := b - a;
+ Assert.IsTrue( Integer(c) = 1 );
+ // now with a litteral
+ c := b - a - 1;
+ Assert.IsTrue( Integer(c) = 0 );
+ c := b - 1 - a;
+ Assert.IsTrue( Integer(c) = 0 );
+ c := 1 - b - a;
+ Assert.IsTrue( Integer(c) = -4 );
+ // multiplication
+ c := a * b;
+ Assert.IsTrue( Integer(c) = 6 );
+ // now with a litteral
+ c := a * b * 2;
+ Assert.IsTrue( Integer(c) = 12 );
+ c := a * 2 * b;
+ Assert.IsTrue( Integer(c) = 12 );
+ c := 2 * a * b;
+ Assert.IsTrue( Integer(c) = 12 );
+ // integer division
+ c := b div a;
+ Assert.IsTrue( Integer(c) = 1 );
+ // division: in Python a division between 2 integers is the same as the integer division
+ c := b / a;
+ Assert.IsTrue( c = 1.5 );
+ Assert.IsTrue( Integer(c) = 2 );
+ // modulus
+ c := b mod a;
+ Assert.IsTrue( Integer(c) = 1 );
+ c := BuiltinModule.divmod(b, a); // this returns a tuple whose first item is the result of the division,
+ // and second item the modulo.
+ if VarIsPythonSequence(c) and (c.Length = 2) then
+ begin
+ Assert.IsTrue(Integer(c.GetItem(0)) = 1); // division
+ Assert.IsTrue(Integer(c.GetItem(1)) = 1); // modulo
+ end;
+ // power
+ c := BuiltinModule.pow(a, b);
+ Assert.IsTrue(c = 8);
+ // negation
+ c := -a;
+ Assert.IsTrue( Integer(c) = -2 );
+ // logical operations
+ //------------------
+ // inverse
+ c := not a; // in python it would be: c = ~2
+ Assert.IsTrue( Integer(c) = -3 );
+ // shift left (<<)
+ c := a shl b;
+ Assert.IsTrue( Integer(c) = 16 );
+ c := a shl 1;
+ Assert.IsTrue( Integer(c) = 4 );
+ // shift right (>>)
+ c := a shl b;
+ c := c shr b;
+ Assert.IsTrue( Integer(c) = Integer(a) );
+ c := b shr 1;
+ Assert.IsTrue( Integer(c) = 1 );
+ // and
+ c := a and (a*5);
+ Assert.IsTrue( Integer(c) = Integer(a) );
+ c := a and 6;
+ Assert.IsTrue( Integer(c) = Integer(a) );
+ // or
+ c := a or b;
+ Assert.IsTrue( Integer(c) = 3 );
+ c := a or 3;
+ Assert.IsTrue( Integer(c) = 3 );
+ // xor
+ c := a xor b;
+ Assert.IsTrue( Integer(c) = 1 );
+ c := a xor 3;
+ Assert.IsTrue( Integer(c) = 1 );
+ // comparisons
+ //------------
+ // equal
+ c := a = b;
+ Assert.IsTrue(c = False);
+ c := a = a;
+ Assert.IsTrue(c = True);
+ Assert.IsTrue( a = 2);
+ // not equal
+ c := a <> b;
+ Assert.IsTrue(c = True);
+ Assert.IsTrue( not (c = b) );
+ c := a <> a;
+ Assert.IsTrue(c = False);
+ Assert.IsTrue( a = 2);
+ // greater than
+ c := a > b; Assert.IsTrue(c = False);
+ c := b > a; Assert.IsTrue(c = True);
+ Assert.IsTrue( a > 1);
+ // greater or equal than
+ c := a >= b; Assert.IsTrue(c = False);
+ c := b >= a; Assert.IsTrue(c = True);
+ c := a >= a; Assert.IsTrue(c = True);
+ Assert.IsTrue( a >= 2 );
+ // less than
+ c := a < b; Assert.IsTrue(c = True);
+ c := b < a; Assert.IsTrue(c = False);
+ Assert.IsTrue( a < 6);
+ // less or equal than
+ c := a <= b; Assert.IsTrue(c = True);
+ c := b <= a; Assert.IsTrue(c = False);
+ c := a <= a; Assert.IsTrue(c = True);
+ Assert.IsTrue( a <= 2);
+ // parenthesis
+ c := a * ((a * b) div b);
+ Assert.IsTrue( c = a*2 );
+ // copy
+ c := a;
+ Assert.IsTrue( c = a);
+ Assert.IsTrue( VarIsSame(c, a) ); // checks if 2 variants share the same Python object.
+ // test long long (Int64)
+ big := Int64(MaxInt)*4;
+ b := VarPythonCreate(big);
+ Assert.IsTrue( b = big );
+ Assert.IsTrue( b <> big+1 );
+ Assert.IsTrue( b > MaxInt );
+ Assert.IsTrue( MaxInt < b );
+ Assert.IsTrue( b+1 = big+1 );
+ Assert.IsTrue( b*2 = big*2 );
+ Assert.IsTrue( b div 2 = big div 2 );
+ c := VarPythonCreate(True);
+ Assert.IsTrue(VarIsBool(c));
+ Assert.IsTrue(VarIsTrue(c));
+ c := VarPythonCreate(False);
+ Assert.IsTrue(VarIsBool(c));
+ Assert.IsTrue(not VarIsTrue(c));
+end;
+procedure TVarPythTest.TestIterator;
+var
+ Module: Variant;
+ Count: integer;
+begin
+ Count := 0;
+ for Module in VarPyIterate(SysModule.modules) do begin
+ Count := Count + 1;
+ Log(Module);
+ end;
+ Assert.IsTrue(Count = len(SysModule.modules));
+end;
+procedure TVarPythTest.TestMappings;
+var
+ a, b, c, keys, values : Variant;
+begin
+ // initialize the operands
+ a := NewPythonDict;
+ Assert.IsTrue(VarIsPython(a));
+ Assert.IsTrue(VarIsPythonMapping(a));
+ Assert.IsTrue(VarIsPythonDict(a));
+ // There is a bug in D2010 in which Char('a') gets translated to integer parameter
+ a.SetItem( string('a'), 1 );
+ a.SetItem( string('b'), 2 );
+ a.SetItem( string('c'), 3 );
+ Assert.IsTrue(a.Length = 3); // this is a special property that does the same as: len(a) in Python
+ Assert.IsTrue(a.Length() = 3); // this is a special method that does the same as the special property
+ Assert.IsTrue(len(a) = 3);
+ Assert.IsTrue(a.GetItem(string('a')) = 1); // this is a special method that lets you do the same as: a[0] in Python
+ Assert.IsTrue(a.GetItem(string('b')) = 2);
+ Assert.IsTrue(a.GetItem(string('c')) = 3);
+
+
+ b := NewPythonDict;
+ Assert.IsTrue(VarIsPython(b));
+ Assert.IsTrue(VarIsPythonMapping(b));
+ Assert.IsTrue(VarIsPythonDict(b));
+ b.SetItem( string('d'), 4 );
+ b.SetItem( string('e'), 5 );
+ b.SetItem( string('f'), 6 );
+ Assert.IsTrue(b.Length = 3);
+ Assert.IsTrue(b.Length() = 3);
+ Assert.IsTrue(len(b) = 3);
+ Assert.IsTrue(b.GetItem(string('d')) = 4);
+ Assert.IsTrue(b.GetItem(string('e')) = 5);
+ Assert.IsTrue(b.GetItem(string('f')) = 6);
+
+ // copy
+ c := a;
+ Assert.IsTrue( c = a);
+ Assert.IsTrue( VarIsSame(c, a) ); // checks if 2 variants share the same Python object.
+
+ // dict methods
+ Assert.IsTrue( Boolean(a.__contains__(string('a'))) );
+ Assert.IsTrue( not Boolean(a.__contains__('abc')) );
+ keys := BuiltinModule.list(a.keys());
+ keys.sort();
+ Assert.IsTrue( keys = VarPythonCreate(VarArrayOf(['a', 'b', 'c'])));
+ values := BuiltinModule.list(a.values());
+ values.sort();
+ Assert.IsTrue( values = VarPythonCreate(VarArrayOf([1, 2, 3])));
+ c := a;
+ c.DeleteItem(string('a'));
+ Assert.IsTrue( not Boolean(c.__contains__(string('a'))) );
+
+ // test string values
+ a := NewPythonDict;
+ a.SetItem( string('a'), 'Hello');
+ a.SetItem( string('b'), 'World!');
+ a.SetItem( string('c'), '');
+ Assert.IsTrue(a.GetItem(string('a')) = 'Hello');
+ Assert.IsTrue(a.GetItem(string('b')) = 'World!');
+ Assert.IsTrue(a.GetItem(string('c')) = '');
+end;
+
+procedure TVarPythTest.TestObjects;
+var
+ _main, f, a, b, c : Variant;
+ val : Integer;
+ _str : String;
+const
+ Script =
+ 'class XYZ(object):' + sLineBreak +
+ ' pass' + sLineBreak +
+ '' + sLineBreak +
+ 'class Foo:' + sLineBreak +
+ ' def __init__(Self, Value=0):' + sLineBreak +
+ ' Self.Value = Value' + sLineBreak +
+ ' def __del__(Self):' + sLineBreak +
+ ' print("delete", Self)' + sLineBreak +
+ ' def __add__(self, other):' + sLineBreak +
+ ' return Foo(self.Value + other.Value)' + sLineBreak +
+ ' def Inc(Self, AValue = 1):' + sLineBreak +
+ ' Self.Value = Self.Value + AValue' + sLineBreak +
+ ' def GetSelf(Self):' + sLineBreak +
+ ' return Self' + sLineBreak +
+ ' def GetValue(Self):' + sLineBreak +
+ ' return Self.Value' + sLineBreak +
+ ' def SetABC(Self, A, B, C):' + sLineBreak +
+ ' Self.A = A' + sLineBreak +
+ ' Self.B = B' + sLineBreak +
+ ' Self.C = C' + sLineBreak +
+ ' def Add(Self, AFooInst):' + sLineBreak +
+ ' Self.Value = Self.Value + AFooInst.Value' + sLineBreak +
+ 'class Bar(Foo):' + sLineBreak +
+ ' def Inc(Self, AValue = 1):' + sLineBreak +
+ ' Self.Value = Self.Value - AValue' + sLineBreak +
+ 'def Add(a, b):' + sLineBreak +
+ ' return a + b' + sLineBreak +
+ 'def MakeList(a, b, c, d):' + sLineBreak +
+ ' return [a, b, c, d]' + sLineBreak +
+ '' + sLineBreak +
+ 'f = Foo()' + sLineBreak +
+ 'print("Created", f)' + sLineBreak +
+ 'f.Inc()' + sLineBreak +
+ 'f.Inc(2)' + sLineBreak +
+ 'b = Bar()' + sLineBreak +
+ 'b.Inc()' + sLineBreak +
+ 'b.Inc(2)';
+
+begin
+ FPythonEngine.ExecString(Script);
+ _main := MainModule;
+ Assert.IsTrue( VarIsPythonModule(_main) );
+ Assert.IsTrue( VarIsPythonModule(SysModule) );
+ Assert.IsTrue( Import('sys').version = SysModule.version );
+ Log(SysModule.version);
+ Assert.IsTrue( Boolean(SysModule.modules.Contains(GetPythonEngine.ExecModule)) ); // if __main__ in sys.modules
+ Assert.IsTrue( VarIsSameType(_main, SysModule) );
+ Assert.IsTrue( _type(_main).__name__ = 'module');
+ Assert.IsTrue( BuiltinModule.type(_main).__name__ = 'module');
+
+ Assert.IsTrue( VarIsPythonClass(_main.Foo) );
+ Assert.IsTrue( VarIsPythonClass(_main.Bar) );
+ Assert.IsTrue( VarIsPythonClass(_main.XYZ) );
+ Assert.IsTrue( not VarIsPythonClass(_main.Foo.__add__) );
+ Assert.IsTrue( not VarIsPythonClass(_main.f) );
+ Assert.IsTrue( VarIsPythonCallable(_main.Foo) );
+ Assert.IsTrue( VarIsPythonCallable(_main.Foo) );
+ Assert.IsTrue( VarIsTrue(BuiltinModule.callable(_main.Foo)) );
+ Assert.IsTrue( VarIsSame(_main.f.__class__, _main.Foo) );
+ Assert.IsTrue( VarIsPythonMethod(_main.f.Inc) );
+ Assert.IsTrue( VarIsPythonCallable(_main.f.Inc) );
+ Assert.IsTrue( VarIsTrue(BuiltinModule.callable(_main.f.Inc)) );
+ Assert.IsTrue( VarIsPythonFunction(_main.Add) );
+ Assert.IsTrue( VarIsPythonCallable(_main.Add) );
+ Assert.IsTrue( VarIsInstanceOf(_main.f, _main.Foo) );
+ Assert.IsTrue( VarIsTrue(BuiltinModule.isinstance(_main.f, _main.Foo)) );
+ Assert.IsTrue( VarIsSubclassOf(_main.Bar, _main.Foo) );
+ Assert.IsTrue( VarIsTrue(BuiltinModule.issubclass(_main.Bar, _main.Foo)) );
+ Assert.IsTrue( not VarIsSubclassOf(_main.Foo, _main.Bar) );
+ Assert.IsTrue( VarIsInstanceOf(_main.b, _main.Foo) );
+ Assert.IsTrue( not VarIsInstanceOf(_main.f, _main.Bar) );
+ Assert.IsTrue( VarIsTrue( BuiltinModule.vars(_main).__contains__(string('f')) ) );
+ Assert.IsTrue( VarIsTrue( BuiltinModule.dir(_main).Contains(string('f')) ) );
+
+ f := _main.Foo(); // new instance of class Foo
+ Log('Instanciate class Foo: ' + f);
+ f.Inc(); // call a method without any arg, because there's a default arg.
+ f.Inc(2); // call a method with one arg, overriding the default arg.
+ Assert.IsTrue( VarIsPythonNumber(f.Value) );
+ Assert.IsTrue( VarIsPythonInteger(f.Value) );
+ Assert.IsTrue( f.Value = _main.f.Value ); // compare the result with what we did in the script
+ Assert.IsTrue( f.GetValue() = _main.f.GetValue() ); // compare the result with what we did in the script
+ Assert.IsTrue( VarIsPython( f.GetSelf() ) );
+ Assert.IsTrue( VarIsSame( f.GetSelf(), f ) );
+ Assert.IsTrue( BuiltinModule.getattr(f, 'Value') = f.Value );
+ // python (+) operator overloading
+ a := _main.Foo(10);
+ b := _main.Foo(5);
+ c := a + b;
+ Assert.IsTrue(a.Value = 10);
+ Assert.IsTrue(b.Value = 5);
+ Assert.IsTrue(c.Value = 15);
+ Log('Test -> a, b, c : ' + a.Value + ', ' + b.Value + ', ' + c.Value);
+ // cascading calls
+ Assert.IsTrue( f.GetSelf().GetSelf().GetSelf().GetSelf().GetValue() = _main.f.GetValue() );
+ Assert.IsTrue( Boolean(f.__dict__.__contains__('Value')) );
+ Assert.IsTrue( VarIsTrue( BuiltinModule.hasattr(f, 'Value') ) );
+ _str := 'Value';
+ Assert.IsTrue( Boolean(f.__dict__.__contains__(_str)) ); // check with a string var
+ Assert.IsTrue( Boolean( BuiltinModule.hasattr(f, _str) ) );
+ val := f.Value;
+ f.Add(f); // passing itself as an argument
+ Assert.IsTrue( f.Value = val*2 );
+ // check param order
+ f.SetABC(1, 2, 3);
+ Assert.IsTrue(f.A = 1);
+ Assert.IsTrue(f.B = 2);
+ Assert.IsTrue(f.C = 3);
+ // add a property to an instance
+ f.Z := 99;
+ Assert.IsTrue(f.Z = 99);
+ // add a var to a module
+ _main.Z := 99;
+ Assert.IsTrue(_main.Z = 99);
+ // check none
+ Assert.IsTrue( VarIsNone(None) );
+ Assert.IsTrue( VarIsNone(VarPythonCreate([1, Null, 3]).GetItem(1)) ); // Null is casted to None
+ Assert.IsTrue( VarIsNone(VarPythonCreate([1, None, 3]).GetItem(1)) );
+ Assert.IsTrue( VarIsNone(f.Inc()) );
+ Assert.IsTrue( f.Inc() = None );
+ Assert.IsTrue( not Boolean(None) ); // if not None:
+ Assert.IsTrue( not VarIsTrue(None) ); // if not None:
+ Assert.IsTrue( Boolean(f) ); // if f:
+ Assert.IsTrue( VarIsTrue(f) ); // if f:
+
+ // call a function
+ Assert.IsTrue( _main.Add(2, 2) = 4 );
+ // call a function with a mix of regular parameters and named parameters
+ f := _main.MakeList(1, 2, 3, 4);
+ Assert.IsTrue(VarIsPythonList(f));
+ Assert.IsTrue(f.Length = 4);
+ Assert.IsTrue(f.GetItem(0) = 1);
+ Assert.IsTrue(f.GetItem(1) = 2);
+ Assert.IsTrue(f.GetItem(2) = 3);
+ Assert.IsTrue(f.GetItem(3) = 4);
+ f := _main.MakeList(1, d:=3, c:=4, b:=2);
+ Assert.IsTrue(VarIsPythonList(f));
+ Assert.IsTrue(f.Length = 4);
+ Assert.IsTrue(f.GetItem(0) = 1);
+ Assert.IsTrue(f.GetItem(1) = 2);
+ Assert.IsTrue(f.GetItem(2) = 4);
+ Assert.IsTrue(f.GetItem(3) = 3);
+ f := _main.MakeList(1, 2, d:= 3, c:=4);
+ Assert.IsTrue(VarIsPythonList(f));
+ Assert.IsTrue(f.Length = 4);
+ Assert.IsTrue(f.GetItem(0) = 1);
+ Assert.IsTrue(f.GetItem(1) = 2);
+ Assert.IsTrue(f.GetItem(2) = 4);
+ Assert.IsTrue(f.GetItem(3) = 3);
+ f := _main.MakeList(1, 2, 3, d:=4);
+ Assert.IsTrue(VarIsPythonList(f));
+ Assert.IsTrue(f.Length = 4);
+ Assert.IsTrue(f.GetItem(0) = 1);
+ Assert.IsTrue(f.GetItem(1) = 2);
+ Assert.IsTrue(f.GetItem(2) = 3);
+ Assert.IsTrue(f.GetItem(3) = 4);
+ f := _main.MakeList(b:=1, a:=2, d:= 3, c:=4);
+ Assert.IsTrue(VarIsPythonList(f));
+ Assert.IsTrue(f.Length = 4);
+ Assert.IsTrue(f.GetItem(0) = 2);
+ Assert.IsTrue(f.GetItem(1) = 1);
+ Assert.IsTrue(f.GetItem(2) = 4);
+ Assert.IsTrue(f.GetItem(3) = 3);
+end;
+procedure TVarPythTest.TestSequences;
+var
+ a, b, c : Variant;
+ iter : Variant;
+ cpt : Integer;
+begin
+ // initialize the operands
+ // you can either use the overloaded function with an array of const
+ // or use the VarArrayOf function that returns an array of variants that will
+ // be casted to a Python list.
+ a := VarPythonCreate([1, 2, 3]);
+ Assert.IsTrue(VarIsPython(a));
+ Assert.IsTrue(VarIsPythonSequence(a));
+ Assert.IsTrue(VarIsPythonList(a));
+ Assert.IsTrue(a.Length = 3); // this is a special property that does the same as: len(a) in Python
+ Assert.IsTrue(a.Length() = 3); // this is a special method that does the same as the special property
+ Assert.IsTrue(len(a) = 3);
+ Assert.IsTrue(a.GetItem(0) = 1); // this is a special method that lets you do the same as: a[0] in Python
+ Assert.IsTrue(a.GetItem(1) = 2);
+ Assert.IsTrue(a.GetItem(2) = 3);
+ Assert.IsTrue(string(a) = '[1, 2, 3]');
+ // indexed access using brackets when the sequence is a property of an object (module, instance...)
+ MainModule.a := VarPythonCreate([1, 2, 3]);
+ Assert.IsTrue(MainModule.a[1] = 2);
+
+ b := VarPythonCreate(VarArrayOf([4, 5, 6]));
+ Assert.IsTrue(VarIsPython(b));
+ Assert.IsTrue(VarIsPythonSequence(b));
+ Assert.IsTrue(VarIsPythonList(b));
+ Assert.IsTrue(b.Length = 3);
+ Assert.IsTrue(b.Length() = 3);
+ Assert.IsTrue(len(b) = 3);
+ Assert.IsTrue(b.GetItem(0) = 4);
+ Assert.IsTrue(b.GetItem(1) = 5);
+ Assert.IsTrue(b.GetItem(2) = 6);
+ Assert.IsTrue(string(b) = '[4, 5, 6]');
+ // concatenation
+ c := a + b;
+ // check result of operation
+ Assert.IsTrue(string(c) = '[1, 2, 3, 4, 5, 6]');
+ // check that operation did not change the content of operands.
+ Assert.IsTrue(string(a) = '[1, 2, 3]');
+ Assert.IsTrue(string(b) = '[4, 5, 6]');
+ // now with a litteral: note that with D6 SP1, we can't concatenate a custom variant with an var array of variants
+ c := a + b + VarPythonCreate(['Hello', 'World!', 3.14]);
+ Assert.IsTrue( string(c) = '[1, 2, 3, 4, 5, 6, ''Hello'', ''World!'', 3.14]' );
+ c := a + VarPythonCreate(['Hello', 'World!', 3.14]) + b;
+ Assert.IsTrue( string(c) = '[1, 2, 3, ''Hello'', ''World!'', 3.14, 4, 5, 6]' );
+ c := VarPythonCreate(['Hello', 'World!', 3.14]) + a + b;
+ Assert.IsTrue( string(c) = '[''Hello'', ''World!'', 3.14, 1, 2, 3, 4, 5, 6]' );
+
+ // multiplication
+ c := a * 3; // in Python the multiplication of sequence concatenates n times the sequence
+ Assert.IsTrue( string(c) = '[1, 2, 3, 1, 2, 3, 1, 2, 3]' );
+
+ // comparisons
+ //------------
+
+ // equal
+ c := a = b;
+ Assert.IsTrue(c = False);
+ c := a = a;
+ Assert.IsTrue(c = True);
+ Assert.IsTrue( string(a) = '[1, 2, 3]');
+
+ // not equal
+ c := a <> b;
+ Assert.IsTrue(c = True);
+ Assert.IsTrue( not (c = b) );
+ c := a <> a;
+ Assert.IsTrue(c = False);
+ Assert.IsTrue( string(a) = '[1, 2, 3]');
+
+ // greater than
+ c := a > b; Assert.IsTrue(c = False);
+ c := b > a; Assert.IsTrue(c = True);
+ Assert.IsTrue( string(a) > '[1, 1, 1]');
+
+ // greater or equal than
+ c := a >= b; Assert.IsTrue(c = False);
+ c := b >= a; Assert.IsTrue(c = True);
+ c := a >= a; Assert.IsTrue(c = True);
+ Assert.IsTrue( string(a) >= '[1, 2, 3]' );
+
+ // less than
+ c := a < b; Assert.IsTrue(c = True);
+ c := b < a; Assert.IsTrue(c = False);
+ Assert.IsTrue( string(a) < '[4, 4, 4]');
+
+ // less or equal than
+ c := a <= b; Assert.IsTrue(c = True);
+ c := b <= a; Assert.IsTrue(c = False);
+ c := a <= a; Assert.IsTrue(c = True);
+ Assert.IsTrue( string(a) <= '[1, 2, 3]');
+
+ // copy
+ c := a;
+ Assert.IsTrue( c = a);
+ Assert.IsTrue( VarIsSame(c, a) ); // checks if 2 variants share the same Python object.
+
+ // sequence methods:
+ c := b + a;
+ c.sort(); // note that you must you the parenthesis to distinguish the call between a method or a property.
+ Assert.IsTrue( c = (a+b) );
+
+ c := NewPythonList; // facility for building sequences
+ Assert.IsTrue( not VarIsTrue(c) ); // c is false because it's an empty collection
+ c.append(1);
+ c.append(2);
+ c.append(3);
+ Assert.IsTrue( VarIsTrue(c) ); // c is true because it's not an empty collection
+ Assert.IsTrue(c = a);
+ Assert.IsTrue( c.pop() = 3 );
+ Assert.IsTrue( string(c) = '[1, 2]');
+
+ c := NewPythonList(3); // facility for building sequences
+ c.SetItem(0, 1);
+ c.SetItem(1, 2);
+ c.SetItem(2, 3);
+ Assert.IsTrue(c = a);
+ c.DeleteItem(1);
+ Assert.IsTrue(c = VarPythonCreate([1,3]));
+
+ Assert.IsTrue(VarPythonCreate([1,2,3,4]).GetSlice(1, 3) = VarPythonCreate([2,3])); // same as x = [1,2,3,4]; x[1:3]
+ Assert.IsTrue(VarPythonCreate([1,2,3,4]).GetSlice(1, Ellipsis) = VarPythonCreate([2,3,4])); // same as x = [1,2,3,4]; x[1:]
+ Assert.IsTrue(VarPythonCreate([1,2,3,4]).GetSlice(1, -1) = VarPythonCreate([2,3])); // same as x = [1,2,3,4]; x[1:-1]
+ c := VarPythonCreate([1,2,3,4]);
+ c.SetSlice(1, 3, VarPythonCreate([7, 8, 9]));
+ Assert.IsTrue( c = VarPythonCreate([1, 7, 8, 9, 4]) );
+ Assert.IsTrue( Boolean(c.Contains( 7 )) ); // same as 7 in c
+ Assert.IsTrue( not Boolean(c.Contains( 77 )) );
+ c.DelSlice(1,3);
+ Assert.IsTrue( c = VarPythonCreate([1,9,4]) );
+
+ c := VarPythonCreate([1, 2, 3, 4], stTuple); // test a tuple
+ Assert.IsTrue( VarIsPythonTuple(c) );
+ Assert.IsTrue( VarIsPythonSequence(c) );
+ Assert.IsTrue( c.GetItem(1) = 2 );
+ Assert.IsTrue( c.Length = 4 );
+ c := NewPythonTuple(3);
+ c.SetItem(0, 1);
+ c.SetItem(1, 2);
+ c.SetItem(2, 3);
+ Assert.IsTrue( VarIsPythonTuple(c) );
+ Assert.IsTrue( VarIsPythonSequence(c) );
+ Assert.IsTrue( c.GetItem(1) = 2 );
+ Assert.IsTrue( c.Length = 3 );
+
+ // test iterator
+ iter := BuiltinModule.iter(VarPythonCreate([1, 2, 3, 4], stTuple));
+ Assert.IsTrue(VarIsPythonIterator(iter));
+ Assert.IsTrue(iter.__next__() = 1);
+ Assert.IsTrue(iter.__next__() = 2);
+ Assert.IsTrue(iter.__next__() = 3);
+ Assert.IsTrue(iter.__next__() = 4);
+ try
+ iter.__next__();
+ except
+ on E: EPyStopIteration do
+ begin
+ Assert.IsTrue(True); //Ok.
+ end
+ else
+ Assert.IsTrue(False, 'expected stop exception');
+ end;
+ cpt := 0;
+ iter := VarPyth.iter(VarPythonCreate([1, 2, 3, 4], stTuple));
+ Assert.IsTrue(VarIsPythonIterator(iter));
+ try
+ while True do
+ begin
+ a := iter.__next__();
+ Inc(cpt);
+ Assert.IsTrue(a = cpt);
+ end;
+ except
+ on E: EPyStopIteration do
+ begin
+ Assert.IsTrue(True); //Ok.
+ end
+ else
+ Assert.IsTrue(False, 'expected stop exception');
+ end;
+ Assert.IsTrue(cpt = 4);
+end;
+procedure TVarPythTest.TestStrings;
+var
+ a, b, c : Variant;
+ w : WideString;
+ _obj : PPyObject;
+begin
+ // initialize the operands
+ a := VarPythonCreate('abc');
+ Assert.IsTrue(VarIsPython(a));
+ Assert.IsTrue(VarIsPythonString(a));
+ Assert.IsTrue(string(a) = 'abc');
+ b := VarPythonCreate('def');
+ Assert.IsTrue(VarIsPython(b));
+ Assert.IsTrue(VarIsPythonString(b));
+ Assert.IsTrue(string(b) = 'def');
+ // concatenation
+ c := a + b;
+ // check result of operation
+ Assert.IsTrue( string(c) = 'abcdef' );
+ // check that operation did not change the content of operands.
+ Assert.IsTrue(string(a) = 'abc');
+ Assert.IsTrue(string(b) = 'def');
+ // now with a litteral
+ c := a + b + '!';
+ Assert.IsTrue( string(c) = 'abcdef!' );
+ c := a + '!' + b;
+ Assert.IsTrue( string(c) = 'abc!def' );
+ c := '!' + a + b;
+ Assert.IsTrue( string(c) = '!abcdef' );
+ // multiplication
+ c := a * 3; // in Python the multiplication of string concatenates n times the string
+ Assert.IsTrue( string(c) = 'abcabcabc' );
+ // comparisons
+ //------------
+ // equal
+ c := a = b;
+ Assert.IsTrue(c = False);
+ c := a = a;
+ Assert.IsTrue(c = True);
+ Assert.IsTrue( a = 'abc');
+ // not equal
+ c := a <> b;
+ Assert.IsTrue(c = True);
+ Assert.IsTrue( not (c = b) );
+ c := a <> a;
+ Assert.IsTrue(c = False);
+ Assert.IsTrue( a = 'abc');
+ // greater than
+ c := a > b; Assert.IsTrue(c = False);
+ c := b > a; Assert.IsTrue(c = True);
+ Assert.IsTrue( a > 'aaa');
+ // greater or equal than
+ c := a >= b; Assert.IsTrue(c = False);
+ c := b >= a; Assert.IsTrue(c = True);
+ c := a >= a; Assert.IsTrue(c = True);
+ Assert.IsTrue( a >= 'abc' );
+ // less than
+ c := a < b; Assert.IsTrue(c = True);
+ c := b < a; Assert.IsTrue(c = False);
+ Assert.IsTrue( a < 'bbb');
+ // less or equal than
+ c := a <= b; Assert.IsTrue(c = True);
+ c := b <= a; Assert.IsTrue(c = False);
+ c := a <= a; Assert.IsTrue(c = True);
+ Assert.IsTrue( a <= 'abc');
+ // copy
+ c := a;
+ Assert.IsTrue( c = a);
+ Assert.IsTrue( VarIsSame(c, a) ); // checks if 2 variants share the same Python object.
+ // empty strings
+ a := VarPythonCreate('');
+ Assert.IsTrue(a.length = 0);
+ Assert.IsTrue(a = '');
+ Assert.IsTrue(string(a) = '');
+ // Unicode strings
+ b := VarPythonEval( 'u"Hello world!"' );
+ Assert.IsTrue( VarIsPythonUnicode(b) );
+ w := FPythonEngine.PyUnicodeAsString(ExtractPythonObjectFrom(b));
+ Assert.IsTrue( w = 'Hello world!');
+ Assert.IsTrue( b = 'Hello world!');
+ Assert.IsTrue( b <> a );
+ _obj := FPythonEngine.PyUnicodeFromString(w);
+ try
+ c := VarPythonCreate( _obj );
+ finally
+ FPythonEngine.Py_XDecRef(_obj);
+ end;
+ Assert.IsTrue(b = c);
+ Assert.IsTrue(c = w);
+ Assert.IsTrue( c = 'Hello world!');
+ w := b;
+ Assert.IsTrue( b = w);
+ Assert.IsTrue( w = 'Hello world!');
+ Assert.IsTrue( Length(w) = 12 );
+ Assert.IsTrue( Length(w) = b.Length() );
+ c := FPythonEngine.PyObjectAsVariant(ExtractPythonObjectFrom(b));
+ Assert.IsTrue( c = b );
+ Assert.IsTrue( c = w );
+ Assert.IsTrue( c = 'Hello world!');
+ Assert.IsTrue( VarType(c) and VarTypeMask = varUString );
+ c := VarPythonCreate(w);
+ Assert.IsTrue( c = 'Hello world!');
+ Assert.IsTrue( c = w );
+ c := VarPythonCreate([w]);
+ Assert.IsTrue( VarIsPythonUnicode(c.GetItem(0)) );
+ Assert.IsTrue( c.GetItem(0) = 'Hello world!');
+ Assert.IsTrue( c.GetItem(0) = w );
+ c := w;
+ b := VarPythonCreate(c);
+ Assert.IsTrue( VarIsPythonUnicode(b) );
+ Assert.IsTrue( b = c );
+ Assert.IsTrue( b = w );
+ // empty strings
+ a := VarPythonEval( 'u""' );
+ Assert.IsTrue(a.length = 0);
+ Assert.IsTrue(a = '');
+ Assert.IsTrue(string(a) = '');
+ Assert.IsTrue(WideString(a) = '');
+end;
+
+initialization
+ TDUnitX.RegisterTestFixture(TVarPythTest);
+
+end.
diff --git a/Tests/FMX/Android/WrapDelphiTest.pas b/Tests/FMX/Android/WrapDelphiTest.pas
new file mode 100644
index 00000000..453b6dda
--- /dev/null
+++ b/Tests/FMX/Android/WrapDelphiTest.pas
@@ -0,0 +1,534 @@
+(**************************************************************************)
+(* *)
+(* Module: Unit 'WrapDelphiTest' Copyright (c) 2021 *)
+(* *)
+(* Lucas Moura Belo - lmbelo *)
+(* lucas.belo@live.com *)
+(* BH, Brazil *)
+(* *)
+(* PyScripter *)
+(* e-mail: pyscripter@gmail.com *)
+(* *)
+(* Project pages: https://github.com/Embarcadero/python4delphi *)
+(* https://github.com/pyscripter/python4delphi *)
+(**************************************************************************)
+(* Functionality: Test unit for WrapDelphi module *)
+(* *)
+(* *)
+(**************************************************************************)
+(* This source code is distributed with no WARRANTY, for no reason or use.*)
+(* Everyone is allowed to use and change this code free for his own tasks *)
+(* and projects, as long as this header and its copyright text is intact. *)
+(* For changed versions of this code, which are public distributed the *)
+(* following additional conditions have to be fullfilled: *)
+(* 1) The header has to contain a comment on the change and the author of *)
+(* it. *)
+(* 2) A copy of the changed source has to be sent to the above E-Mail *)
+(* address or my then valid address, if this is possible to the *)
+(* author. *)
+(* The second condition has the target to maintain an up to date central *)
+(* version of the component. If this condition is not acceptable for *)
+(* confidential or legal reasons, everyone is free to derive a component *)
+(* or to generate a diff file to my or other original sources. *)
+(**************************************************************************)
+
+unit WrapDelphiTest;
+
+interface
+
+uses
+ Types,
+ DUnitX.TestFramework,
+ PythonEngine,
+ WrapDelphi;
+
+type
+ TFruit = (Apple, Banana, Orange);
+ TFruits = set of TFruit;
+
+ {$M+}
+ ITestInterface = interface(IInterface)
+ ['{AD50ADF2-2691-47CA-80AB-07AF1EDA8C89}']
+ procedure SetString(const S: string);
+ function GetString: string;
+ end;
+ {$M-}
+
+ TSubRecord = record
+ DoubleField: double;
+ end;
+
+ TTestRecord = record
+ StringField: string;
+ SubRecord: TSubRecord;
+ procedure SetStringField(S: string);
+ end;
+
+ TFruitDynArray = TArray;
+ TStaticArray = array[0..999] of Int64;
+ TTestRttiAccess = class
+ private
+ FFruit: TFruit;
+ FFruits: TFruits;
+ public
+ FruitField :TFruit;
+ FruitsField: TFruits;
+ StringField: string;
+ DoubleField: double;
+ ObjectField: TObject;
+ RecordField: TTestRecord;
+ InterfaceField: ITestInterface;
+ function GetData: TObject;
+ procedure BuyFruits(AFruits: TFruits);
+ procedure SellFruits(const AFruits: TFruitDynArray);
+ procedure SellFruitsInt(const AFruits:TIntegerDynArray);
+ function GetDynArray: TInt64DynArray;
+ function GetStaticArray: TStaticArray;
+ property Fruit: TFruit read FFruit write FFruit;
+ property Fruits: TFruits read FFruits write FFruits;
+ function SetStringField(var Value: Integer): string; overload;
+ function SetStringField(const Value: string): string; overload;
+ procedure PassVariantArray(const Value: Variant);
+ end;
+
+ TTestInterfaceImpl = class(TInterfacedObject, ITestInterface)
+ private
+ FString: string;
+ procedure SetString(const S: string);
+ function GetString: string;
+ end;
+
+ [TestFixture]
+ TTestWrapDelphi = class(TObject)
+ private
+ PythonEngine: TPythonEngine;
+ DelphiModule: TPythonModule;
+ PyDelphiWrapper: TPyDelphiWrapper;
+ Rtti_Var: Variant;
+ TestRttiAccess: TTestRttiAccess;
+ Rec: TTestRecord;
+ Rtti_Rec: Variant;
+ FTestInterface: ITestInterface;
+ Rtti_Interface: Variant;
+ public
+ [SetupFixture]
+ procedure SetupFixture;
+ [TearDownFixture]
+ procedure TearDownFixture;
+ [Test]
+ procedure TestEnumProperty;
+ [Test]
+ procedure TestSetProperty;
+ [Test]
+ procedure TestDoubleField;
+ [Test]
+ procedure TestEnumField;
+ [Test]
+ procedure TestSetField;
+ [Test]
+ procedure TestStringField;
+ [Test]
+ procedure TestSetProps;
+ [Test]
+ procedure TestObjectField;
+ [Test]
+ procedure TestMethodCall;
+ [Test]
+ procedure TestRecord;
+ [Test]
+ procedure TestRecordField;
+ [Test]
+ procedure TestInterface;
+ [Test]
+ procedure TestInterfaceField;
+ [Test]
+ procedure TestDynArrayParameters;
+ [Test]
+ procedure TestGetDynArray;
+ [Test]
+ procedure TestGetStaticArray;
+ [Test]
+ procedure TestMethodWithVarAndOverload;
+ [Test]
+ procedure TestFreeReturnedObject;
+ [Test]
+ procedure TestPassVariantArray;
+ end;
+
+implementation
+
+Uses
+ System.SysUtils,
+ System.Variants,
+ System.Classes,
+ System.Rtti,
+ VarPyth,
+ WrapDelphiClasses,
+ PythonLoad;
+
+
+{ TTestRTTIAccess }
+
+procedure TTestRttiAccess.BuyFruits(AFruits: TFruits);
+begin
+ Fruits := AFruits;
+end;
+
+{ TTestWrapDelphi }
+
+procedure TTestWrapDelphi.TestFreeReturnedObject;
+begin
+ PythonEngine.ExecString(
+ 'from delphi import rtti_var' + sLineBreak +
+ 'obj = rtti_var.GetData()' + sLineBreak +
+ 'obj.Free()'
+ );
+ Assert.Pass;
+end;
+
+procedure TTestWrapDelphi.SetupFixture;
+var
+ Py : PPyObject;
+begin
+ PythonEngine := TPythonEngine.Create(nil);
+ PythonEngine.Name := 'PythonEngine';
+ TPythonLoad.Configure(PythonEngine);
+
+ DelphiModule := TPythonModule.Create(nil);
+
+ DelphiModule.Name := 'DelphiModule';
+ DelphiModule.Engine := PythonEngine;
+ DelphiModule.ModuleName := 'delphi';
+
+ PyDelphiWrapper := TPyDelphiWrapper.Create(nil);
+
+ PyDelphiWrapper.Name := 'PyDelphiWrapper';
+ PyDelphiWrapper.Engine := PythonEngine;
+ PyDelphiWrapper.Module := DelphiModule;
+
+ PythonEngine.LoadDll;
+ // Then wrap the an instance our TTestRTTIAccess
+ // It will allow us to to test access to public fields and methods as well
+ // public (as well as published) properties.
+ // This time we would like the object to be destroyed when the PyObject
+ // is destroyed, so we need to set its Owned property to True;
+ TestRttiAccess := TTestRTTIAccess.Create;
+ TestRttiAccess.InterfaceField := TTestInterfaceImpl.Create;
+ Py := PyDelphiWrapper.Wrap(TestRttiAccess, TObjectOwnership.soReference);
+ DelphiModule.SetVar('rtti_var', Py);
+ PythonEngine.Py_DecRef(Py);
+ Py := PyDelphiWrapper.WrapRecord(@Rec, TRttiContext.Create.GetType(TypeInfo(TTestRecord)) as TRttiStructuredType);
+ DelphiModule.SetVar('rtti_rec', Py);
+ PythonEngine.Py_DecRef(Py);
+ FTestInterface := TTestInterfaceImpl.Create;
+ Py := PyDelphiWrapper.WrapInterface(TValue.From(FTestInterface));
+ DelphiModule.SetVar('rtti_interface', Py);
+ PythonEngine.Py_DecRef(Py);
+ PythonEngine.ExecString('from delphi import rtti_var, rtti_rec, rtti_interface');
+ Rtti_Var := MainModule.rtti_var;
+ Rtti_Rec := MainModule.rtti_rec;
+ Rtti_Interface := MainModule.rtti_interface;
+end;
+
+procedure TTestWrapDelphi.TearDownFixture;
+begin
+ VarClear(Rtti_Var);
+ VarClear(Rtti_Rec);
+ VarClear(Rtti_Interface);
+ PythonEngine.Free;
+ PyDelphiWrapper.Free;
+ DelphiModule.Free;
+ TestRttiAccess.Free;
+end;
+
+procedure TTestWrapDelphi.TestDoubleField;
+begin
+ TestRttiAccess.DoubleField := 3.14;
+ Assert.AreEqual(double(TestRttiAccess.DoubleField), double(3.14));
+ Rtti_Var.DoubleField := variant(double(1.23)); //implicitly cast to a variant to avoid a bug present in 10.4.2
+ Assert.AreEqual(double(Rtti_Var.DoubleField), double(1.23));
+end;
+
+procedure TTestWrapDelphi.TestEnumField;
+begin
+ TestRttiAccess.FruitField := Apple;
+ Assert.IsTrue(RTTI_var.FruitField = 'Apple');
+ Rtti_Var.FruitField := 'Banana';
+ Assert.IsTrue(TestRttiAccess.FruitField = Banana);
+end;
+
+procedure TTestWrapDelphi.TestEnumProperty;
+// Enumeration values are converted to/from strings
+begin
+ TestRttiAccess.Fruit := Apple;
+ Assert.IsTrue(RTTI_var.Fruit = 'Apple');
+ Rtti_Var.Fruit := 'Banana';
+ Assert.IsTrue(TestRttiAccess.Fruit = Banana);
+end;
+
+procedure TTestWrapDelphi.TestGetDynArray;
+var
+ List: Variant;
+begin
+ List := Rtti_Var.GetDynArray();
+ Assert.IsTrue(VarIsPythonList(List));
+ Assert.AreEqual(1000000, Integer(len(List)));
+ Assert.AreEqual(Int64(999999), Int64(PythonEngine.PyObjectAsVariant(PythonEngine.PyList_GetItem(ExtractPythonObjectFrom(List), 999999))));
+end;
+
+procedure TTestWrapDelphi.TestGetStaticArray;
+var
+ List: Variant;
+begin
+ List := Rtti_Var.GetStaticArray();
+ Assert.IsTrue(VarIsPythonList(List));
+ Assert.AreEqual(1000, Integer(len(List)));
+ Assert.AreEqual(Int64(999), Int64(PythonEngine.PyObjectAsVariant(PythonEngine.PyList_GetItem(ExtractPythonObjectFrom(List), 999))));
+end;
+
+procedure TTestWrapDelphi.TestInterface;
+begin
+ Rtti_Interface.SetString('Test');
+ Assert.IsTrue(Rtti_Interface.GetString() = 'Test');
+end;
+
+procedure TTestWrapDelphi.TestInterfaceField;
+begin
+ Rtti_Interface.SetString('New Value');
+ Assert.IsTrue(Rtti_Interface.GetString() = 'New Value');
+ Rtti_Var.InterfaceField.SetString('Old Value');
+ Assert.IsTrue(Rtti_Var.InterfaceField.GetString() = 'Old Value');
+ // Assign interface
+ Rtti_Var.InterfaceField := Rtti_Interface;
+ Assert.IsTrue(Rtti_Var.InterfaceField.GetString() = 'New Value');
+ Rtti_Var.InterfaceField := None;
+ Assert.IsTrue(VarIsNone(Rtti_Var.InterfaceField));
+end;
+
+procedure TTestWrapDelphi.TestMethodCall;
+begin
+ TestRttiAccess.Fruits := [];
+ Assert.AreEqual(string(Rtti_Var.Fruits), '[]');
+ Rtti_Var.BuyFruits(VarPythonCreate(['Apple', 'Banana'], stList));
+ Assert.AreEqual(string(Rtti_Var.Fruits), '[''Apple'', ''Banana'']');
+end;
+
+procedure TTestWrapDelphi.TestObjectField;
+{
+ Demonstrating and testing:
+ Subclassing Delphi components in Python
+ Creating Delphi objects in Python
+ Assigning objects to object fields
+}
+Var
+ Script: AnsiString;
+ myComp: Variant;
+begin
+ Script :=
+ 'from delphi import Component' + sLineBreak +
+ 'class MyComponent(Component):' + SLineBreak +
+ ' def __init__(self, Owner):' + SLineBreak +
+ ' self._x = None' + SLineBreak +
+ '' + SLineBreak +
+ ' @property' + SLineBreak +
+ ' def x(self):' + SLineBreak +
+ ' return self._x' + SLineBreak +
+ '' + SLineBreak +
+ ' @x.setter' + SLineBreak +
+ ' def x(self, value):' + SLineBreak +
+ ' self._x = value' + SLineBreak +
+ '' + SLineBreak +
+ 'myComp = MyComponent(None)';
+ ;
+
+ PythonEngine.ExecString(Script);
+ myComp := MainModule.myComp;
+ // accessing inherited property
+ Assert.IsTrue(myComp.Name = '');
+ myComp.Name := 'NoName';
+ Assert.IsTrue(myComp.Name = 'NoName');
+ // accessing subclass property
+ myComp.x := variant(double(3.14)); //implicitly cast to a variant to avoid a bug present in 10.4.2
+ Assert.IsTrue(myComp.x = 3.14);
+
+ // Setting an object field
+ rtti_var.ObjectField := myComp;
+ Assert.IsTrue(rtti_var.ObjectField.Name = 'NoName');
+ Assert.AreEqual(TComponent(TestRttiAccess.ObjectField).Name, 'NoName');
+ rtti_var.ObjectField := None;
+ Assert.IsTrue(rtti_var.ObjectField = None);
+end;
+
+procedure TTestWrapDelphi.TestPassVariantArray;
+begin
+ PythonEngine.ExecString(
+ 'from delphi import rtti_var' + sLineBreak +
+ 'rtti_var.PassVariantArray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])'
+ );
+ Assert.Pass;
+end;
+
+procedure TTestWrapDelphi.TestRecord;
+begin
+ Rtti_rec.StringField := 'abcd';
+ Assert.IsTrue(rtti_rec.StringField = 'abcd');
+ Rtti_rec.SetStringField('1234');
+ Assert.IsTrue(rtti_rec.StringField = '1234');
+ Assert.AreEqual(Rec.StringField, '1234');
+ Rtti_rec.SubRecord.DoubleField := variant(double(3.14)); //implicitly cast to a variant to avoid a bug present in 10.4.2
+ Assert.IsTrue(rtti_rec.SubRecord.DoubleField = 3.14);
+ Assert.AreEqual(Rec.SubRecord.DoubleField, 3.14);
+end;
+
+procedure TTestWrapDelphi.TestRecordField;
+Var
+ RecValue: Variant;
+begin
+ RecValue := rtti_var.RecordField;
+ RecValue.StringField := 'abc';
+ rtti_var.RecordField := RecValue;
+ Assert.IsTrue(rtti_var.RecordField.StringField = 'abc');
+end;
+
+procedure TTestWrapDelphi.TestSetField;
+// Sets are converted to/from list of strings
+begin
+ TestRttiAccess.FruitsField := [];
+ Assert.AreEqual(string(Rtti_Var.FruitsField), '[]');
+ Rtti_Var.FruitsField := VarPythonCreate(['Apple', 'Banana'], stList);
+ Assert.AreEqual(string(Rtti_Var.FruitsField), '[''Apple'', ''Banana'']');
+ Assert.IsTrue(TestRttiAccess.FruitsField = [Apple, Banana]);
+end;
+
+procedure TTestWrapDelphi.TestSetProperty;
+begin
+ TestRttiAccess.Fruits := [];
+ Assert.AreEqual(string(Rtti_Var.Fruits), '[]');
+ Rtti_Var.Fruits := VarPythonCreate(['Apple', 'Banana'], stList);
+ Assert.AreEqual(string(Rtti_Var.Fruits), '[''Apple'', ''Banana'']');
+ Assert.IsTrue(TestRttiAccess.Fruits = [Apple, Banana]);
+end;
+
+procedure TTestWrapDelphi.TestSetProps;
+begin
+ rtti_var.SetProps(StringField := 'abc', DoubleField := 1.234);
+ Assert.AreEqual(TestRttiAccess.StringField, 'abc');
+ Assert.AreEqual(TestRttiAccess.DoubleField, 1.234);
+end;
+
+procedure TTestWrapDelphi.TestStringField;
+begin
+ TestRttiAccess.StringField := 'Hi';
+ Assert.AreEqual(string(Rtti_Var.StringField), 'Hi');
+ Rtti_Var.StringField := 'P4D';
+ Assert.AreEqual(TestRttiAccess.StringField, 'P4D');
+end;
+
+procedure TTestWrapDelphi.TestDynArrayParameters;
+{var
+ rc: TRttiContext;
+ rt: TRttiType;
+ rm: TRttiMethod;
+ rp: TArray;
+ ra: TArray;}
+begin
+{ rc := TRttiContext.Create;
+ rt := rc.GetType(TypeInfo(TTestRttiAccess));
+ rm := rt.GetMethod('SellFruitsInt');
+ rp := rm.GetParameters;
+ SetLength(ra, 1);
+ ra[0] := TValue.FromArray(TypeInfo(TIntegerDynArray), [TValue.From(0)]);
+ rm.Invoke(TestRttiAccess, ra);}
+ TestRttiAccess.Fruits := [TFruit.Apple, TFruit.Banana, TFruit.Orange];
+ Rtti_Var.SellFruitsInt(VarPythonCreate([0, 1], stList));
+ Assert.IsTrue(TestRttiAccess.Fruits = [Orange]);
+ TestRttiAccess.Fruits := [TFruit.Apple, TFruit.Banana, TFruit.Orange];
+ Rtti_Var.SellFruits(VarPythonCreate([Ord(TFruit.Apple), Ord(TFruit.Banana)], stList));
+ Assert.IsTrue(TestRttiAccess.Fruits = [Orange]);
+end;
+
+procedure TTestWrapDelphi.TestMethodWithVarAndOverload;
+begin
+ Rtti_Var.SetStringField('test');
+ Assert.AreEqual('test', TestRttiAccess.StringField);
+end;
+
+function TTestRttiAccess.SetStringField(const Value: string): string;
+begin
+ StringField := Value;
+ Result := StringField;
+end;
+
+function TTestRttiAccess.SetStringField(var Value: Integer): string;
+begin
+ StringField := IntToStr(Value);
+ Result := StringField;
+end;
+
+function TTestRttiAccess.GetData: TObject;
+begin
+ Result := TStringList.Create;
+end;
+
+function TTestRttiAccess.GetDynArray: TInt64DynArray;
+var
+ I: Integer;
+begin
+ SetLength(Result, 1000000);
+ for I := 0 to Length(Result) - 1 do
+ Result[I] := I;
+end;
+
+function TTestRttiAccess.GetStaticArray: TStaticArray;
+var
+ I: Integer;
+begin
+ for I := 0 to Length(Result) - 1 do
+ Result[I] := I;
+end;
+
+procedure TTestRttiAccess.PassVariantArray(const Value: Variant);
+begin
+ Assert.IsTrue(VarIsArray(Value) and (VarArrayHighBound(Value, 1) = 9));
+end;
+
+procedure TTestRttiAccess.SellFruits(const AFruits: TFruitDynArray);
+var
+ Fruit: TFruit;
+begin
+ for Fruit in AFruits do
+ Exclude(FFruits, Fruit);
+end;
+
+procedure TTestRttiAccess.SellFruitsInt(const AFruits:TIntegerDynArray);
+var
+ Fruit: Integer;
+begin
+ for Fruit in AFruits do
+ Exclude(FFruits, TFruit(Fruit));
+end;
+
+{ TTestRecord }
+
+procedure TTestRecord.SetStringField(S: string);
+begin
+ Self.StringField := S;
+end;
+
+{ TTestInterfaceImpl }
+
+function TTestInterfaceImpl.GetString: string;
+begin
+ Result := FString;
+end;
+
+procedure TTestInterfaceImpl.SetString(const S: string);
+begin
+ FString := S;
+end;
+
+initialization
+ TDUnitX.RegisterTestFixture(TTestWrapDelphi);
+ ReportMemoryLeaksOnShutdown := True;
+
+end.