-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathxidehelpunit.pas
107 lines (80 loc) · 116 KB
/
xidehelpunit.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
(*
Copyright (c) 2020 Steve Wright
This unit is part of the XIDE project.
This project is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************
*)
unit XIDEHelpUnit;
{$ifndef JScript}
{$mode objfpc}{$H+}
{$endif}
interface
uses
Classes, SysUtils, StringUtils, NodeUtils, XForm,
{$ifndef JScript}
Forms, Controls, Dialogs,LazsUtils, Events, {framView,}
{$else}
HTMLUtils,
{$endif}
WrapperPanel, XVBox, XHBox, XMemo, XButton,
XLabel, XEditBox, XHTMLText, XScrollBox, XHTMLEditor;
type
{ TXIDEHelpForm }
TXIDEHelpForm = class(TXForm)
HelpFormVBox1: TXVBox;
HelpHTMLText: TXHTMLText;
{$ifndef JScript}
procedure FormActivate(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormResize(Sender: TObject);
procedure FormShow(Sender: TObject);
// procedure LoadNewText(Data: PtrInt);
{$endif}
private
public
procedure InitialiseonShow;
end;
var
XIDEHelpForm: TXIDEHelpForm;
HelpFormRoot:TDataNode;
implementation
{$R *.lfm}
const BaseHtml =
//'<h1 style="text-align: center;"><u>XIDE Overview</u></h1><h2 style="text-align: center;"> (A simple "Browser-First" IDE for Pascal and Python)</h2><h2>Purpose</h2><p>XIDE is a combined Client Side Run Time Library and RAD IDE intended to allow Pascal and/or Python development in the browser with the minimum of installation overhead or learning curve while also being as platform independent as possible. It is targeted at Prototyping, Small Group Collaboration and Agile Line of Business projects on any platform that is supported by Chrome or Electron, or Lazarus (and the Chrome Embedded Framework). It is not intended for the development of general-purpose public facing web sites.</p><h2>Installation</h2><p>In the browser, XIDE for Chrome is a single page static HTML page with no dependencies. so installation is just a matter of loading that initial web page. All subsequent computation and data storage is done client side. This single page web app combines the currently selected user project, as well as the RTL and IDE Code so any user project can be deployed with the IDE disabled (for end users) or enabled (for collaborators) as required.</p><p>Python in XIDE is based on the Mozilla Pyodide project which brings a full data science stack to the browser, such as NumPy, Pandas and Matplotlib. </p><p>If using a snapshot of XIDE on the desktop (i.e. XIDE.exe), you need to install local copies of Free Pascal and Python following the relevant instructions on their web sites. Then using the XIDE.exe main menu "Settings" option set the path to the home directories for the fpc compiler. Alternatively to rebuild XIDE from source, see <a href="https://github.com/Steve--W/XIDE">https://github.com/Steve--W/XIDE.</a> </p><h2>Functionality</h2><p>XIDE is designed to bring the power of Free Pascal (Pas2JS) and the convenience of Rapid Application Development (RAD) to the browser. It is a "Browser First" approach which also delivers cross platform capability by replicating browser functionality on the desktop in native code. This allows the user to exploit the greater efficiency of compiled native code compared to interpreted browser environments as required. It also allows a single code base to support multiple different target environments for different user circumstances or different stages in a project. </p><p>The Python option in XIDE adds broader "Data Science" capabilities to the environment and allows the more interactive exploratory approach of Python to be exploited as required. See <a href="https://hacks.mozilla.org/2019/04/pyodide-bringing-the-scientific-python-stack-to-the-browser/">https://hacks.mozilla.org/2019/04/pyodide-bringing-the-scientific-python-stack-to-the-browser/</a></p><h2>Unified User Interface</h2><p>The browser supports a number of different standards as part of its user interface. These include HTML, CSS, SVG to cover page layout, style editing, and vector graphics respectively. Normally these all require their own conventions to be used when accessed directly from the browser and/or JavaScript. XIDE unifies the user''s access to these different browser capabilities using a standardised Object Inspector / Drag and Drop approach for them all. For HTML and SVG this should appear seamless to the user with all the SVG containers and components accessed in an identical manner to HTML so requiring no further explanation than provided below for basic screen layout and editing. </p><h2>CSS Functionality</h2><p>CSS functionality is provided by supporting a style design tree in addition to the Code and UI design trees described below. As with the UI design tree, Style resources (new design rules, targets, properties and rule types ) are dragged from a resources tree and dropped on the relevant node of the style tree. The style tree also supports logical grouping of targets using "AND" and "OR" nodes. This speeds up and simplifies the CSS syntax generation considerably compared to direct text entry.</p><p></p><h2>Designing a User Interface</h2><h3><b>Resource and Instance trees</b></h3><p>XIDE uses a very simple paradigm. Essentially, it consists of three elements.</p><p></p><ol><li> A resources tree, showing the available widgets (visual and non visual)</li><li> A system design tree and object property inspector/editor</li><li> A layout panel showing a WYSIWYG version of the current page design.</li></ol><p></p> <p>The UI is built by pasting nodes from the resource tree to the system design tree. Each node has object properties defined by a name/value pairs that can be edited using the object inspector or referenced and or updated by run time code. Events are also available on each widget so that Pascal code can be attached to them using the built in code editor and compiler. Python scripts can also be called from these event handlers.</p><h3><b>Available Widgets</b></h3><p>The widgets listed in the resource tree include both UI and non visual components (the latter can be added to the root node of the UI design tree). </p><h3><b>Responsive Design</b></h3><p>XIDE supports a simple Responsive Design layout paradigm which consists of a Main page, Tab controls and Popups to define the constituent pages in a UI design. Horizontal and Vertical layout boxes (together with associated alignment properties) are then nested within these pages to control the final layout of components on the page.</p><h3><b>Writing Application Code</b></h3><p>XIDE uses an event driven model where event handlers can be attached to pre-defined events triggered by objects in the user interface. These procedures can be inspected and/or edited by using the object inspector to navigate to the required UI object then pressing the ellipsis button to the right of the required event in its events tab. This creates an entry for that event handler under the "Event Handlers" node in the code design tree. So once a handler has been added it can then also be navigated to by selecting it in the code designer and pressing the edit button. </p><h3><b>Pascal Syntax</b></h3><p>The Pascal syntax recognised by XIDE is that used by the Pas2JS variant of Free Pascal. (<a href="http://wiki.freepascal.org/pas2js">http://wiki.freepascal.org/pas2js</a>). A detailed description of the supported syntax can be found here. (<a href="http://wiki.freepascal.org/pas2js#RTL">http://wiki.freepascal.org/pas2js#RTL</a>)</p><h3><b>Unit Structure</b></h3><p>In addition to the event handler nodes, shared code can be written by adding units directly to the code design tree as "Pascal Units" or "Python Scripts". </p><p>Functions and procedures in the code nodes can be amended or deleted by selecting the node on the code design tree and pressing the "Edit" button which will bring up the code editor screen as previously described for the event handler code. After a Pascal unit has been compiled for the first time in a session, all the procedures and functions declared in it are displayed as its child nodes in the code design tree. Selecting one of these nodes and pressing the edit button below will navigate directly to that function. Alternatively, selecting a node and pressing "Code Search" will list all references to that function or procedure allowing you to navigate directly to the most relevant reference.</p><h3><b>Python </b></h3><p>The Python syntax used is version 3.8. </p><p>Python does not have a unit structure like Pascal, however blocks of Python code can be added to the Code Designer tree in the same way as Pascal units. The difference is that these will be run when entering run mode. They are executed in the order they occur on the Code Designer tree and can contain initialisation, declarations and / or any other valid executable Python Code. </p><p>To execute Python code elsewhere, such as in an event handler, then simply invoke the "RunPython(<i>......</i>)" procedure with the relevant python function call (or code) as a string parameter,</p><p>A console output box is supplied so that Python errors and print statements can be viewed. On the desktop, the copy of Python being used is the version installed on the host machine, see the documentation for that system to review valid syntax, permissions etc. In the browser, the version of Python used is that supported by mozilla (see <a href="https://hacks.mozilla.org/2019/04/pyodide-bringing-the-scientific-python-stack-to-the-browser/">https://hacks.mozilla.org/2019/04/pyodide-bringing-the-scientific-python-stack-to-the-browser/</a>)</p><h3><b>Accessing user interface objects at run time</b></h3><p>XIDE is designed to be a cross platform rapid application development system. In order to do this it uses a text based system description tree (The System Design or Instance Tree) to reflect the state of a users program at all times. This is similar to the function of the Document Object Model (DOM) in standard web applications. All object properties for nodes on this tree can be accessed and updated using the supplied get and set calls (see below).</p> <h3><b>Types of API Calls</b></h3><p>In XIDE design mode the instance tree describing a users project can be inspected manually using the Object Inspector. This allows the user to select any node on the tree and inspect and/or modify its properties or event handlers as required. The XIDE API allows the same actions to be available programmatically. The functions available fall into the following types (and work in an identical manner in both Pascal and Python) viz:-</p><p></p><ul><li> Dialog boxes</li><li> Get and/or set a property value of a UI object</li><li> Save and load user selected data to the clipboard or local storage</li><li> Copy or delete a UI component or move it to a new parent.</li><li> Show or hide a popup form.</li><li> Show or hide a busy indicator.</li><li> get and set GPU parameters </li></ul><p></p><p>The detailed syntax for these function calls is appended below. Note that unless explicitly stated, all values are strings.</p><h3><b>Asynchronous Calls, Multi Threading and Initialization functions</b></h3><p>Many web calls issue requests that need to wait for a response from a web service, database or other remote service provider. Similarly, when starting another thread in parallel, the main thread will often need to wait for such child threads to return the results of their work before it can proceed. XIDE allows main event handlers to specify a "initalisation"function. This is a block of code which issues all such requests prior to running the main event code when they have all finished executing. See below for the detail syntax of the available calls.</p><p>Note however that all such asynchronous calls first parameter is "e" the event context (automatically declared and populated by XIDE, behind the scenes, for every XIDE event) from which they have been issued so they know where to return without requiring the user to enter complex boilerplate code.</p><h2><b>List of XIDE specific API procedure and function calls</b></h2> <p></p><h3>General Functions</h3><ul><li>procedure SetPropertyValue(nodeName,propName,newValue:String); <font color="#0000ff">set a component property (string value) </font></li><li>function GetPropertyValue(nodeName,propName:String); <font color="#0000ff"> returns a component property value (as string) </font></li><li>procedure SetPropertyValueIndexed(nodeName,propName:String;newValue:TStringArray; x,y:integer); <font color="#0000ff">set a portion of a component array property</font> </li><li>procedure CopyToClip(str:String); <font color="#0000ff"> copies the given string to the clipboard </font></li><li>function CopyFromClip(e:TEventStatus):String; <font color="#0000ff">CopyFromClip is an async function (required for browser use), so it must be coded in the ''Init'' section of an event handler. The result here is a blank string. The clipboard string is held in e.ReturnString, which can be picked up in the ''Main'' section of the event handler.</font></li><li>procedure ShowXForm(XFormID:String; modal:Boolean); <font color="#0000ff"> opens a TXForm. [note:''modal=false'' currently only effective on desktop] </font></li><li>procedure CloseXForm(XFormID:String); <font color="#0000ff"> closes a TXForm. </font></li><li>procedure DoEvent(EventType,NodeId,myValue:String); <font color="#0000ff"> executes the event handler defined for the given event type and component. </font></li><li>procedure MoveComponent(nodeId:string;NewParentId:string); <font color="#0000ff">re-parents the given UI component </font></li><li>procedure CopyComponent(nodeId,NewParentId,NewName:string); <font color="#0000ff">copies the given UI component and places the clone under the given parent </font></li><li>function DeleteComponent(nodeId:string;ShowNotFoundMsg:Boolean=true):Boolean; <font color="#0000ff"> deletes the given UI component. Returns false if not done. </font></li><li>function UserSystemAsString():String; <font color="#0000ff">Returns the string representation of the current user system (can be imported to XIDE via System>Load) </font></li><li>function LoadUserSystemString(SystemString:String); <font color="#0000ff">Imports a new user system to the XIDE framework (can only be done in ''Design'' mode) </font></li><li>procedure ShowBusy(e:TEventStatus); <font color="#0000ff">Shows the busy cursor ShowBusy is an async function (required for browser use), so it must be coded in the ''Init'' section of an event handler. </font></li><li>procedure HideBusy; <font color="#0000ff">Hides the busy cursor </font> </li><li>procedure ProcessMessages; <font color="#0000ff"> Functional in Desktop execution only. Executes a pascal Application.ProcessMessages statement. </font></li><li>procedure DebugStart; <font color="#0000ff">Functional in Browser execution only. Executes a Javascript ''debugger;'' statement - starts the native browser debug facility. </font></li><li>procedure RunPython(str:String); <font color="#0000ff"> Executes the given Python script </font></li><li>procedure PyodideLoadPackage(nm:String); <font color="#0000ff"> Functional in Browser execution only. Loads the requested Pyodide/python package, so that it will be available for import. </font></li><li>function PyodidePackageLoaded(nm:String):Boolean; <font color="#0000ff"> Functional in Browser execution only. Returns true if the named package has been loaded into the Pyodide environment. </font> </li></ul><div contenteditable="true"><ul></ul><h3>Messages and Dialogs</h3><ul><li>procedure ShowMessage(msg:String); <font color="#0000ff"> displays a popup alert </font></li><li>function Confirm(TextMessage:string):boolean; <font color="#0000ff">displays a confirmation alert; returns true/false </font></li><li>function Prompt(TextMessage,promptString:string):string; <font color="#0000ff">displays an input box; returns user-entered string </font></li><li>procedure ConsoleLog(txt:String); <font color="#0000ff">Writes a debug message to the console log </font></li></ul><ul></ul><h3>TXTable Functions</h3><ul><li>procedure LoadTableFromExcelCopy(TableName,CopiedString:String); <font color="#0000ff">Populate the given TXTable component with a string in Excel format (eg. as copied from a spreadsheet) </font></li><li>procedure LoadTableFromNumArray(TableName,NumArray:T2DNumArray); <font color="#0000ff">Populate the given TXTable component from a 2D numeric array </font></li><li>function GetTableDataArray(TableName:String;SkipHeader:Boolean):T2DStringArray; <font color="#0000ff"> Fetch the cells from the given TXTable component as a 2D string array </font></li><li>function Array2DToString(arr:T2DNumArray):String; <font color="#0000ff"> Convert numeric 2D array to string form eg. [[...],...,[...]] </font></li></ul><ul></ul><h3>TXGPUCanvas Functions</h3><ul><li>function GetGPUParamNumValue(GPUName,pName:String):TNumArray; <font color="#0000ff">For the given TXGPUCanvas component, returns the value of the named numeric parameter as an array </font></li><li>function GetGPUConstIntValue(GPUName,pName:String):integer; <font color="#0000ff"> For the given TXGPUCanvas component, returns the value of the named integer parameter </font></li><li>procedure SetGPUParamNumValue(GPUName,pName:String;pValue:TNumArray); <font color="#0000ff">For the given TXGPUCanvas component, sets the value of the named numeric parameter as a 1-D array </font></li><li>procedure SetGPUParam2DNumValue(GPUName,pName:String;pValue:T2DNumArray); <font color="#0000ff">For the given TXGPUCanvas component, sets the value of the named numeric parameter as a 2-D array </font></li><li>procedure SetGPUConstIntValue(GPUName,pName:String;pValue:integer); <font color="#0000ff">For the given TXGPUCanvas component, sets the value of the named integer parameter </font></li><li>function GetGPUPixelArray(GPUName:String):T3DNumArray; <font color="#0000ff"> Fetch the current Pixel array for the given TXGPUCanvas component </font></li><li>function GetGPUPixelArrayAsString(GPUName:String):String; <font color="#0000ff">Fetch the current Pixel array in string format for the given TXGPUCanvas component </font> </li><li>function GetGPUStageArray(GPUName:String):T3DNumArray; <font color="#0000ff"> Fetch the stage array (resulting from the non-graphical kernel stack) for the given </font>TXGPUCanvas component </li><li>function GetGPUStageArrayAsString(GPUName:String):String; <font color="#0000ff">Fetch the stage array in string format for the given TXGPUCanvas component </font></li></ul><ul></ul><ul></ul><ul></ul><ul></ul><ul></ul><ul></ul><ul></ul><ul></ul><h3> Python Only</h3><ul><li>function ShowPythonPlot(ImgName,fig)<font color="#0000ff"> In the given TXImage component, displays the contents of fig (a matplotlib figure) </font></li></ul><h2>Composite Components</h2><p>XIDE can be used to build reusable ''widgets'' by creating a system with a set of XIDE elements and associated events, and then encapsulating that system. The encapsulated system is saved to local storage, and will appear in the Resources tree as a Composite component, which can then be pasted into other systems the user is building.</p><h3>To Create a Composite Component</h3><p></p><ol><li>Clear the system.</li><li>Build your widget in the normal way (for example, a table, with a copy and a paste button, and click events coded).</li><li>Test the system.</li><li>In design mode, select System>Encapsulate on the main menu. Provide a name for the composite component (eg. "TableWithCopyPaste").</li><li>In the Resources Tree, under ''Composites'', your new widget should now be listed.</li></ol><p></p><h3>To Use a Composite Component</h3><p></p><ol><li>Build a new system in the normal way.</li><li>Select a composite component in the Resources Tree, and paste to the system in the normal way. </li></ol><p></p><p>The composite component will be listed in the Design Tree, but without its constituent components - only the enclosing element will be shown. The composite component has two non-editable properties to note:</p><p></p><ul><li> ''CompositeType'', which shows the name with which the composite was originally created.</li><li> ''SourceString'', which contains the definition of the sub-elements within the composite, for system use.</li></ul><p></p><h3>To Edit a Composite Component</h3><p></p><ol><li>Clear the system.</li><li>Select the composite resource in the Resource Tree, and press ''Load''. This will load the composite as a system in design mode.</li><li>When your update is completed, save the composite again using System>Encapsulate on the main menu.</li></ol><p></p><p>NOTE: This will not update any instantiated copies of your composite. To update instantiated copies, load the system(s) containing them, then delete and re-paste the composite.</p><h3>To Pass Data Into a Composite Component</h3><p>By default, events within a composite element have no view of the containing system, and so cannot obtain data from it. So while building a composite component, you can include a Composite Interface element (TXCompositeIntf in the Resources Tree, under Non-Visual components).</p><p></p><ol><li>Paste a composite interface element under the UIRootNode in the design tree. </li><li>In the object inspector Properties tab, press the ''Add'' button. This will create a new property for the interface. </li><li>On the popup screen, enter the property name.</li><li>Use the ''Type'' selector to specify whether the property is ''Input'' or ''Output''. Select ''Input''.</li><li>Enter some brief text to explain to a user of your composite what the purpose of this property is.</li><li>Press ''Done''.</li></ol><p></p><p>The new property is now listed in the properties list for the interface, and can be accessed from event code within the composite. Encapsulate the composite component, and then paste it into a test system. Note that the object inspector for the instantiated composite component has a tab page "Interface", in which your interface property is listed. An input property is editable here, or can be populated programmatically at run time.</p><h3>To Get Data Out of a Composite Component</h3><p>Events in the enclosing system have no view of the sub-elements within a composite, and so cannot obtain property values directly. For this purpose an ''output'' property is needed. As in the section above, while editing the composite component, add an interface property, and set its type to ''Output''. When your composite is pasted into a containing system, the output property is listed in the Interface tab, but cannot be edited there. It is the responsibility of events within the composite to set the property value. </p><h3>To add a callable Method to a Composite Component</h3><p>While editing your composite system in design mode, select your interface component (TXCompositeIntf) in the design tree.</p><p></p><ol><li>On the ''Events'' tab, press ''Add'' to create a new method.</li><li>On the popup screen, enter the name of the method, and its type (select ''Read-Only'').</li><li>Enter some brief text to explain to a user of your composite what the purpose of this method is.</li><li>Press ''Done''.</li></ol><p></p><p>The new method is now listed in the events list for the interface. Encapsulate the composite component, and then paste it into a test system. Note that the object inspector for the instantiated composite component has your method listed under ''Events'', but cannot be edited here. The enclosing system can execute the method using the ''DoEvent'' built-in.</p><h3>To add an editable Event Handler to a Composite Component</h3><p>While editing your composite system in design mode, select your interface component (TXCompositeIntf) in the design tree.</p><p></p><ol><li>On the ''Events'' tab, press ''Add'' to create a new method.</li><li>On the popup screen, enter the name of the method, and its type (select ''Editable'').</li><li>Enter some brief text to explain to a user of your composite what event within the composite will execute it.</li><li>Press ''Done''.</li></ol><p></p><p>The new event handler is now listed in the events list for the interface, but code cannot be added here. The composite system can execute the method using the ''DoEvent'' built-in, for example on closing a form, or on changing a data table. Encapsulate the composite component, and then paste it into a test system. Note that the object inspector for the instantiated composite component has your event handler listed under ''Events'', and can be edited here, so that the user of the composite component can create their own handler.</p><h2><b>Project Development and Deployment</b></h2><p>During the development phase of a project XIDE will usually be loaded in design mode where you can edit the user interface design and the code behind it. On startup on the desktop, the IDE re-loads the project you were last working on. On the browser, it can be set to revert to the original state every time the app is started or to reload from the previous session.</p><p>Existing projects can be loaded from a previously saved system in local storage, or from the clipboard. Clearing the current system will start a new project. At the end of the design phase, you will sometimes want to deploy the developed HTML app to end users without allowing access to the IDE. In this case, select the "System / Deploy" option from the main menu and this will generate a self contained HTML page implementing your application and the run time environment needed to execute it, but with the interactive IDE features disabled. You can now load this to a server of your choice, or email directly to your end user so they can run it from their file system. </p><p>Alternatively, if you wish to give them access to inspect and perhaps contribute to, or modify, the app, then distribute the blank XIDE app for their preferred platform and use the "System / Save" option to generate a project definition file that they can load into it using the "System / Load" option on the main menu. </p><h2><b>Debugging</b></h2><p>When testing Pascal code you have written using XIDE, the PAS2JS compiler error messages will flag any source code syntax problems. If you click on one of these error messages this will position the cursor at the relevant character position in the line of code in the XIDE code editor. Run time errors will sometimes be trapped by error handlers built in to XIDE and generate a helpful error message. If this is not sufficient to uniquely identify the cause of the problem then "ctrl shift J" in Chrome will bring up the built in developer console which will hopefully provide the additional information you need to track down the problem. Alternatively, a break point can be set in the code by inserting a "DebugStart;" instruction that will start the native browser debug facility at that point.</p><h2>Implementation, Extensibility and Licensing</h2><p>XIDE is implemented using the Pas2JS dialect of the Object Pascal programming language. This is because it is efficient, easy to learn, and is available on a wide range of processor architectures. </p><p>Sometimes, as projects go through their life cycle, new more specialist requirements emerge. At this point the XIDE framework can be extended using project or platform specific custom components developed in Lazarus. </p><p>XIDE is an open source project distributed using the same licence as Lazarus (GPL) Source code is available from GitHub see <a href="https://github.com/Steve--W/XIDE">here</a> for the IDE and <a href="https://github.com/Steve--W/XComponents">here</a> for the components used to build it. (see <font color="#0000ff">https://github.com/Steve--W/XIDE</font> and<font color="#0000ff"> https://github.com/Steve--W/XComponents</font> respectively)</p><h2>Development Roadmap</h2><p>I have developed XIDE to support my ongoing academic research projects. I have made the project open source in case it should prove useful to anyone else. In particular, I hope its browser first approach, low installation overhead and easy learning curve will help to introduce the joys of Free Pascal and Lazarus to a wider audience.<br></p><p>Those aspects of XIDE and XComponents that I use regularly are "tried and tested". Some aspects that are used less often may have more bugs, and there are many aspects where it would be great to add new or improved features but where I do not have the bandwidth to address at the moment. If anyone wants to help out with any improvement to XIDE then their contribution will be most welcome.</p><p>(Some topics that spring to mind, from a long list of potential improvements, are:- Broadening XIDE browser support beyond the Chrome compatible set, XIDE integration with Lazarus, improving the wrapper for GPUJS or adding a drag and drop utility for constructing MatPlotLib data visualisations to make these Python libraries easily accessible to the Pascal community. )</p><h2>Compatibility</h2><p>In desktop mode, XIDE is designed to run on platforms supported by Lazarus, and optionally, the Chromium Embedded Framework and Python (i.e. most desktop platforms). If CEF or Python is not available then XIDE can still run but will then not support their specialist features. Alternatively, Electron or Cordova and Crosswalk can be used to provide a hybrid implementation of XIDE. This gives full Web connectivity and CSS on a wide range of platforms but with a trade off in terms of size, speed and security.</p><p>In browser mode XIDE is targeting closed user groups (where the browser can be specified) so it is only tested on recent versions of Chrome but it may also work on other browsers which use a Chrome engine. (e.g. the latest version of Microsoft Edge) </p><p>Note that the Style Designer is only available on the Browser versions as it depends on CSS functionality.</p><h2>Motivation for including a GPU capability in XIDE</h2><p>XIDE provides a thin wrapper for GPUJS (See https://gpu.rocks/) which generates GPU code from JavaScript. This produces WebGL code as it is widely supported "out of the box" in most browsers and on most processor/GPU combinations. This minimises the installation and configuration needed in order to get GPU code running on a new system. As such it is a good way to start learning about the possibilities (and perhaps more importantly the limitations) of programming for a massively parallel platform. </p><p>One of the weaknesses of this approach is the frustrating inability to optimise code or diagnose bugs in the GPU kernels except by exhaustive trial and error. So for any serious GPU programming it is well worth investing the time in getting to grips with the (admittedly intimidating) learning curve needed to master tools like OpenCL or Cuda and the associated tool stacks. Having said that, for simple "embarrassingly parallel" examples, or where there is a need to build simple GPU code into more general purpose or widely shared apps, the GPUJS approach can be very helpful.</p><h2>The XIDE GPUJS Wrapper</h2><p>The Pascal code for the GPU is accessed as a property of a GPU Canvas component which has been dropped onto the User Interface layout screen and/or as a node on the Code designer tree. The Pascal GPU code editor follows the same edit/compile cycle as for user code in the rest of the system. The differences are that this is code for blocks of threads in parallel. The code describes a single instruction multiple data (SIMD) approach where all the threads run the same code with thread specific code referencing "this.thread.x" , "this.thread.y" and "this.thread.z" to reflect their position in the block of threads. Parameter names are declared using a Paramlist property of the GPU canvas component and their transfer and run time execution is controlled by system calls described below. (N.B. parameters need to be passed as arrays so even scalar parameters passed into the code need to be referenced as follows "myParam[0]" )<br></p><p>The Pascal GPU code can daisy chain kernels. (Set the TXGPUCanvas property NumKernels>0) For each kernel in the chain its return value must be set to "MyValue". The next kernel in the chain can then read all the thread return values from the previous kernel by reading from "MyArray".The initial "MyArray" passed to the first kernel in the chain is set as a property ("InitStageData") of the GPU canvas and can have any x,y,z sizes as chosen by the user. The final kernel is the graphics display kernel where you set the r,g,b values as usual. The calculated data input to the graphics display kernel can also be accessed using either the "GetGPUStageArray" or "GetGPUStageArrayAsString" instructions;</p><p>Maths functions available in the GPU code are as follows:-</p><p></p><ul><li>abs(a) sign(a) trunc(a) ceil(a) max(a,b) min(a,b)</li><li>sin(a) cos(a) arcsin(a) arccos(a) arctan(a,b)</li><li>sqrt(a) power(a,b) ln(a) log10(a) log2(a) </li></ul><h2>Limitations of coding for the GPU </h2><p>When coding in Pascal for the GPU, you should be aware that there are fundamental limitations on the constructs available. In particular:-</p><p></p><ul><li>All parameters passed into the GPU are real arrays (scalar parameters are real arrays of length one)<br></li><li>You can read from but not write to any of these array parameters</li><li>You cannot declare a local array</li><li>Each thread returns a single real value</li><li>You cannot communicate with any other thread (except by synchronising the results in a new kernel)</li><li>You cannot use a Boolean type (use 0 or 1 instead)</li><li>You cannot use "var" parameters in a function call</li><li>All function parameters must be a simple type</li><li>Nested function declarations do not follow normal (Pascal) scope rules</li><li>Loops are unrolled so you MUST SET the "<span style="font-family: Verdana, Arial, sans-serif; font-size: 12px; white-space: nowrap;">MaxIterations"</span> parameter at a high enough value to reflect your algorithm''s requirements</li><li>The number of threads in each kernel are given by the KernelXDims, KernelYDims and Kernel ZDims properties of the GPU Canvas and these MUST BE SET either manually or programatically before activating the GPU.</li><li>The GPU is a Single Instruction Multiple Data machine so branching in a thread does not jump over the code in the path not taken, it idles in order to allow other threads to execute the code in that path if need be. </li><li>Debugging on the GPU is "primitive" the only way to do it when running on the hardware is to write out intermediate results to the thread output value for selected threads which you dedicate to providing diagnostic output. </li></ul><p><br></p><p><br></p><p></p>';
//'<h1 style="text-align: center;"><u>XIDE Help</u></h1><h2 style="text-align: center;"> (A simple "Browser-First" IDE for Pascal and Python)</h2><h2>Contents</h2><p>Overview</p><p></p><ul><li><a href="#Purpose">Purpose</a></li><li><a href="#Installation">Installation</a></li><li><a href="#Functionality">Functionality</a></li><li><a href="#UnifiedUserInterface(HTML,CSS,SVG)">Unified User Interface (HTML,CSS,SVG)</a></li><li><a href="#TheStyleDesigner">The Style Designer</a></li><li><a href="#CompositeComponents">Composite Components</a></li><li><a href="#GPUCapability">GPU Capability</a></li><li><a href="#ProjectDevelopmentandDeployment">Project Development and Deployment</a></li><li><a href="#Debugging">Debugging</a></li><li><a href="#ImplementationExtensibilityandLicencing">Implementation, Extensibility and Licencing</a></li><li><a href="#DevelopmentRoadmap">Development Roadmap</a></li><li><a href="#Compatibility">Compatibility</a></li></ul><p></p><p></p><p>User Interface</p><ul><li><a href="#DesigningaUserinterface">Designing a Userinterface</a></li><li><a href="#ResourceandInstanceTrees">Resource and InstanceTrees</a></li><li><a href="#AvailableWidgets">Available Widgets</a></li><li><a href="#ResponsiveDesign">Responsive Design</a></li><li><a href="#WritingApplicationCode">Writing Application Code</a></li><li><a href="#PascalSyntax">Pascal Syntax</a></li><li><a href="#Python">Python</a></li></ul><p></p><p>Application Programming Interface</p><p></p><ul><li><a href="#AccessingUserinterfaceObjectsatRunTime">Accessing User interface Objects at Run Time</a></li><li><a href="#TypesofAPICalls">Types of API Calls</a></li><li><a href="#AsynchronousCallsMultithreadingandInitialisationfunctions">Asynchronous Calls,Multithreading and Initialisation functions</a></li><li><a href="#ListofXIDEspecificAPIprocedureandfunctioncalls">List of XIDE specific API procedure and function calls</a></li><li><a href="#Generalfunctions">General functions</a></li><li><a href="#MessagesandDialogs">Messages and Dialogs</a></li><li><a href="#TXTablefunctions">TXTable functions</a></li><li><a href="#TXGPUCanvasfunctions">TXGPU Canvas functions</a></li><li><a href="#PythonOnly">Python Only functions</a></li></ul><p></p><p>Encapsulation</p><ul><li><a href="#TocreateacompositeComponent">To create a composite Component</a></li><li><a href="#TouseacompositeComponent">To use a composite Component</a></li><li><a href="#ToeditacompositeComponent">To edit a composite Component</a></li><li><a href="#TopassdataintoacompositeComponent">To pass data in to a composite Component</a></li><li><a href="#TogetdataoutofacompositeComponent">To get data out of a composite Component</a></li><li><a href="#ToaddacallablemethodtoacompositeComponent">To add a callable method to a composite Component</a></li><li><a href="#ToaddaneditableeventhandlertoacompositeComponent">To add an editable event handler to a composite Component</a></li></ul><p>GPU <br></p><ul><li><a href="#TheXIDEGPUJSWrapper">The XIDE GPUJS Wrapper</a></li><li><a href="#MathsfunctionsavailableintheGPU">Maths functions available in the GPU</a></li><li><a href="#LimitationsofcodingfortheGPU">Limitations of coding for the GPU</a></li></ul><p></p><p></p><p> </p><p></p><hr id="null"><h2><p></p></h2><h2><p><a id="Purpose">Purpose</a><br></p></h2><p>XIDE is a combined Client Side Run Time Library and RAD IDE intended to allow Pascal and/or Python development in the browser with the minimum of installation overhead or learning curve while also being as platform independent as possible. It is targeted at Prototyping, Small Group Collaboration and Agile Line of Business projects on any platform that is supported by Chrome or Electron, or Lazarus (and the Chrome Embedded Framework). It is not intended for the development of general-purpose public facing web sites.</p><h2><a id="Installation">Installation</a><br></h2><p>In the browser, XIDE for Chrome is a single page static HTML page with no dependencies. so installation is just a matter of loading that initial web page. All subsequent computation and data storage is done client side. This single page web app combines the currently selected user project, as well as the RTL and IDE Code so any user project can be deployed with the IDE disabled (for end users) or enabled (for collaborators) as required.</p><p>Python in XIDE is based on the Mozilla Pyodide project which brings a full data science stack to the browser, such as NumPy, Pandas and Matplotlib. </p><p>If using a snapshot of XIDE on the desktop (i.e. XIDE.exe), you need to install local copies of Free Pascal and Python following the relevant instructions on their web sites. Then using the XIDE.exe main menu "Settings" option set the path to the home directories for the fpc compiler. Alternatively to rebuild XIDE from source, see <a href="https://github.com/Steve--W/XIDE">https://github.com/Steve--W/XIDE.</a> </p><h2><a id="Functionality">Functionality</a><br></h2><p>XIDE is designed to bring the power of Free Pascal (Pas2JS) and the convenience of Rapid Application Development (RAD) to the browser. It is a "Browser First" approach which also delivers cross platform capability by replicating browser functionality on the desktop in native code. This allows the user to exploit the greater efficiency of compiled native code compared to interpreted browser environments as required. It also allows a single code base to support multiple different target environments for different user circumstances or different stages in a project. </p><p>The Python option in XIDE adds broader "Data Science" capabilities to the environment and allows the more interactive exploratory approach of Python to be exploited as required. See <a href="https://hacks.mozilla.org/2019/04/pyodide-bringing-the-scientific-python-stack-to-the-browser/">https://hacks.mozilla.org/2019/04/pyodide-bringing-the-scientific-python-stack-to-the-browser/</a></p><h2><a id="UnifiedUserInterface(HTML,CSS,SVG)">Unified User Interface (HTML,CSS,SVG)</a><br></h2><p>The browser supports a number of different standards as part of its user interface. These include HTML, CSS, SVG to cover page layout, style editing, and vector graphics respectively. Normally these all require their own conventions to be used when accessed directly from the browser and/or JavaScript. XIDE unifies the user''s access to these different browser capabilities using a standardised Object Inspector / Drag and Drop approach for them all. For HTML and SVG this should appear seamless to the user with all the SVG containers and components accessed in an identical manner to HTML so requiring no further explanation than provided below for basic screen layout and editing. </p><h2><a id="TheStyleDesigner">The Style Designer</a><br></h2><p>CSS functionality is provided by supporting a style design tree in addition to the Code and UI design trees described below. As with the UI design tree, Style resources (new design rules, targets, properties and rule types ) are dragged from a resources tree and dropped on the relevant node of the style tree. The style tree also supports logical grouping of targets using "AND" and "OR" nodes. This speeds up and simplifies the CSS syntax generation considerably compared to direct text entry.</p><h2><a id="CompositeComponents">Composite Components</a><br></h2><p>XIDE can be used to build reusable "widgets" by creating a system with a set of XIDE elements and associated events, and then encapsulating that system. The encapsulated system is saved to local storage, and will appear in the Resources tree as a Composite component, which can then be pasted into other systems the user is building.</p><h2><a id="GPUCapability">GPU Capability</a><br></h2><p>XIDE provides a thin wrapper for GPUJS (See https://gpu.rocks/) which generates GPU code from JavaScript. This produces WebGL code as it is widely supported "out of the box" in most browsers and on most processor/GPU combinations. This minimises the installation and configuration needed in order to get GPU code running on a new system. As such it is a good way to start learning about the possibilities (and perhaps more importantly the limitations) of programming for a massively parallel platform. </p><p>One of the weaknesses of this approach is the frustrating inability to optimise code or diagnose bugs in the GPU kernels except by exhaustive trial and error. So for any serious GPU programming it is well worth investing the time in getting to grips with the (admittedly intimidating) learning curve needed to master tools like OpenCL or Cuda and the associated tool stacks. Having said that, for simple "embarrassingly parallel" examples, or where there is a need to build simple GPU code into more general purpose or widely shared apps, the GPUJS approach can be very helpful.</p><h2><a id="ProjectDevelopmentandDeployment">Project Development and Deployment</a><br></h2><p>During the development phase of a project XIDE will usually be loaded in design mode where you can edit the user interface design and the code behind it. On startup on the desktop, the IDE re-loads the project you were last working on. On the browser, it can be set to revert to the original state every time the app is started or to reload from the previous session.</p><p>Existing projects can be loaded from a previously saved system in local storage, or from the clipboard. Clearing the current system will start a new project. At the end of the design phase, you will sometimes want to deploy the developed HTML app to end users without allowing access to the IDE. In this case, select the "System / Deploy" option from the main menu and this will generate a self contained HTML page implementing your application and the run time environment needed to execute it, but with the interactive IDE features disabled. You can now load this to a server of your choice, or email directly to your end user so they can run it from their file system. </p><p>Alternatively, if you wish to give them access to inspect and perhaps contribute to, or modify, the app, then distribute the blank XIDE app for their preferred platform and use the "System / Save" option to generate a project definition file that they can load into it using the "System / Load" option on the main menu. </p><h2><a id="Debugging">Debugging</a><br></h2><p>When testing Pascal code you have written using XIDE, the PAS2JS compiler error messages will flag any source code syntax problems. If you click on one of these error messages this will position the cursor at the relevant character position in the line of code in the XIDE code editor. Run time errors will sometimes be trapped by error handlers built in to XIDE and generate a helpful error message. If this is not sufficient to uniquely identify the cause of the problem then "ctrl shift J" in Chrome will bring up the built in developer console which will hopefully provide the additional information you need to track down the problem. Alternatively, a break point can be set in the code by inserting a "DebugStart;" instruction that will start the native browser debug facility at that point.</p><h2><a id="ImplementationExtensibilityandLicencing">Implementation, Extensibility and Licensing</a><br></h2><p>XIDE is implemented using the Pas2JS dialect of the Object Pascal programming language. This is because it is efficient, easy to learn, and is available on a wide range of processor architectures. </p><p>Sometimes, as projects go through their life cycle, new more specialist requirements emerge. At this point the XIDE framework can be extended using project or platform specific custom components developed in Lazarus. </p><p>XIDE is an open source project distributed using the same licence as Lazarus (GPL) Source code is available from GitHub see <a href="https://github.com/Steve--W/XIDE">here</a> for the IDE and <a href="https://github.com/Steve--W/XComponents">here</a> for the components used to build it. (see <font color="#0000ff">https://github.com/Steve--W/XIDE</font> and<font color="#0000ff"> https://github.com/Steve--W/XComponents</font> respectively)</p><h2><a id="DevelopmentRoadmap">Development Roadmap</a><br></h2><p>I have developed XIDE to support my ongoing academic research projects. I have made the project open source in case it should prove useful to anyone else. In particular, I hope its browser first approach, low installation overhead and easy learning curve will help to introduce the joys of Free Pascal and Lazarus to a wider audience.<br></p><p>Those aspects of XIDE and XComponents that I use regularly are "tried and tested". Some aspects that are used less often may have more bugs, and there are many aspects where it would be great to add new or improved features but where I do not have the bandwidth to address at the moment. If anyone wants to help out with any improvement to XIDE then their contribution will be most welcome.</p><p>(Some topics that spring to mind, from a long list of potential improvements, are:- Broadening XIDE browser support beyond the Chrome compatible set, XIDE integration with Lazarus, improving the wrapper for GPUJS or adding a drag and drop utility for constructing MatPlotLib data visualisations to make these Python libraries easily accessible to the Pascal community. )</p><h2><a id="Compatibility">Compatibility</a><br></h2><p>In desktop mode, XIDE is designed to run on platforms supported by Lazarus, and optionally, the Chromium Embedded Framework and Python (i.e. most desktop platforms). If CEF or Python is not available then XIDE can still run but will then not support their specialist features. Alternatively, Electron or Cordova and Crosswalk can be used to provide a hybrid implementation of XIDE. This gives full Web connectivity and CSS on a wide range of platforms but with a trade off in terms of size, speed and security.</p><p>In browser mode XIDE is targeting closed user groups (where the browser can be specified) so it is only tested on recent versions of Chrome but it may also work on other browsers which use a Chrome engine. (e.g. the latest version of Microsoft Edge) </p><p>Note that TheStyleDesigner is only available on the Browser versions as it depends on CSS functionality.</p><p><br></p><hr id="null"><p></p><h2><a id="DesigningaUserinterface">Designing a User interface</a><br></h2><h3><a id="ResourceandInstanceTrees">Resource and Instance Trees</a><br></h3><p>XIDE uses a very simple paradigm. Essentially, it consists of three elements.</p><p></p><ol><li> A resources tree, showing the AvailableWidgets (visual and non visual)</li><li> A system design tree and object property inspector/editor</li><li> A layout panel showing a WYSIWYG version of the current page design.</li></ol><p></p> <p>The UI is built by pasting nodes from the resource tree to the system design tree. Each node has object properties defined by a name/value pairs that can be edited using the object inspector or referenced and or updated by run time code. Events are also available on each widget so that Pascal code can be attached to them using the built in code editor and compiler. Python scripts can also be called from these event handlers.</p><h3><a id="AvailableWidgets">Available Widgets</a><br></h3><p>The widgets listed in the resource tree include both UI and non visual components (the latter can be added to the root node of the UI design tree). </p><h3><a id="ResponsiveDesign">Responsive Design</a><br></h3><p>XIDE supports a simple ResponsiveDesign layout paradigm which consists of a Main page, Tab controls and Popups to define the constituent pages in a UI design. Horizontal and Vertical layout boxes (together with associated alignment properties) are then nested within these pages to control the final layout of components on the page.</p><h3><a id="WritingApplicationCode">Writing Application Code</a><br></h3><p>XIDE uses an event driven model where event handlers can be attached to pre-defined events triggered by objects in the user interface. These procedures can be inspected and/or edited by using the object inspector to navigate to the required UI object then pressing the ellipsis button to the right of the required event in its events tab. This creates an entry for that event handler under the "Event Handlers" node in the code design tree. So once a handler has been added it can then also be navigated to by selecting it in the code designer and pressing the edit button. </p><h3><a id="PascalSyntax">Pascal Syntax</a><br></h3><p>The PascalSyntax recognised by XIDE is that used by the Pas2JS variant of Free Pascal. (<a href="http://wiki.freepascal.org/pas2js">http://wiki.freepascal.org/pas2js</a>). A detailed description of the supported syntax can be found here. (<a href="http://wiki.freepascal.org/pas2js#RTL">http://wiki.freepascal.org/pas2js#RTL</a>)</p><h3><a id="UnitStructure">Unit Structure</a><br></h3><p>In addition to the event handler nodes, shared code can be written by adding units directly to the code design tree as "Pascal Units" or "Python Scripts". </p><p>Functions and procedures in the code nodes can be amended or deleted by selecting the node on the code design tree and pressing the "Edit" button which will bring up the code editor screen as previously described for the event handler code. After a Pascal unit has been compiled for the first time in a session, all the procedures and functions declared in it are displayed as its child nodes in the code design tree. Selecting one of these nodes and pressing the edit button below will navigate directly to that function. Alternatively, selecting a node and pressing "Code Search" will list all references to that function or procedure allowing you to navigate directly to the most relevant reference.</p><h3><a id="Python">Python</a><br></h3><p>The Python syntax used is version 3.8. </p><p>Python does not have a unit structure like Pascal, however blocks of Python code can be added to the Code Designer tree in the same way as Pascal units. The difference is that these will be run when entering run mode. They are executed in the order they occur on the Code Designer tree and can contain initialisation, declarations and / or any other valid executable Python Code. </p><p>To execute Python code elsewhere, such as in an event handler, then simply invoke the "RunPython(<i>......</i>)" procedure with the relevant python function call (or code) as a string parameter,</p><p>A console output box is supplied so that Python errors and print statements can be viewed. On the desktop, the copy of Python being used is the version installed on the host machine, see the documentation for that system to review valid syntax, permissions etc. In the browser, the version of Python used is that supported by mozilla (see <a href="https://hacks.mozilla.org/2019/04/pyodide-bringing-the-scientific-python-stack-to-the-browser/">https://hacks.mozilla.org/2019/04/pyodide-bringing-the-scientific-python-stack-to-the-browser/</a>)</p><p><br></p><hr id="null"><h3><a id="AccessingUserinterfaceObjectsatRunTime">Accessing User interface Objects at Run Time</a><br></h3><p>XIDE is designed to be a cross platform rapid application development system. In order to do this it uses a text based system description tree (The System Design or Instance Tree) to reflect the state of a users program at all times. This is similar to the function of the Document Object Model (DOM) in standard web applications. All object properties for nodes on this tree can be accessed and updated using the supplied get and set calls (see below).</p> <h3><a id="TypesofAPICalls">Types of API Calls</a><br></h3><p>In XIDE design mode the instance tree describing a users project can be inspected manually using the Object Inspector. This allows the user to select any node on the tree and inspect and/or modify its properties or event handlers as required. The XIDE API allows the same actions to be available programmatically. The functions available fall into the following types (and work in an identical manner in both Pascal and Python) viz:-</p><p></p><ul><li> Dialog boxes</li><li> Get and/or set a property value of a UI object</li><li> Save and load user selected data to the clipboard or local storage</li><li> Copy or delete a UI component or move it to a new parent.</li><li> Show or hide a popup form.</li><li> Show or hide a busy indicator.</li><li> get and set GPU parameters </li></ul><p></p><p>The detailed syntax for these function calls is appended below. Note that unless explicitly stated, all values are strings.</p><h3><a id="AsynchronousCallsMultiThreadingandInitializationfunctions">Asynchronous Calls, Multi Threading and Initialization functions</a><br></h3><p>Many web calls issue requests that need to wait for a response from a web service, database or other remote service provider. Similarly, when starting another thread in parallel, the main thread will often need to wait for such child threads to return the results of their work before it can proceed. XIDE allows main event handlers to specify a "initalisation"function. This is a block of code which issues all such requests prior to running the main event code when they have all finished executing. See below for the detail syntax of the available calls.</p><p>Note however that all such asynchronous calls first parameter is "e" the event context (automatically declared and populated by XIDE, behind the scenes, for every XIDE event) from which they have been issued so they know where to return without requiring the user to enter complex boilerplate code.</p><h2><a id="ListofXIDEspecificAPIprocedureandfunctioncalls">List of XIDE specific API procedure and function calls</a><br></h2> <p></p><h3><a id="Generalfunctions">General functions</a><br></h3><ul><li>procedure SetPropertyValue(nodeName,propName,newValue:String); <font color="#0000ff">set a component property (string value) </font></li><li>function GetPropertyValue(nodeName,propName:String); <font color="#0000ff"> returns a component property value (as string) </font></li><li>procedure SetPropertyValueIndexed(nodeName,propName:String;newValue:TStringArray; x,y:integer); <font color="#0000ff">set a portion of a component array property</font> </li><li>procedure CopyToClip(str:String); <font color="#0000ff"> copies the given string to the clipboard </font></li><li>function CopyFromClip(e:TEventStatus):String; <font color="#0000ff">CopyFromClip is an async function (required for browser use), so it must be coded in the "Init" section of an event handler. The result here is a blank string. The clipboard string is held in e.ReturnString, which can be picked up in the "Main" section of the event handler.</font></li><li>procedure ShowXForm(XFormID:String; modal:Boolean); <font color="#0000ff"> opens a TXForm. [note:"modal=false" currently only effective on desktop] </font></li><li>procedure CloseXForm(XFormID:String); <font color="#0000ff"> closes a TXForm. </font></li><li>procedure DoEvent(EventType,NodeId,myValue:String); <font color="#0000ff"> executes the event handler defined for the given event type and component. </font></li><li>procedure MoveComponent(nodeId:string;NewParentId:string); <font color="#0000ff">re-parents the given UI component </font></li><li>procedure CopyComponent(nodeId,NewParentId,NewName:string); <font color="#0000ff">copies the given UI component and places the clone under the given parent </font></li><li>function DeleteComponent(nodeId:string;ShowNotFoundMsg:Boolean=true):Boolean; <font color="#0000ff"> deletes the given UI component. Returns false if not done. </font></li><li>function UserSystemAsString():String; <font color="#0000ff">Returns the string representation of the current user system (can be imported to XIDE via System>Load) </font></li><li>function LoadUserSystemString(SystemString:String); <font color="#0000ff">Imports a new user system to the XIDE framework (can only be done in "Design" mode) </font></li><li>procedure ShowBusy(e:TEventStatus); <font color="#0000ff">Shows the busy cursor ShowBusy is an async function (required for browser use), so it must be coded in the "Init" section of an event handler. </font></li><li>procedure HideBusy; <font color="#0000ff">Hides the busy cursor </font> </li><li>procedure ProcessMessages; <font color="#0000ff"> Functional in Desktop execution only. Executes a pascal Application.ProcessMessages statement. </font></li><li>procedure DebugStart; <font color="#0000ff">Functional in Browser execution only. Executes a Javascript "debugger;" statement - starts the native browser debug facility. </font></li><li>procedure RunPython(str:String); <font color="#0000ff"> Executes the given Python script </font></li><li>procedure PyodideLoadPackage(nm:String); <font color="#0000ff"> Functional in Browser execution only. Loads the requested Pyodide/python package, so that it will be available for import. </font></li><li>function PyodidePackageLoaded(nm:String):Boolean; <font color="#0000ff"> Functional in Browser execution only. Returns true if the named package has been loaded into the Pyodide environment. </font> </li></ul><div contenteditable="true"><ul></ul><h3><a id="MessagesandDialogs">Messages and Dialogs</a><br></h3><ul><li>procedure ShowMessage(msg:String); <font color="#0000ff"> displays a popup alert </font></li><li>function Confirm(TextMessage:string):boolean; <font color="#0000ff">displays a confirmation alert; returns true/false </font></li><li>function Prompt(TextMessage,promptString:string):string; <font color="#0000ff">displays an input box; returns user-entered string </font></li><li>procedure ConsoleLog(txt:String); <font color="#0000ff">Writes a debug message to the console log </font></li></ul><ul></ul><h3><a id="TXTablefunctions">TXTable functions</a><br></h3><ul><li>procedure LoadTableFromExcelCopy(TableName,CopiedString:String); <font color="#0000ff">Populate the given TXTable component with a string in Excel format (eg. as copied from a spreadsheet) </font></li><li>procedure LoadTableFromNumArray(TableName,NumArray:T2DNumArray); <font color="#0000ff">Populate the given TXTable component from a 2D numeric array </font></li><li>function GetTableDataArray(TableName:String;SkipHeader:Boolean):T2DStringArray; <font color="#0000ff"> Fetch the cells from the given TXTable component as a 2D string array </font></li><li>function Array2DToString(arr:T2DNumArray):String; <font color="#0000ff"> Convert numeric 2D array to string form eg. [[...],...,[...]] </font></li></ul><ul></ul><h3><a id="TXGPUCanvasfunctions">TXGPU Canvas functions</a><br></h3><ul><li>function GetGPUParamNumValue(GPUName,pName:String):TNumArray; <font color="#0000ff">For the given TXGPUCanvas component, returns the value of the named numeric parameter as an array </font></li><li>function GetGPUConstIntValue(GPUName,pName:String):integer; <font color="#0000ff"> For the given TXGPUCanvas component, returns the value of the named integer parameter </font></li><li>procedure SetGPUParamNumValue(GPUName,pName:String;pValue:TNumArray); <font color="#0000ff">For the given TXGPUCanvas component, sets the value of the named numeric parameter as a 1-D array </font></li><li>procedure SetGPUParam2DNumValue(GPUName,pName:String;pValue:T2DNumArray); <font color="#0000ff">For the given TXGPUCanvas component, sets the value of the named numeric parameter as a 2-D array </font></li><li>procedure SetGPUConstIntValue(GPUName,pName:String;pValue:integer); <font color="#0000ff">For the given TXGPUCanvas component, sets the value of the named integer parameter </font></li><li>function GetGPUPixelArray(GPUName:String):T3DNumArray; <font color="#0000ff"> Fetch the current Pixel array for the given TXGPUCanvas component </font></li><li>function GetGPUPixelArrayAsString(GPUName:String):String; <font color="#0000ff">Fetch the current Pixel array in string format for the given TXGPUCanvas component </font> </li><li>function GetGPUStageArray(GPUName:String):T3DNumArray; <font color="#0000ff"> Fetch the stage array (resulting from the non-graphical kernel stack) for the given </font>TXGPUCanvas component </li><li>function GetGPUStageArrayAsString(GPUName:String):String; <font color="#0000ff">Fetch the stage array in string format for the given TXGPUCanvas component </font></li></ul><ul></ul><ul></ul><ul></ul><ul></ul><ul></ul><ul></ul><ul></ul><ul></ul><h3><a id="PythonOnly">Python Only</a><br></h3><ul><li>function ShowPythonPlot(ImgName,fig)<font color="#0000ff"> In the given TXImage component, displays the contents of fig (a matplotlib figure) </font></li></ul><hr id="null"><h2><a id="TocreateacompositeComponent">To create a composite Component</a><br></h2><p></p><ol><li>Clear the system.</li><li>Build your widget in the normal way (for example, a table, with a copy and a paste button, and click events coded).</li><li>Test the system.</li><li>In design mode, select System>Encapsulate on the main menu. Provide a name for the composite component (eg. "TableWithCopyPaste").</li><li>In the Resources Tree, under "Composites", your new widget should now be listed.</li></ol><p></p><h3><a id="TouseacompositeComponent">To use a composite Component</a><br></h3><p></p><ol><li>Build a new system in the normal way.</li><li>Select a composite component in the Resources Tree, and paste to the system in the normal way. </li></ol><p></p><p>The composite component will be listed in the Design Tree, but without its constituent components - only the enclosing element will be shown. The composite component has two non-editable properties to note:</p><p></p><ul><li> "CompositeType", which shows the name with which the composite was originally created.</li><li> "SourceString", which contains the definition of the sub-elements within the composite, for system use.</li></ul><p></p><h3><a id="ToeditacompositeComponent">To edit a composite Component</a><br></h3><p></p><ol><li>Clear the system.</li><li>Select the composite resource in the Resource Tree, and press "Load". This will load the composite as a system in design mode.</li><li>When your update is completed, save the composite again using System>Encapsulate on the main menu.</li></ol><p></p><p>NOTE: This will not update any instantiated copies of your composite. To update instantiated copies, load the system(s) containing them, then delete and re-paste the composite.</p><h3><a id="TopassdataintoacompositeComponent">To pass data into a composite Component</a><br></h3><p>By default, events within a composite element have no view of the containing system, and so cannot obtain data from it. So while building a composite component, you can include a Composite Interface element (TXCompositeIntf in the Resources Tree, under Non-Visual components).</p><p></p><ol><li>Paste a composite interface element under the UIRootNode in the design tree. </li><li>In the object inspector Properties tab, press the "Add" button. This will create a new property for the interface. </li><li>On the popup screen, enter the property name.</li><li>Use the "Type" selector to specify whether the property is "Input" or "Output". Select "Input".</li><li>Enter some brief text to explain to a user of your composite what the purpose of this property is.</li><li>Press "Done".</li></ol><p></p><p>The new property is now listed in the properties list for the interface, and can be accessed from event code within the composite. Encapsulate the composite component, and then paste it into a test system. Note that the object inspector for the instantiated composite component has a tab page "Interface", in which your interface property is listed. An input property is editable here, or can be populated programmatically at run time.</p><h3><a id="TogetdataoutofacompositeComponent">To get data out of a composite Component</a><br></h3><p>Events in the enclosing system have no view of the sub-elements within a composite, and so cannot obtain property values directly. For this purpose an "output" property is needed. As in the section above, while editing the composite component, add an interface property, and set its type to "Output". When your composite is pasted into a containing system, the output property is listed in the Interface tab, but cannot be edited there. It is the responsibility of events within the composite to set the property value. </p><h3><a id="ToaddacallablemethodtoacompositeComponent">To add a callable method to a composite Component</a><br></h3><p>While editing your composite system in design mode, select your interface component (TXCompositeIntf) in the design tree.</p><p></p><ol><li>On the "Events" tab, press "Add" to create a new method.</li><li>On the popup screen, enter the name of the method, and its type (select "Read-Only").</li><li>Enter some brief text to explain to a user of your composite what the purpose of this method is.</li><li>Press "Done".</li></ol><p></p><p>The new method is now listed in the events list for the interface. Encapsulate the composite component, and then paste it into a test system. Note that the object inspector for the instantiated composite component has your method listed under "Events", but cannot be edited here. The enclosing system can execute the method using the "DoEvent" built-in.</p><h3><a id="ToaddaneditableEventHandlertoaCompositeComponent">To add an editable Event Handler to a Composite Component</a><br></h3><p>While editing your composite system in design mode, select your interface component (TXCompositeIntf) in the design tree.</p><p></p><ol><li>On the "Events" tab, press "Add" to create a new method.</li><li>On the popup screen, enter the name of the method, and its type (select "Editable").</li><li>Enter some brief text to explain to a user of your composite what event within the composite will execute it.</li><li>Press "Done".</li></ol><p></p><p>The new event handler is now listed in the events list for the interface, but code cannot be added here. The composite system can execute the method using the "DoEvent" built-in, for example on closing a form, or on changing a data table. Encapsulate the composite component, and then paste it into a test system. Note that the object inspector for the instantiated composite component has your event handler listed under "Events", and can be edited here, so that the user of the composite component can create their own handler.</p><p><br></p><hr id="null"><h2></h2><h2><a id="TheXIDEGPUJSWrapper">The XIDE GPUJS Wrapper</a><br></h2><p>The Pascal code for the GPU is accessed as a property of a GPU Canvas component which has been dropped onto the User Interface layout screen and/or as a node on the Code designer tree. The Pascal GPU code editor follows the same edit/compile cycle as for user code in the rest of the system. The differences are that this is code for blocks of threads in parallel. The code describes a single instruction multiple data (SIMD) approach where all the threads run the same code with thread specific code referencing "this.thread.x" , "this.thread.y" and "this.thread.z" to reflect their position in the block of threads. Parameter names are declared using a Paramlist property of the GPU canvas component and their transfer and run time execution is controlled by system calls described below. (N.B. parameters need to be passed as arrays so even scalar parameters passed into the code need to be referenced as follows "myParam[0]" )<br></p><p>The Pascal GPU code can daisy chain kernels. (Set the TXGPUCanvas property NumKernels>0) For each kernel in the chain its return value must be set to "MyValue". The next kernel in the chain can then read all the thread return values from the previous kernel by reading from "MyArray".The initial "MyArray" passed to the first kernel in the chain is set as a property ("InitStageData") of the GPU canvas and can have any x,y,z sizes as chosen by the user. The final kernel is the graphics display kernel where you set the r,g,b values as usual. The calculated data input to the graphics display kernel can also be accessed using either the "GetGPUStageArray" or "GetGPUStageArrayAsString" instructions;</p><h2><a id="MathsfunctionsavailableintheGPU">Maths functions available in the GPU </a> code are as follows:-</h2><p></p><ul><li>abs(a) sign(a) trunc(a) ceil(a) max(a,b) min(a,b)</li><li>sin(a) cos(a) arcsin(a) arccos(a) arctan(a,b)</li><li>sqrt(a) power(a,b) ln(a) log10(a) log2(a) </li></ul><h2><a id="LimitationsofcodingfortheGPU">Limitations of coding for the GPU</a><br></h2><p>When coding in Pascal for the GPU, you should be aware that there are fundamental limitations on the constructs available. In particular:-</p><p></p><ul><li>All parameters passed into the GPU are real arrays (scalar parameters are real arrays of length one)<br></li><li>You can read from but not write to any of these array parameters</li><li>You cannot declare a local array</li><li>Each thread returns a single real value</li><li>You cannot communicate with any other thread (except by synchronising the results in a new kernel)</li><li>You cannot use a Boolean type (use 0 or 1 instead)</li><li>You cannot use "var" parameters in a function call</li><li>All function parameters must be a simple type</li><li>Nested function declarations do not follow normal (Pascal) scope rules</li><li>Loops are unrolled so you MUST SET the "<span style="font-family: Verdana, Arial, sans-serif; font-size: 12px; white-space: nowrap;">MaxIterations"</span> parameter at a high enough value to reflect your algorithm''s requirements</li><li>The number of threads in each kernel are given by the KernelXDims, KernelYDims and Kernel ZDims properties of the GPU Canvas and these MUST BE SET either manually or programatically before activating the GPU.</li><li>The GPU is a Single Instruction Multiple Data machine so branching in a thread does not jump over the code in the path not taken, it idles in order to allow other threads to execute the code in that path if need be. </li><li>Debugging on the GPU is "primitive" the only way to do it when running on the hardware is to write out intermediate results to the thread output value for selected threads which you dedicate to providing diagnostic output. </li></ul><p><br></p><p><br></p><p></p>';
'<h1 style="text-align: center;"><u>XIDE Help</u></h1><h2 style="text-align: center;"> (A simple "Browser-First" IDE for Pascal and Python)</h2><h2>Contents</h2><p>Overview</p><p></p><ul><li><a href="#Purpose">Purpose</a></li><li><a href="#Installation">Installation</a></li><li><a href="#Functionality">Functionality</a></li><li><a href="#UnifiedUserInterface(HTML,CSS,SVG)">Unified User Interface (HTML,CSS,SVG)</a></li><li><a href="#TheStyleDesigner">The Style Designer</a></li><li><a href="#CompositeComponents">Composite Components</a></li><li><a href="#GPUCapability">GPU Capability</a></li><li><a href="#ProjectDevelopmentandDeployment">Project Development and Deployment</a></li><li><a href="#Debugging">Debugging</a></li><li><a href="#ImplementationExtensibilityandLicencing">Implementation, Extensibility and Licencing</a></li><li><a href="#DevelopmentRoadmap">Development Roadmap</a></li><li><a href="#Compatibility">Compatibility</a></li></ul><p></p><p></p><p>User Interface</p><ul><li><a href="#DesigningaUserinterface">Designing a Userinterface</a></li><li><a href="#ResourceandInstanceTrees">Resource and InstanceTrees</a></li><li><a href="#AvailableWidgets">Available Widgets</a></li><li><a href="#ResponsiveDesign">Responsive Design</a></li><li><a href="#WritingApplicationCode">Writing Application Code</a></li><li><a href="#PascalSyntax">Pascal Syntax</a></li><li><a href="#Python">Python</a></li></ul><p></p><p>Application Programming Interface</p><p></p><ul><li><a href="#AccessingUserinterfaceObjectsatRunTime">Accessing User interface Objects at Run Time</a></li><li><a href="#TypesofAPICalls">Types of API Calls</a></li><li><a href="#AsynchronousCallsMultithreadingandInitialisationfunctions">Asynchronous Calls,Multithreading and Initialisation functions</a></li><li><a href="#ListofXIDEspecificAPIprocedureandfunctioncalls">List of XIDE specific API procedure and function calls</a></li><li><a href="#Generalfunctions">General functions</a></li><li><a href="#MessagesandDialogs">Messages and Dialogs</a></li><li><a href="#TXTablefunctions">TXTable functions</a></li><li><a href="#TXGPUCanvasfunctions">TXGPU Canvas functions</a></li><li><a href="#PythonOnly">Python Only functions</a></li></ul><p></p><p>Encapsulation</p><ul><li><a href="#TocreateacompositeComponent">To create a composite Component</a></li><li><a href="#TouseacompositeComponent">To use a composite Component</a></li><li><a href="#ToeditacompositeComponent">To edit a composite Component</a></li><li><a href="#TopassdataintoacompositeComponent">To pass data in to a composite Component</a></li><li><a href="#TogetdataoutofacompositeComponent">To get data out of a composite Component</a></li><li><a href="#ToaddacallablemethodtoacompositeComponent">To add a callable method to a composite Component</a></li><li><a href="#ToaddaneditableeventhandlertoacompositeComponent">To add an editable event handler to a composite Component</a></li></ul><p>GPU <br></p><ul><li><a href="#TheXIDEGPUJSWrapper">The XIDE GPUJS Wrapper</a></li><li><a href="#MathsfunctionsavailableintheGPU">Maths functions available in the GPU</a></li><li><a href="#LimitationsofcodingfortheGPU">Limitations of coding for the GPU</a></li></ul><p></p><p></p><p> </p><p></p><hr id="null"><h2><p></p></h2><h2><p><a id="Purpose">Purpose</a><br></p></h2><p>XIDE is a combined Client Side Run Time Library and RAD IDE intended to allow Pascal and/or Python development in the browser with the minimum of installation overhead or learning curve while also being as platform independent as possible. It is targeted at Prototyping, Small Group Collaboration and Agile Line of Business projects on any platform that is supported by Chrome or Electron, or Lazarus (and the Chrome Embedded Framework). It is not intended for the development of general-purpose public facing web sites.</p><h2><a id="Installation">Installation</a><br></h2><p>In the browser, XIDE for Chrome is a single page static HTML page with no dependencies. so installation is just a matter of loading that initial web page. All subsequent computation and data storage is done client side. This single page web app combines the currently selected user project, as well as the RTL and IDE Code so any user project can be deployed with the IDE disabled (for end users) or enabled (for collaborators) as required.</p><p>Python in XIDE is based on the Mozilla Pyodide project which brings a full data science stack to the browser, such as NumPy, Pandas and Matplotlib. </p><p>If using a snapshot of XIDE on the desktop (i.e. XIDE.exe), you need to install local copies of Free Pascal and Python following the relevant instructions on their web sites. Then using the XIDE.exe main menu "Settings" option set the path to the home directories for the fpc compiler. Alternatively to rebuild XIDE from source, see <a href="https://github.com/Steve--W/XIDE">https://github.com/Steve--W/XIDE.</a> </p><h2><a id="Functionality">Functionality</a><br></h2><p>XIDE is designed to bring the power of Free Pascal (Pas2JS) and the convenience of Rapid Application Development (RAD) to the browser. It is a "Browser First" approach which also delivers cross platform capability by replicating browser functionality on the desktop in native code. This allows the user to exploit the greater efficiency of compiled native code compared to interpreted browser environments as required. It also allows a single code base to support multiple different target environments for different user circumstances or different stages in a project. </p><p>The Python option in XIDE adds broader "Data Science" capabilities to the environment and allows the more interactive exploratory approach of Python to be exploited as required. See <a href="https://hacks.mozilla.org/2019/04/pyodide-bringing-the-scientific-python-stack-to-the-browser/">https://hacks.mozilla.org/2019/04/pyodide-bringing-the-scientific-python-stack-to-the-browser/</a></p><h2><a id="UnifiedUserInterface(HTML,CSS,SVG)">Unified User Interface (HTML,CSS,SVG)</a><br></h2><p>The browser supports a number of different standards as part of its user interface. These include HTML, CSS, SVG to cover page layout, style editing, and vector graphics respectively. Normally these all require their own conventions to be used when accessed directly from the browser and/or JavaScript. XIDE unifies the user''s access to these different browser capabilities using a standardised Object Inspector / Drag and Drop approach for them all. For HTML and SVG this should appear seamless to the user with all the SVG containers and components accessed in an identical manner to HTML so requiring no further explanation than provided below for basic screen layout and editing. </p><h2><a id="TheStyleDesigner">The Style Designer</a><br></h2><p>CSS functionality is provided by supporting a style design tree in addition to the Code and UI design trees described below. As with the UI design tree, Style resources (new design rules, targets, properties and rule types ) are dragged from a resources tree and dropped on the relevant node of the style tree. The style tree also supports logical grouping of targets using "AND" and "OR" nodes. This speeds up and simplifies the CSS syntax generation considerably compared to direct text entry.</p><h2><a id="CompositeComponents">Composite Components</a><br></h2><p>XIDE can be used to build reusable "widgets" by creating a system with a set of XIDE elements and associated events, and then encapsulating that system. The encapsulated system is saved to local storage, and will appear in the Resources tree as a Composite component, which can then be pasted into other systems the user is building.</p><h2><a id="GPUCapability">GPU Capability</a><br></h2><p>XIDE provides a thin wrapper for GPUJS (See https://gpu.rocks/) which generates GPU code from JavaScript. This produces WebGL code as it is widely supported "out of the box" in most browsers and on most processor/GPU combinations. This minimises the installation and configuration needed in order to get GPU code running on a new system. As such it is a good way to start learning about the possibilities (and perhaps more importantly the limitations) of programming for a massively parallel platform. </p><p>One of the weaknesses of this approach is the frustrating inability to optimise code or diagnose bugs in the GPU kernels except by exhaustive trial and error. So for any serious GPU programming it is well worth investing the time in getting to grips with the (admittedly intimidating) learning curve needed to master tools like OpenCL or Cuda and the associated tool stacks. Having said that, for simple "embarrassingly parallel" examples, or where there is a need to build simple GPU code into more general purpose or widely shared apps, the GPUJS approach can be very helpful.</p><h2><a id="ProjectDevelopmentandDeployment">Project Development and Deployment</a><br></h2><p>During the development phase of a project XIDE will usually be loaded in design mode where you can edit the user interface design and the code behind it. On startup on the desktop, the IDE re-loads the project you were last working on. On the browser, it can be set to revert to the original state every time the app is started or to reload from the previous session.</p><p>Existing projects can be loaded from a previously saved system in local storage, or from the clipboard. Clearing the current system will start a new project. At the end of the design phase, you will sometimes want to deploy the developed HTML app to end users without allowing access to the IDE. In this case, select the "System / Deploy" option from the main menu and this will generate a self contained HTML page implementing your application and the run time environment needed to execute it, but with the interactive IDE features disabled. You can now load this to a server of your choice, or email directly to your end user so they can run it from their file system. </p><p>Alternatively, if you wish to give them access to inspect and perhaps contribute to, or modify, the app, then distribute the blank XIDE app for their preferred platform and use the "System / Save" option to generate a project definition file that they can load into it using the "System / Load" option on the main menu. </p><h2><a id="Debugging">Debugging</a><br></h2><p>When testing Pascal code you have written using XIDE, the PAS2JS compiler error messages will flag any source code syntax problems. If you click on one of these error messages this will position the cursor at the relevant character position in the line of code in the XIDE code editor. Run time errors will sometimes be trapped by error handlers built in to XIDE and generate a helpful error message. If this is not sufficient to uniquely identify the cause of the problem then "ctrl shift J" in Chrome will bring up the built in developer console which will hopefully provide the additional information you need to track down the problem. Alternatively, a break point can be set in the code by inserting a "DebugStart;" instruction that will start the native browser debug facility at that point.</p><h2><a id="ImplementationExtensibilityandLicencing">Implementation, Extensibility and Licensing</a><br></h2><p>XIDE is implemented using the Pas2JS dialect of the Object Pascal programming language. This is because it is efficient, easy to learn, and is available on a wide range of processor architectures. </p><p>Sometimes, as projects go through their life cycle, new more specialist requirements emerge. At this point the XIDE framework can be extended using project or platform specific custom components developed in Lazarus. </p><p>XIDE is an open source project distributed using the same licence as Lazarus (GPL) Source code is available from GitHub see <a href="https://github.com/Steve--W/XIDE">here</a> for the IDE and <a href="https://github.com/Steve--W/XComponents">here</a> for the components used to build it. (see <font color="#0000ff">https://github.com/Steve--W/XIDE</font> and<font color="#0000ff"> https://github.com/Steve--W/XComponents</font> respectively)</p><h2><a id="DevelopmentRoadmap">Development Roadmap</a><br></h2><p>I have developed XIDE to support my ongoing academic research projects. I have made the project open source in case it should prove useful to anyone else. In particular, I hope its browser first approach, low installation overhead and easy learning curve will help to introduce the joys of Free Pascal and Lazarus to a wider audience.<br></p><p>Those aspects of XIDE and XComponents that I use regularly are "tried and tested". Some aspects that are used less often may have more bugs, and there are many aspects where it would be great to add new or improved features but where I do not have the bandwidth to address at the moment. If anyone wants to help out with any improvement to XIDE then their contribution will be most welcome.</p><p>(Some topics that spring to mind, from a long list of potential improvements, are:- Broadening XIDE browser support beyond the Chrome compatible set, XIDE integration with Lazarus, improving the wrapper for GPUJS or adding a drag and drop utility for constructing MatPlotLib data visualisations to make these Python libraries easily accessible to the Pascal community. )</p><h2><a id="Compatibility">Compatibility</a><br></h2><p>In desktop mode, XIDE is designed to run on platforms supported by Lazarus, and optionally, the Chromium Embedded Framework and Python (i.e. most desktop platforms). If CEF or Python is not available then XIDE can still run but will then not support their specialist features. Alternatively, Electron or Cordova and Crosswalk can be used to provide a hybrid implementation of XIDE. This gives full Web connectivity and CSS on a wide range of platforms but with a trade off in terms of size, speed and security.</p><p>In browser mode XIDE is targeting closed user groups (where the browser can be specified) so it is only tested on recent versions of Chrome but it may also work on other browsers which use a Chrome engine. (e.g. the latest version of Microsoft Edge) </p><p>Note that TheStyleDesigner is only available on the Browser versions as it depends on CSS functionality.</p><p><br></p><hr id="null"><p></p><h2><a id="DesigningaUserinterface">Designing a User interface</a><br></h2><h3><a id="ResourceandInstanceTrees">Resource and Instance Trees</a><br></h3><p>XIDE uses a very simple paradigm. Essentially, it consists of three elements.</p><p></p><ol><li> A resources tree, showing the AvailableWidgets (visual and non visual)</li><li> A system design tree and object property inspector/editor</li><li> A layout panel showing a WYSIWYG version of the current page design.</li></ol><p></p> <p>The UI is built by pasting nodes from the resource tree to the system design tree. Each node has object properties defined by a name/value pairs that can be edited using the object inspector or referenced and or updated by run time code. Events are also available on each widget so that Pascal code can be attached to them using the built in code editor and compiler. Python scripts can also be called from these event handlers.</p><h3><a id="AvailableWidgets">Available Widgets</a><br></h3><p>The widgets listed in the resource tree include both UI and non visual components (the latter can be added to the root node of the UI design tree). </p><h3><a id="ResponsiveDesign">Responsive Design</a><br></h3><p>XIDE supports a simple ResponsiveDesign layout paradigm which consists of a Main page, Tab controls and Popups to define the constituent pages in a UI design. Horizontal and Vertical layout boxes (together with associated alignment properties) are then nested within these pages to control the final layout of components on the page.</p><h3><a id="WritingApplicationCode">Writing Application Code</a><br></h3><p>XIDE uses an event driven model where event handlers can be attached to pre-defined events triggered by objects in the user interface. These procedures can be inspected and/or edited by using the object inspector to navigate to the required UI object then pressing the ellipsis button to the right of the required event in its events tab. This creates an entry for that event handler under the "Event Handlers" node in the code design tree. So once a handler has been added it can then also be navigated to by selecting it in the code designer and pressing the edit button. </p><h3><a id="PascalSyntax">Pascal Syntax</a><br></h3><p>The PascalSyntax recognised by XIDE is that used by the Pas2JS variant of Free Pascal. (<a href="http://wiki.freepascal.org/pas2js">http://wiki.freepascal.org/pas2js</a>). A detailed description of the supported syntax can be found here. (<a href="http://wiki.freepascal.org/pas2js#RTL">http://wiki.freepascal.org/pas2js#RTL</a>)</p><h3><a id="UnitStructure">Unit Structure</a><br></h3><p>In addition to the event handler nodes, shared code can be written by adding units directly to the code design tree as "Pascal Units" or "Python Scripts". </p><p>Functions and procedures in the code nodes can be amended or deleted by selecting the node on the code design tree and pressing the "Edit" button which will bring up the code editor screen as previously described for the event handler code. After a Pascal unit has been compiled for the first time in a session, all the procedures and functions declared in it are displayed as its child nodes in the code design tree. Selecting one of these nodes and pressing the edit button below will navigate directly to that function. Alternatively, selecting a node and pressing "Code Search" will list all references to that function or procedure allowing you to navigate directly to the most relevant reference.</p><h3><a id="Python">Python</a><br></h3><p>The Python syntax used is version 3.8. </p><p>Python does not have a unit structure like Pascal, however blocks of Python code can be added to the Code Designer tree in the same way as Pascal units. The difference is that these will be run when entering run mode. They are executed in the order they occur on the Code Designer tree and can contain initialisation, declarations and / or any other valid executable Python Code. </p><p>To execute Python code elsewhere, such as in an event handler, then simply invoke the "RunPython(<i>......</i>)" procedure with the relevant python function call (or code) as a string parameter,</p><p>A console output box is supplied so that Python errors and print statements can be viewed. On the desktop, the copy of Python being used is the version installed on the host machine, see the documentation for that system to review valid syntax, permissions etc. In the browser, the version of Python used is that supported by mozilla (see <a href="https://hacks.mozilla.org/2019/04/pyodide-bringing-the-scientific-python-stack-to-the-browser/">https://hacks.mozilla.org/2019/04/pyodide-bringing-the-scientific-python-stack-to-the-browser/</a>)</p><p><b>Javascript</b></p><div style="color: rgb(29, 34, 40); font-family: "times new roman", "new york", times, serif;">XIDE allows JavaScript code to be embedded as an ASM block in your pascal code. It can also use external JavaScript packages if you create a Pascal import unit for them. This process can be simplified by using the Typescript library of popular Javascript APIs. This is called definitely typed. (https://github.com/DefinitelyTyped/DefinitelyTyped) and covers thousands of JavaScript libraries.</div><div style="color: rgb(29, 34, 40); font-family: "times new roman", "new york", times, serif;"><br></div><div style="color: rgb(29, 34, 40); font-family: "times new roman", "new york", times, serif;">The Pas2JS team have created a CGI tool (https://www.freepascal.org/~michael/pas2js-demos/ts2pas/) available online which allows you to type the name of a Javascript library you are interested in.. If it is in DefinitelyTyped, then the name will appear in the list. Selecting the correct file and pressing "Go" will convert the file for you into a ready-made Pascal import unit. This is still being refined, but should work with most of the libraries in DefinitelyTyped. Fingers crossed, the libraries you are interested in are among them!</div><div style="color: rgb(29, 34, 40); font-family: "times new roman", "new york", times, serif; font-size: 13px;">.<br></div><hr id="null"><h3><a id="AccessingUserinterfaceObjectsatRunTime">Accessing User interface Objects at Run Time</a><br></h3><p>XIDE is designed to be a cross platform rapid application development system. In order to do this it uses a text based system description tree (The System Design or Instance Tree) to reflect the state of a users program at all times. This is similar to the function of the Document Object Model (DOM) in standard web applications. All object properties for nodes on this tree can be accessed and updated using the supplied get and set calls (see below).</p> <h3><a id="TypesofAPICalls">Types of API Calls</a><br></h3><p>In XIDE design mode the instance tree describing a users project can be inspected manually using the Object Inspector. This allows the user to select any node on the tree and inspect and/or modify its properties or event handlers as required. The XIDE API allows the same actions to be available programmatically. The functions available fall into the following types (and work in an identical manner in both Pascal and Python) viz:-</p><p></p><ul><li> Dialog boxes</li><li> Get and/or set a property value of a UI object</li><li> Save and load user selected data to the clipboard or local storage</li><li> Copy or delete a UI component or move it to a new parent.</li><li> Show or hide a popup form.</li><li> Show or hide a busy indicator.</li><li> get and set GPU parameters </li></ul><p></p><p>The detailed syntax for these function calls is appended below. Note that unless explicitly stated, all values are strings.</p><h3><a id="AsynchronousCallsMultiThreadingandInitializationfunctions">Asynchronous Calls, Multi Threading and Initialization functions</a><br></h3><p>Many web calls issue requests that need to wait for a response from a web service, database or other remote service provider. Similarly, when starting another thread in parallel, the main thread will often need to wait for such child threads to return the results of their work before it can proceed. XIDE allows main event handlers to specify a "initalisation"function. This is a block of code which issues all such requests prior to running the main event code when they have all finished executing. See below for the detail syntax of the available calls.</p><p>Note however that all such asynchronous calls first parameter is "e" the event context (automatically declared and populated by XIDE, behind the scenes, for every XIDE event) from which they have been issued so they know where to return without requiring the user to enter complex boilerplate code.</p><h2><a id="ListofXIDEspecificAPIprocedureandfunctioncalls">List of XIDE specific API procedure and function calls</a><br></h2> <p></p><h3><a id="Generalfunctions">General functions</a><br></h3><ul><li>procedure SetPropertyValue(nodeName,propName,newValue:String); <font color="#0000ff">set a component property (string value) </font></li><li>function GetPropertyValue(nodeName,propName:String); <font color="#0000ff"> returns a component property value (as string) </font></li><li>procedure SetPropertyValueIndexed(nodeName,propName:String;newValue:TStringArray; x,y:integer); <font color="#0000ff">set a portion of a component array property</font> </li><li>procedure CopyToClip(str:String); <font color="#0000ff"> copies the given string to the clipboard </font></li><li>function CopyFromClip(e:TEventStatus):String; <font color="#0000ff">CopyFromClip is an async function (required for browser use), so it must be coded in the "Init" section of an event handler. The result here is a blank string. The clipboard string is held in e.ReturnString, which can be picked up in the "Main" section of the event handler.</font></li><li>procedure ShowXForm(XFormID:String; modal:Boolean); <font color="#0000ff"> opens a TXForm. [note:"modal=false" currently only effective on desktop] </font></li><li>procedure CloseXForm(XFormID:String); <font color="#0000ff"> closes a TXForm. </font></li><li>procedure DoEvent(EventType,NodeId,myValue:String); <font color="#0000ff"> executes the event handler defined for the given event type and component. </font></li><li>procedure MoveComponent(nodeId:string;NewParentId:string); <font color="#0000ff">re-parents the given UI component </font></li><li>procedure CopyComponent(nodeId,NewParentId,NewName:string); <font color="#0000ff">copies the given UI component and places the clone under the given parent </font></li><li>function DeleteComponent(nodeId:string;ShowNotFoundMsg:Boolean=true):Boolean; <font color="#0000ff"> deletes the given UI component. Returns false if not done. </font></li><li>function UserSystemAsString():String; <font color="#0000ff">Returns the string representation of the current user system (can be imported to XIDE via System>Load) </font></li><li>function LoadUserSystemString(SystemString:String); <font color="#0000ff">Imports a new user system to the XIDE framework (can only be done in "Design" mode) </font></li><li>procedure ShowBusy(e:TEventStatus); <font color="#0000ff">Shows the busy cursor ShowBusy is an async function (required for browser use), so it must be coded in the "Init" section of an event handler. </font></li><li>procedure HideBusy; <font color="#0000ff">Hides the busy cursor </font> </li><li>procedure ProcessMessages; <font color="#0000ff"> Functional in Desktop execution only. Executes a pascal Application.ProcessMessages statement. </font></li><li>procedure DebugStart; <font color="#0000ff">Functional in Browser execution only. Executes a Javascript "debugger;" statement - starts the native browser debug facility. </font></li><li>procedure RunPython(str:String); <font color="#0000ff"> Executes the given Python script </font></li><li>procedure PyodideLoadPackage(nm:String); <font color="#0000ff"> Functional in Browser execution only. Loads the requested Pyodide/python package, so that it will be available for import. </font></li><li>function PyodidePackageLoaded(nm:String):Boolean; <font color="#0000ff"> Functional in Browser execution only. Returns true if the named package has been loaded into the Pyodide environment. </font> </li></ul><div contenteditable="true"><ul></ul><h3><a id="MessagesandDialogs">Messages and Dialogs</a><br></h3><ul><li>procedure ShowMessage(msg:String); <font color="#0000ff"> displays a popup alert </font></li><li>function Confirm(TextMessage:string):boolean; <font color="#0000ff">displays a confirmation alert; returns true/false </font></li><li>function Prompt(TextMessage,promptString:string):string; <font color="#0000ff">displays an input box; returns user-entered string </font></li><li>procedure ConsoleLog(txt:String); <font color="#0000ff">Writes a debug message to the console log </font></li></ul><ul></ul><h3><a id="TXTablefunctions">TXTable functions</a><br></h3><ul><li>procedure LoadTableFromExcelCopy(TableName,CopiedString:String); <font color="#0000ff">Populate the given TXTable component with a string in Excel format (eg. as copied from a spreadsheet) </font></li><li>procedure LoadTableFromNumArray(TableName,NumArray:T2DNumArray); <font color="#0000ff">Populate the given TXTable component from a 2D numeric array </font></li><li>function GetTableDataArray(TableName:String;SkipHeader:Boolean):T2DStringArray; <font color="#0000ff"> Fetch the cells from the given TXTable component as a 2D string array </font></li><li>function Array2DToString(arr:T2DNumArray):String; <font color="#0000ff"> Convert numeric 2D array to string form eg. [[...],...,[...]] </font></li></ul><ul></ul><h3><a id="TXGPUCanvasfunctions">TXGPU Canvas functions</a><br></h3><ul><li>function GetGPUParamNumValue(GPUName,pName:String):TNumArray; <font color="#0000ff">For the given TXGPUCanvas component, returns the value of the named numeric parameter as an array </font></li><li>function GetGPUConstIntValue(GPUName,pName:String):integer; <font color="#0000ff"> For the given TXGPUCanvas component, returns the value of the named integer parameter </font></li><li>procedure SetGPUParamNumValue(GPUName,pName:String;pValue:TNumArray); <font color="#0000ff">For the given TXGPUCanvas component, sets the value of the named numeric parameter as a 1-D array </font></li><li>procedure SetGPUParam2DNumValue(GPUName,pName:String;pValue:T2DNumArray); <font color="#0000ff">For the given TXGPUCanvas component, sets the value of the named numeric parameter as a 2-D array </font></li><li>procedure SetGPUConstIntValue(GPUName,pName:String;pValue:integer); <font color="#0000ff">For the given TXGPUCanvas component, sets the value of the named integer parameter </font></li><li>function GetGPUPixelArray(GPUName:String):T3DNumArray; <font color="#0000ff"> Fetch the current Pixel array for the given TXGPUCanvas component </font></li><li>function GetGPUPixelArrayAsString(GPUName:String):String; <font color="#0000ff">Fetch the current Pixel array in string format for the given TXGPUCanvas component </font> </li><li>function GetGPUStageArray(GPUName:String):T3DNumArray; <font color="#0000ff"> Fetch the stage array (resulting from the non-graphical kernel stack) for the given </font>TXGPUCanvas component </li><li>function GetGPUStageArrayAsString(GPUName:String):String; <font color="#0000ff">Fetch the stage array in string format for the given TXGPUCanvas component </font></li></ul><ul></ul><ul></ul><ul></ul><ul></ul><ul></ul><ul></ul><ul></ul><ul></ul><h3><a id="PythonOnly">Python Only</a><br></h3><ul><li>function ShowPythonPlot(ImgName,fig)<font color="#0000ff"> In the given TXImage component, displays the contents of fig (a matplotlib figure) </font></li></ul><hr id="null"><h2><a id="TocreateacompositeComponent">To create a composite Component</a><br></h2><p></p><ol><li>Clear the system.</li><li>Build your widget in the normal way (for example, a table, with a copy and a paste button, and click events coded).</li><li>Test the system.</li><li>In design mode, select System>Encapsulate on the main menu. Provide a name for the composite component (eg. "TableWithCopyPaste").</li><li>In the Resources Tree, under "Composites", your new widget should now be listed.</li></ol><p></p><h3><a id="TouseacompositeComponent">To use a composite Component</a><br></h3><p></p><ol><li>Build a new system in the normal way.</li><li>Select a composite component in the Resources Tree, and paste to the system in the normal way. </li></ol><p></p><p>The composite component will be listed in the Design Tree, but without its constituent components - only the enclosing element will be shown. The composite component has two non-editable properties to note:</p><p></p><ul><li> "CompositeType", which shows the name with which the composite was originally created.</li><li> "SourceString", which contains the definition of the sub-elements within the composite, for system use.</li></ul><p></p><h3><a id="ToeditacompositeComponent">To edit a composite Component</a><br></h3><p></p><ol><li>Clear the system.</li><li>Select the composite resource in the Resource Tree, and press "Load". This will load the composite as a system in design mode.</li><li>When your update is completed, save the composite again using System>Encapsulate on the main menu.</li></ol><p></p><p>NOTE: This will not update any instantiated copies of your composite. To update instantiated copies, load the system(s) containing them, then delete and re-paste the composite.</p><h3><a id="TopassdataintoacompositeComponent">To pass data into a composite Component</a><br></h3><p>By default, events within a composite element have no view of the containing system, and so cannot obtain data from it. So while building a composite component, you can include a Composite Interface element (TXCompositeIntf in the Resources Tree, under Non-Visual components).</p><p></p><ol><li>Paste a composite interface element under the UIRootNode in the design tree. </li><li>In the object inspector Properties tab, press the "Add" button. This will create a new property for the interface. </li><li>On the popup screen, enter the property name.</li><li>Use the "Type" selector to specify whether the property is "Input" or "Output". Select "Input".</li><li>Enter some brief text to explain to a user of your composite what the purpose of this property is.</li><li>Press "Done".</li></ol><p></p><p>The new property is now listed in the properties list for the interface, and can be accessed from event code within the composite. Encapsulate the composite component, and then paste it into a test system. Note that the object inspector for the instantiated composite component has a tab page "Interface", in which your interface property is listed. An input property is editable here, or can be populated programmatically at run time.</p><h3><a id="TogetdataoutofacompositeComponent">To get data out of a composite Component</a><br></h3><p>Events in the enclosing system have no view of the sub-elements within a composite, and so cannot obtain property values directly. For this purpose an "output" property is needed. As in the section above, while editing the composite component, add an interface property, and set its type to "Output". When your composite is pasted into a containing system, the output property is listed in the Interface tab, but cannot be edited there. It is the responsibility of events within the composite to set the property value. </p><h3><a id="ToaddacallablemethodtoacompositeComponent">To add a callable method to a composite Component</a><br></h3><p>While editing your composite system in design mode, select your interface component (TXCompositeIntf) in the design tree.</p><p></p><ol><li>On the "Events" tab, press "Add" to create a new method.</li><li>On the popup screen, enter the name of the method, and its type (select "Read-Only").</li><li>Enter some brief text to explain to a user of your composite what the purpose of this method is.</li><li>Press "Done".</li></ol><p></p><p>The new method is now listed in the events list for the interface. Encapsulate the composite component, and then paste it into a test system. Note that the object inspector for the instantiated composite component has your method listed under "Events", but cannot be edited here. The enclosing system can execute the method using the "DoEvent" built-in.</p><h3><a id="ToaddaneditableEventHandlertoaCompositeComponent">To add an editable Event Handler to a Composite Component</a><br></h3><p>While editing your composite system in design mode, select your interface component (TXCompositeIntf) in the design tree.</p><p></p><ol><li>On the "Events" tab, press "Add" to create a new method.</li><li>On the popup screen, enter the name of the method, and its type (select "Editable").</li><li>Enter some brief text to explain to a user of your composite what event within the composite will execute it.</li><li>Press "Done".</li></ol><p></p><p>The new event handler is now listed in the events list for the interface, but code cannot be added here. The composite system can execute the method using the "DoEvent" built-in, for example on closing a form, or on changing a data table. Encapsulate the composite component, and then paste it into a test system. Note that the object inspector for the instantiated composite component has your event handler listed under "Events", and can be edited here, so that the user of the composite component can create their own handler.</p><p><br></p><hr id="null"><h2></h2><h2><a id="TheXIDEGPUJSWrapper">The XIDE GPUJS Wrapper</a><br></h2><p>The Pascal code for the GPU is accessed as a property of a GPU Canvas component which has been dropped onto the User Interface layout screen and/or as a node on the Code designer tree. The Pascal GPU code editor follows the same edit/compile cycle as for user code in the rest of the system. The differences are that this is code for blocks of threads in parallel. The code describes a single instruction multiple data (SIMD) approach where all the threads run the same code with thread specific code referencing "this.thread.x" , "this.thread.y" and "this.thread.z" to reflect their position in the block of threads. Parameter names are declared using a Paramlist property of the GPU canvas component and their transfer and run time execution is controlled by system calls described below. (N.B. parameters need to be passed as arrays so even scalar parameters passed into the code need to be referenced as follows "myParam[0]" )<br></p><p>The Pascal GPU code can daisy chain kernels. (Set the TXGPUCanvas property NumKernels>0) For each kernel in the chain its return value must be set to "MyValue". The next kernel in the chain can then read all the thread return values from the previous kernel by reading from "MyArray".The initial "MyArray" passed to the first kernel in the chain is set as a property ("InitStageData") of the GPU canvas and can have any x,y,z sizes as chosen by the user. The final kernel is the graphics display kernel where you set the r,g,b values as usual. The calculated data input to the graphics display kernel can also be accessed using either the "GetGPUStageArray" or "GetGPUStageArrayAsString" instructions;</p><h2><a id="MathsfunctionsavailableintheGPU">Maths functions available in the GPU </a> code are as follows:-</h2><p></p><ul><li>abs(a) sign(a) trunc(a) ceil(a) max(a,b) min(a,b)</li><li>sin(a) cos(a) arcsin(a) arccos(a) arctan(a,b)</li><li>sqrt(a) power(a,b) ln(a) log10(a) log2(a) </li></ul><h2><a id="LimitationsofcodingfortheGPU">Limitations of coding for the GPU</a><br></h2><p>When coding in Pascal for the GPU, you should be aware that there are fundamental limitations on the constructs available. In particular:-</p><p></p><ul><li>All parameters passed into the GPU are real arrays (scalar parameters are real arrays of length one)<br></li><li>You can read from but not write to any of these array parameters</li><li>You cannot declare a local array</li><li>Each thread returns a single real value</li><li>You cannot communicate with any other thread (except by synchronising the results in a new kernel)</li><li>You cannot use a Boolean type (use 0 or 1 instead)</li><li>You cannot use "var" parameters in a function call</li><li>All function parameters must be a simple type</li><li>Nested function declarations do not follow normal (Pascal) scope rules</li><li>Loops are unrolled so you MUST SET the "<span style="font-family: Verdana, Arial, sans-serif; font-size: 12px; white-space: nowrap;">MaxIterations"</span> parameter at a high enough value to reflect your algorithm''s requirements</li><li>The number of threads in each kernel are given by the KernelXDims, KernelYDims and Kernel ZDims properties of the GPU Canvas and these MUST BE SET either manually or programatically before activating the GPU.</li><li>The GPU is a Single Instruction Multiple Data machine so branching in a thread does not jump over the code in the path not taken, it idles in order to allow other threads to execute the code in that path if need be. </li><li>Debugging on the GPU is "primitive" the only way to do it when running on the hardware is to write out intermediate results to the thread output value for selected threads which you dedicate to providing diagnostic output. </li></ul><p><br></p><p><br></p><p></p>';
{ TXIDEHelpForm }
{$ifndef JScript}
procedure TXIDEHelpForm.FormCreate(Sender: TObject);
begin
myNode:=DoXFormCreated(self);
HelpFormRoot:=FindDataNodeById(myNode,'HelpFormVBox1','',true);
HelpHTMLText.SourceText:=BaseHTML;
end;
procedure TXIDEHelpForm.FormActivate(Sender: TObject);
begin
end;
procedure TXIDEHelpForm.FormResize(Sender: TObject);
begin
DoFormResize(self, HelpFormVBox1);
end;
procedure TXIDEHelpForm.FormShow(Sender: TObject);
begin
HelpHTMLText.SourceText:=HelpHTMLText.SourceText;
end;
{$endif}
procedure TXIDEHelpForm.InitialiseonShow;
begin
self.Top:=100;
self.Left:=150;
{$ifdef JScript}
// reset overview text AFTER the popup is rendered, otherwise actual height and width return 0
asm
var ob=this.HelpHTMLText;
setTimeout(function(){pas.XHTMLText.ResetHTMLText(ob.NodeName,ob.NameSpace); }, 200);
end;
{$endif}
end;
end.