RUSSIAN
(Русский)
ENGLISH


This function requires cookies.
If the browser does not accept cookies,
the light theme is used always.

PART 1.   AL-IV:    How to start programming

 

A reference to download compilers and base code samples:
https://sourceforge.net/projects/al-iv/
Last date changed: April, 2021

Select a compiler and a target platform

  • An application written on AL-IV is supposed to be maximal multi-platform. A written program always can be built for any supported platform just selecting a correspondent compiler version and specifying desired set of libraries implementing supporting of a target platform selected.

    So a platform selection is not a problem an a design stage: just select a platform where you are now and for which a compiler is ready (Windows ?)*.
     
  • For now there are compilers for Delphi32, C#, Java and Free Pascal .
     
  • So, any platform can be satisfactory selected by any of following targets: Windows(.NET/32/64), Linux, Android (at the Feb, 2020 and there are no changes for now, 2021).

 

 

Configure parameters to pass to a compiler

  • AL-IV compiler is a console application. It gets a specified source file and a list of directories to search used classes and other parameters as arguments and creates as a result an output project in a specified directory on the target programming language for which it is prepared.
    E.g. there are compilers:

     

    • Compiled\AL4Compiler.exe - AL-IV to C# primary compiler;
    • CSharpBuild\AL4CSharpCompiler.exe - AL-IV to C# compiler;
    • Delphi_build\AL4DelphiCompiler.exe - AL-IV to Delphi / Free Pascal (created using C#, requires .NET Framework 3.5);
    • By_Delphi_build\AL4DelphiCompiler.exe - AL-IV to Delphi compiler (which itself is compiled by the AL-IV to Delphi compiler above, so it can be run in earlier Windows versions which do not support .NET, or even in Linux under wine).
  • To see which parameters are need by a compiler, it is sufficient to run it without parameters (in a console window). Then it will print a list of options available. Take an attantion on a key
    /@ path\filename
    This is the best way to configure options to compile your projects and then just to pass such configurations file as a parameter together with the option /@.
    If you watch in target folders for different projects for files having long extensions like compiler.options or visual-program1cs.config, you can find then such options to launch compilers.
     
 
  • Typical configurations file contains several lines.

    The first line contains path\main_file_name - such file contains a root class from which compiling is started. Also, it should contain a static function having a short name Main (and its full name can be any sufficiently long to satisfy the AL-IV requirements, e.g. Main|_artificial_intellect_constructor). This main function should not have parameters or return a value. It it called once to run a compiled program.

    There is possible that other classes also are used in the program, and it is necessary to use one or more keys
    /src path
    to specify additional folders to search used classes. For native classes it is important to specify folders containing classes specific for a certain target platform. E.g. folders named _Delphi are used to create resulting Delphi application but folders named _CSharp are specific for resulting C#-project.

    Take an attention onto an option /nocon|sole - it should be used if a GUI application is required and it is not necessary to create initially a console window in the target program. In some target platforms this does not mean that console output can not be used: a console can be shown when it is first time is accessed from the code. But in certain target platforms this is not possible and console output will be lost.
 
 

Editing source code

  • You can use any convenient text editor to prepare a source code on AL-IV, e.g. a notepad or Notepad++ or any other similar tool. An IDE from almost any existing language also can be used (e.g. Delphi of MS Visual C++ IDE). It is possible to download here an xml-file with settings for the Notepad++ on AL-IV syntax highlighting (as it could be possible to do with its rules).
    There is also special code edit tool provided, IDE AL4, which is the best choice to work with the AL-IV code. It supports appropriate coloring, lines to highlight blocks of code, underlining problem parts of code, navigating on code, etc. It has also visual designer for forms, menus and reports
  • If you use an external text editor, then it is desired that it be capable to load and save text encoded in UTF-8. For this moment all ready compilers can read such text though a compiler made from Delphi output sources, can fail reading national letters. It is better not to use national symbols in sources for this time.
  • It is recommended it settings of your text editor to turn on replacing tabulations with spaces (this will make easier moving from one text editor to another). And if this is possible use "smart identation" rather then fixed length tabulations: by the first next word following spaces. And at least do not use too short tabulations (less then 3 spaces width).
  • Samples of source code can be learned in a short AL-IV description with samples. There is also a Hello, world application version there.
  • In case of a GUI application use a test project (in a folder AL4\Test_visual_project) as a sample. In such case it is convenient to make the main class as an inheritance from the {Form} class placing there a static function Main which creates the {Form} instance and launches it. Or use the project and class wizards embedded into the IDE AL4: in the menu File - New  class, then File - New project (on base the class created).
  • Some advices on code decoration:
    • Do not ignore the AL-IV requirements on a quality code. Never add the BAD modifier to a class, always satisfy requirements:
      • not more then three explicit function parameters,
      • not more then three nested blocks CASE/FOR,
      • not more then 7 simple + 7 block statements in a block section of code,
      • not more then 7 field declarations in a class section.
    • Give understandable full names to variables (functions types etc.) using as a short version of a name a starting part of such name. You should write such long name once and further use only short name to refer to the variable (of whatever you named) but in result if you (of not only you) will read such long name after some years it will be understandable yet though.
    • Follow a good practice while naming variables, functions, its parameters, fields, classes etc. Starting part of a name should be readable enough (do not use shrtned idntfiers by omitting some letters. It is preferable to use names like short|ened, id|entifiers etc.). Do not use hard reading (though widely used) gluedIntoOneLongName names. Use instead underscore_symbols_between_name_parts. Believe: these are much more readable. Take an attention that in the AL-iV it is possible to use underscores in numeric constants: 0x_FFfe_BF2a.

 

Follow these rules and you will get much more readable, structured and understandable code which can be easy corrected and supported later.

 

 

Compiler launching, errors analyzing

  • Place the main command to launch the compiler (with the parameter /@ ...) into a cmd-file to avoid typing it constantly.
  • You will launch the compiler very often.
  • You will produce a lot of errors especially on the start: AL-IV has a bit distinct logic in semantics and syntax than in other modern programming languages.
    Typical problems:
  • You used a function from another class but a compiler does not see it? Check if you included the class needed into an IMPORT statement list.
    You did include it? Check that you call the function correctly. May there is just a typo or another letter case?
    May be the function is not static and a class instance is required to call it (in a form object.Method(...)? ). Or other case, you have defined a new function but forget to declare it STATIC? Be attentive please: the compiler is not an extrasensory (though it takes pains).
  • The compiler requests a semicolon though a function is not yet ended? Check your code: an extra semicolon is somewhere above.
  • The compiler thinks that it is not suitable to have a dot (and a keyword or semicolon is waiting for)? You forget to finish some block above with a semicolon.
  • The compiler is complaining that there are more then 3 nesting levels but you see by your eyes that there are only three such levels? Check in above code that all the semicolons are on its places.
  • Write a semicolon which is carried onto the next line exactly under its corresponding statement header first character:
    FOR ... ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
        PUSH ... ▄▄▄▄▄▄▄▄▄▄▄▄▄ 
             CASE ... ▄▄▄▄▄▄  
                  ... ; ▄▄▄█  
        ; ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄█ 
    ; ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄█
  • Do you have problems with these semicolon and dot symbols too often? As an exercise write a utility which will show levels for all statements in your code. Such practice is useful and... useful: this utility will come handy next time you will find such error.
  • Finally, use the special text editor IDE AL4 which graphically confirms a correctness of blocks nesting even before you run the compiler.
  • After the compiler AL-IV successfully produced source files for your final project on a target language, it will try to launch a compiler certain for the target language.
    • There should no be problems with the C# compiler: it is installed always together with a .Net framework (csc.exe);
    • To run the Delphi32 compiler it is necessary to have a dcc32.exe from one of the old Delphi compilers. To force AL-IV finding its location, place a file dcc32.cmd into a destination folder of your project having following text:
      "path\to\dcc32.exe" "%1"
      or just
      dcc32.exe "%1"
      if a path to it is already added to the system environment variable PATH.
    • To run the javac compiler it is necessary to have installed jdk (any of versions 6, 7, 8 seems to be enough). Also, create an environment variable JAVABIN assigning a path to the bin Java directory to it to provide finding it by the AL-IV compiler.
  • If you add a key option /run finally your compiled application will be launched in result. It is also possible to pass options to it using a key /param [in square brackets].
P.S. In the APPENDIX (below), configuring of a certain sample is examined more detailed.

If libraries have not enough necessary functions ...

  • In some cases this is not a problem: if there are no too many such functions and you know how to call such functions on a target language selected, use native functions.
    Some advices though:
  • Consolidate all native functions in a separate class (or in several such classes). Mark the class as NATIVE (using the NATIVE modifier of a class):
    CLASS {My_wrappers|_to_native_functions}, NATIVE, UNTESTED : ...
  •  Mark a wrapper function as NATIVE and place a string constant as a body of those function:
    FUN Native_wrapper_name(param1, param2,
        param3) ==> TYPE, NATIVE, STATIC :
        "    return Some_native_function_call(...);" .

  • If a native function should contain two or more lines, use prefix symbol @ before the first line to add automatically line ending characters to the string constant after each line of code:
    FUN Native..., NATIVE:
       @"    if (X_Param1 < 0) return -1;"
        "    ..."
        "    more code;" .

  • If it is necessary to add some "native" code in between functions of the target source file, use a directive
    NATIVE "text" .
    placed between functions.
    Take into attention that several first such directives starting special words can be interpreted specially in certain target platforms, e.g. to add some additional import to target files. E.g.:
    NATIVE "using System.Drawing.Imaging;" .
  • If it is not possible to place all the desired native code into a string constant, use the native function just to call a wrapper function which you manually write using the target language. It is possible to place such manually written function near the AL-IV NATIVE function calling it:
    • the file should have an extension which is treated as a source file for a certain programming language compiler (pas for Delphi, java for Java, cs for C# etc.);
    • AL-IV code should be enclosed into symbols /* ... */, which traditionally are used in C-like languages to start and end multi-line comments (symbols /* and */ should be placed in separate lines);
    • if a native programming language uses other symbols to start and finish long comments, then the AL-IV code together with symbols /* and */ should be enclosed into those symbols. E.g. for the Pascal:
      (*
      /*
      .... AL-IV code
      */
      *)

      Or, for the Python:
      """
      /*
      ... AL-IV code
      */
      """
  • Take into attention that for a target platform compiler all the source files either generated (as a result of working AL-IV compiler) or used without changes should be added into a target folder before compile. So for extra files having native functions it is necessary add (for this development stage - manually) commands:
    /copy path\to\file.ext
    (A file will be copied but all comments starting from // at line starts are replaced onto a phrase saying that this is just a copy).
    Or, better add once a directive at the start of the library class using this native file:
    NATIVE "///COPY filename" .
 

Debugging

  • For this moment and in a distant future step-by-step debugging is not available and it is even is not planned. Instead, we have:

     

    • invulnerable (hmm, may be almost invulnerable) application which is not suddenly crashed on a stupid reason such as outbound of an array or a null reference to an object or even too deep recursion.
    • Almost always it is possible to add some code which on some conditions will output some tracing information into a console, or a text file, or onto display, and values printed can be used to understand what is the problem.
      (It is better to use blocks DEBUG: ... ; - those blocks can be later easy found and commented or removed, or turned off by adding an option /final while compiling).
    • Starting from, the version 0.92.9, when compiling to the Delphi/VCL, it is possible to use incremental compiling: the compiler after launching the application, waits for changes in sources of classes, recompiles them to separate DLLs, which can be attached to the running application on fly (by requests from your code). There are certainly some restrictions there:

       

      • it is not allowed to change declarations of existing methods, functions, fields, etc.;
      • it is not allowed to add new or remove existing methods, functions, fields etc.;
      • it is only allowed to change functions / methods code;
      • functions which works once (e.g., CONSTRUCT) and already was called, are not called again except you did not provide call of them in your code;
    • Starting from version 0.94.7, the /$INCREMENTAL key is supported for compiling to C# (but without dynamic code re-load into already running application: it is necessary to close it to start re-compiling changed classes and re-building/re-starting the application);
    • It is possible (starting from version 0.91.1) to set up TRAP methods on read, write class fields, and for array fields also on add, insert and delete operations with such field. It is also possible to access functions stack and its call counters (when the /debug option is on). This very useful mechanism to search and fix problems in algorithm: you set up a trap e.g. on writing a value into a field in its code e.g. print to the console an entire stack trace. This way you get a problem function name and its call counter at the moment when a problem occur and either analyze the function code or add additional debug print for such conditions. Using traps it is possible to short sufficiently amount of iterations and output information while debugging your code.
    • At last... - you have a code generated by the AL-IV compiler and it is possible to debug it using a target language debugger. By the way, section comments
      ------------------------- 'text'
      are copied (almost always) to the generated code, so these could be useful to search a neighbor code using these.

PART 2. AL-IV:    Creating GUI applications

 

Preamble. Programming an application with a visual graphics interface in the AL-IV is constructed the way allowing to write a single universal code for all the target platforms and depending on a selected compiler and a selected library of classes, to get in result an application for a certain "platform". Independently on a platform, a resulting application will consist of the same set of almost identical (by capabilities) visual and un-visual control items which always work the same way.

 

Some differences are possible though. In some environments a symbol '/' is used to divide directories, in others the symbol '\' is used. In one case a user makes a right click to pop-up a menu, in other cases he may be click twice or does something else. An exterior of a form can differ and even controls layout on a form can depend on a target device.

 

I.e. we develop an application in a convenient for a developer environment and then we specify in which target platform we want to get it working. And it is compiled for that platform though we did not change the source at all to adopt it to another platform.

 

Unfortunately there are also some  drawbacks:

  • we have to take into account a presence of all the desired components on all the wanted target platforms. For this moment, there are 4 platforms supported for GUI development (Delphi - VCL, Delphi - KOL, Delphi BDS with Firemonkey, C# - WinForms, Free Pascal - LCL).
     
  • we have to use a paradigm of visual forms and dialogs designing removing a programmer from a decision how much pixels should be sizes of each visual item and how exactly these should be placed relatively to each other.

 

2.1. Tree of visual and nonvisual components to develop applications 

 

 
 

All the standard visual items are direct descendants of a class {Control}. Below are their short descriptions, together with a comparison of it's analogues from target platforms on which these are (more often) are implemented.

AL-IV

C#

Delphi / FPC

Java (Android)

{Label} Label TLabel Label
{Button} Button TButton Button
{Checkbox} CheckBox TCheckBox CheckBox
{Combo},

does not allow to edit text, only to select a value

ComboBox TComboBox Spinner
{Edit} TextBox (Multiline = FALSE) TEdit TextView (Read only)/ EditText
{Memo} TextBox (Multiline = true) TMemo extView (Read only)/ EditText
{Listview}, only table style (detailed view) ListView TListView ListView
{Listbox} ListBox TListBox ProgressBar
{Progress} ProgressBar TProgressBar View
{Paintbox} PictureBox TPaintBox TextView
{Date_picker} DatePicker TDateTimePicker

 

 

Visual control items particularities are often results of a features of its correspondent mirrors components features and restrictions. If such prototype control component has a serious disadvantage in comparison to other such mirrors on other platforms, we have either to try to overcome this one or to lower our control functionality. And this last is anyway better way then to allow sufficiently different behavior of a control on different target palatforms.

 

In the table above the right three columns corresponding to target platforms contain comments on implementation on certain platforms.

 

E.g., for {Combo}: this item is not allowing direct text entering since on a Java-awt platform its mirror component has a correspondent restriction. In case of necessity of entering a value which is not present in a list it is possible e.g. to add an item to a pop-up list, named like "...another value" or "enter new" or something like. Or this can be implemented with an additional button or a pop-up menu or by just editing an additional field. This is not so hard problem anyway but makes implementation of the {Combo} much more easier. It is still a combination of two instances: a list of values and a field with a selected value.

 

Non-visual control items ({Dialog_file}, {Timer}, {Menu} etc.) are also derived from the class {Control}. Certainly, some properties of which are concerning to its location, size, etc. are just has no effect. For them, it is much more important their deriving from the {Control} and common implementation of its mirrors.

 

2.2. Form organization. Columns. 

 

Form is designed as two leveled [but see also an addition in the next paragraph]: form contains columns, which contain controls (buttons, labels, text fields, combo boxes etc.)

Actually it is possible that amount of nested levels can be more then two: form can contain a scrollable pane containing columns, as well as columns can contain scrollable panes, which has controls placed in those. (In case of a mobile application forms are represented by panels located on a form representing the application).

But these additional nesting levels are invisible for custom code, so for a programmer, this model stays two-leveled.

 

Moreover, columns also have no its own class and these are  controlled via form methods. It is not necessary to control too many parameters of columns though. Its layout is set once on creation. It is only possible to hide column, add or remove items on it, and change its size (but this last can be ignored in some target environments).

It is important to understand that an some target systems the exterior of a form can be different from the layout initially designed. E.g. in case of small smartphone screen, not all the columns can be visible together, and switching between them can be implemented using gestures, additional buttons or other ways.

 

If in a constructor of a form start creating controls without creating a column, the first column is therefore created as unnamed, 'CLIENT' aligned (occupying entire form until other columns are created).

If there are several columns aligned 'CLIENT' then only one will be showing at a time: the client column for which in the form event column_hidden, the result FALSE was returned.

 

 

Additionally, it is allowed to create "nested" perpendicular columns with alignment 'LEFT'/'TOP', 'RIGHT', 'BOTTOM'. When creating such column, the alias of the "parent" column is specified, which aligning should not be "parallel" to the "nested" column aligning (e.g. if the "nested" column aligned 'LEFT' or 'RIGHT', the parent column should not be aligned 'LEFT' or 'RIGHT' too).

Terms "nested" and "parent" are quoted still actually another nesting level is not created: the "parent" column is just used as an anchor, or basis, and its rectangle is cutting from the correspondent side to allocate the "nested" column during allocation process.

Note that on some platforms nesting columns is not supported and columns are placed directly on the form with the aligning specified (Android).

 

For a case of automatic controls placing:

 

For columns aligned to 'LEFT', to 'RIGHT' and to 'CLIENT', automatic placement of visual control items is implemented from top to bottom (it is also possible to specify aligning controls from the top to the bottom for horizontal columns, too). At that case horizontal sizes of controls are calculated automatically either to fit a control to a column width or to place it near to its label if a label size is allowing this. (And if a {Paint_turtle} component is created following the control, it is also placed in the same row aligned right).


A "label width" parameter (passed on a column creation via a {sizes_col} record) specifies a maximum label size for which a label is placed near the following control item. If a column width is greater then the width specified, then the label occupies the whole row and the following control is placed in the next row, below the label.

 

Only one visual item in a column is allowed to be resizable together with a column resizing (by height). And not all visual control classes are allowing vertical sizing (these are {Memo}, {Listview} and {Paintbox}). To apply such behavior to a control, it is necessary to make a call for it:
Set_anchor_bottom(TRUE)

 

For columns aligned to 'TOP' and 'BOTTOM', another placement rule acts: from left to right (or from right to left depending on user language locale) with a small gap between these. Vertical size for {Memo}, {Listview} and {Paintbox} in such columns can be set manually, and vertical size of a column is automatically adjusted to fit all containing controls.

An example of a column aligned top/bottom (schema):

 

For such horizontal "columns" it is possible to specify the property controlling controls placement: with the method Set_controls_layout({controls_layout}) or in the Form Designer. Possible variants:

'CONTROLS_LEFT' - all the visual items are placed from the left to the right. If the last control is of class {Edit}, {Compo}, {Paintbox} (or its inheritance) and has the flag set "Expanded right/bottom", then it occupies the rest of the column;

'CONTROLS_RIGHT' - all the items are located at the right side of the column;

'CONTROLS_CENTER' - items are allocated on the same distance from each other and from the column left and right sides (if there is enough space, otherwise similar to 'CONTROLS_LEFT');

'CONTROLS_JUSTIFY' - like above but the left and the right items are pined to the column sides without a gap;

'CONTROLS_LEFT_LAST_RIGHT' - the same as 'CONTROLS_LEFT' but the last item is located at the right side (if there is space in the column);

'CONTROLS_TOP_To_BOTTOM' - for a horizontal column, vertical controls layout is defined; in nost cases it is necessary to set up the column height manually to make visible all its controls;

'CONTROLS_VERTICAL_2|_COLUMNS' - works both for horizontal and vertical columns dividing them only the left and the right columns; first a half of controls are placed in the left side, from the top to the bottom, then the rest of them at the right side, also from top to bottom;

 

It is possible also to refuse from automatic controls placement calling Set_column_auto_arrange(FALSE), and place them manually by your code. E.g. in the form event resize. (But on some platforms such call can be ignored, and this should be taken into account).

 

2.3. Events handling 

 

There are not pointers to functions in the AL-IV. The are no delegates like in C# or listeners like in Java - these are too bulky way to handle events. The single way to handle events from visual controls in the AL-IV is in overriding correspondent methods of a form, e.g. click, key_press, mouse_move, timer, etc.

For cases of descending controls, some events are also called for controls. E.g. to handle mouse events.

 

Like all the methods starting from a lowercase letter, these methods are protected. These also are marked as CALLBACK, i.e. these are not designed to call it by your code. Though such restriction is not inherited in a derived class, protecting only the method itself from incorrect usage.

 

If similar events should be handled from several controls on a form, it is necessary to analyze a parameter sender. The best way to branch depending on a Sender is to place sender_alias to a CASE header. Alias is a short string label name of a control given to it at its creation, it should be convenient to refer to it at run time.

 

It is recommended complex enough handling of events take out from such CASE to separate methods, leaving only sufficiently short handlers there containing not more than several lines of code.

 

In case when it is necessary to combine into one place handling the same event from different sources (buttons, menu, keyboard etc.), it is better to use for that menu handler, calling it from all the alternative methods. (To avoid complains from the compiler about incorrect using of a CALLBACK method menu, move your code to a separate method, naming it e.g. "operation", and calling it from event handlers like menu, click and others, passing necessary parameter to identify an operation called).

 

It is possible to simplify developing forms/dialogs if to use classes {Form_common}/{Dialog_common} in place of basic {Form}/{Dialog}. These two classes automatically handle some events like control keyboard keys presses and mouse clicks, selecting and scrolling with mouse wheel for {Paint_table}, {Paint_tree} and {Paint_line}. Also these are simplifying adding hints showing on controls under the mouse cursor and allows to provide the same custom colors for all the forms/dialogs in a project. And its functionality also can be extended as well.

 

2.4. Disabling / hiding controls 

 

It is not possible to disable or hide a visual item immediately calling a method of a form or a visual control item. Hiding is performed on results of calling back a form event (i.e. an overridden form method) hidden, disabling - by calling an overridden method disabled. An overridden method should return TRUE, if for some case a control item should be disabled / hidden. This methods are called after each important event such as text editing, combo box selecting or other value change. If this is not enough, it is always possible to call a method of a form Any_change (where methods disabled and hidden are actually called).

 

The disabled method is called only for those visual controls which were added to an array grayable[]. Similarly, method hidden - only for visual controls present in an array can_hide[]. It is better to add interesting controls there in the form CONSTRUCT method. (While visual designing a form, this is done setting a checkmark "Can be hidden/disabled").

 

Controlling visibility of columns is very similar, but it is done by overriding a method column_hidden. Its single parameter is a column alias, assigned to a column when it was created. And this method is always called for each column on a form (there is no special array of columns to list such can be hidden at all).

 

2.5. Pop-up menu 

 

In the AL-IV it is suggested to use only pop up menu. To simulate a main menu it is possible to use a column with buttons aligned 'TOP' in which pressing a button leads to a correspondent popup up menu show.

 

A menu is created on base of strings separated by end line symbols (#NL). You can prepare such string as a constant or create it dynamically in a calling point (or in a special function if you wish).

 

String lines used to specify menu items consist of a menu item and menu text colon separated. If there is no a colon symbol (':') there, then the entire text is used as an alias of the menu item in such case (it is not recommended to do so, since you later can provide a string localization, including a menu items localization).

It is possible to write additional attributes "disabled" and/or "checked" comma separated between the menu item alias and the colon.

E.g. calling a traditional file menu for a "File" button (in a "main menu" made from buttons):
 

 popup_menu(@
    "OPEN:Open"
    "SAVE:Save"
    "SVAS:Save as..."
    "-"
    "PRNT,disabled:Print"
    "PRVW,disabled:Print preview"
    "-"
    "EXIT:Exit")

 

A line which is specifying a menu is passed to a function popup_menu, which shows the menu created. At that point currently working handler should finish its working. A control flow will return to a program when a callback-method menu_item representing a menu handler is called in response to menu item click (or press it by a keyboard). A point on a screen where a menu is shown depends on which mouse (or other) handler was called last time. E.g. it case of a click method it is a bottom left corner point of a button (or other control item) clicked.

 

In an event handler it is better to analyze (using the CASE statement) a string representing a menu item name (CASE sender_alias ? ...) to branch depend on which item was fired.

 

To make it possible to create / edit menu with the visual Menu Editor (which is a part of the Form Designer), it is suggested to use functions from the class {Menu|_create}. When using them, the menu above will be looking like following:

 popup_menu(
    "" Item(  "OPEN",
              "&Open" )

    "" Item(  "SAVE",
              "&Save" )

    "" Item(  "SVAS",
              "Save &as..." )

    "" Separator

    "" Item(  "PRNT",
              "&Print"
       ).Disabled(!can_print)

    "" Item(  "PRVW",
              "Print pre&view"
       ).Disabled(!can_print)

    "" Separator

    "" Item(  "EXIT",
              "&Exit"  ) )

 

 
 

An additional feature from using the menu designer: such menus are drawn below the form scheme, allowing by mouse double click to go to the menu item handler in the code (in the IDE).

 

2.6. Canvas painting 

 

A form can contain (in a column as usual) a visual item intended to paint (or several such items). Painting is preformed only in a method paint of a form using its object Canvas of a class {Canvas}. Actually painting is performed on a buffer bitmap ({Bitmap} class, designed to paint and to store raster images), and a result is copying onto screen after painting. This reduces amount of flicks while redrawing forms.

 

Similarly, painting can be done on any {Bitmap} object, also though its object Canvas of the class {Canvas}.

 

All the coordinates on AL-IV forms are measured in points rather then in pixels. This provides an independence from a screen resolution, providing sizes of items proportional to a selected font scale.

 

On a {Canvas}, also points are used by default, but using an opened field Units it is possible to specify other units (pixels, centimeters, inches).

 

A canvas has a set of methods to draw graphic primitives using current colors and font, pen and brush styles. E.g., Erase, Rect, Line, Ellipse, Arc, Text, Poly. Also it is possible to perform affine transformations such as Scale, Offset and Rotate. A function Reset_transform removes all the transformations.

 

Before the painting function paint is called to paint on a canvas of a {Paintbox} control, all the transformations are reset.

In comparison to other programming environments this can seems strange but out of the paint method, property Canvas of the class {Paintbox} contains NONE (so any painting commands will be ignored out of the paint method call). This means that painting is allowed only when the system decides that painting is required for a control. E.g. when the control is resized or an overlapping window was disappear or moved. It is possible to call Invalidate_all for a {Paintbox} control but this will not to lead calling the paint immediately.

A class {Paintbox} allows scrolling of a content which is greater then the visible area of the {Paintbox} control. The visibility of the vertical/horizontal scrollbars can be defined only on create it. On base of the {Paintbox} other components are created: {Paint_tabs}, {Paint_lines} (and its descendents {Paint_table} and {Paint_tree}), and {Paint_turtle}.

 

2.7. 3D visualization ()pen GL)

 

The {OpenGL} class can be used to call functions of the Open GL machine in the style very close to classic. But values of constant parameters are controlled on the compiling stage. For example, while calling the function glEnable it is possible to pass only one of constants, acceptable by that function (e.g., GL_BLEND, GL_LIGHTn, GL_TEXTURE_2D and so on). But on an attempt to pass something not allowed, the compiler will report an error.

To work on mobile platforms the Open GL ES (Android) modification is used, in which some basic functions are not supported. Therefore, the {OpenGL} class supports working of functions glCallList[s]/glNewList and its accompanions, and also glNewQuadric/glSphere/... - in the simulation mode. So the lovely examples from an introductory books should work as usual.

 

An example of using of the class {OpenGL} is in the sample project Test_visual_projects\Test_OpenGL.

 

2.9. Long operations handling

 

In difference to the most of the programming languages, the AL-IV make special efforts to prevent a possibility of an infinity loops (as well as an infinity recursion). In part, there is only one kind of the statement which allows an infinitive looping (FOR INFINITE), and using it is a subject for penalties (it is necessary to specify the modifier INFINITE for a class using such kind of statements).

But this is not all. A sufficiently long loop can be created as a result of several nesting loops, for example. So, in each FOR loop statement on each iteration the special global counter is increasing. And each time when it achieves 65536 value, the system function check_long_operation is called. It resets the counter and analyses the presence of attached handlers.

The handler attached by default in visual applications, provides automatic showing of the progress of a long operation started in case when the application becomes working hard under some calculations and stopped responding onto events. The dialog is appearing after 3 seconds of unavailability to respond onto events, and it is automatically closing when the application returns to the normal state.

If a developer did not take any efforts to show a progress of a long operation or to describe to a user what is doing there, the dialog is looking boring a bit, just showing the name of an event which was called last before the application hangs responding. And also it has two buttons allowing to pause the process (to free the processor or just to cool it a bit) and to cancel working under the long operation started (if the user has no any hope to await finishing it).

To provide a progress visual moving and to describe what is doing for the user and the stage of working it is sufficient to include in the import section a reference to the class {Long_operation} and to call methods of the property Long_operation of the form: Set_description, Set_stage, Set_progress. The form is looking and behaviors same way but showing what was specified in these methods.

 

Certainly, all the functionality if it is not used or is not desired on some reasons can be easy turned off adding the option /$NOLONGOP to the compiler options.

 

The sample of using the class {Long_operation} can be found in the demo application "100" using hard calculations to find combinations of mathematical operations between given digits which lead to the specified resulting value (by default, 100).

 

PART 3. Development environment: source editor IDE AL4

Compiling IDE AL4 editor

 

Unpack IDE_AL4.zip providing the folder IDE_AL4 to be nesting into a root folder AL-IV.

In Windows (XP, 7, 8.x, 10): open IDE_AL4 and run the command file _compile-C#.cmd. If a framework .NET required is installed, the project will be compiled, and resulting exe file can be found in the folder IDE_AL4\Compiled.

If it is not possible to install a required .NET framework version, you can install Delphi 7 (32 bit version), configure it as it is described in instructions, and then compile IDE AL4 using the command _compile_Delphi.cmd. In such case, resulting executable file can be found in the folder Compiled_Delphi.

The same way, for other possible target compilers (Java, C++, Python, ...). Though using IDE compiled for another version then C# / Delphi can be labored since low speed of gfraphics / strings handling in such target environments.

 

At the end of compiling resulting executable can be moved, copied, launched as usual for executables.

 

It is also possible to compile IDE for OS Linux, and even without using Windows. Follow instructions on configuring Lazarus+Free Pascal compiler in Windows / Linux, then call correspondent command files to build IDE AL4 using Lazarus (_compile.sh, _compile_final.sh).

 

Starting from version 0.92.7, the visual Form Designer was added to the IDE AL4.

 

Localization of IDE AL4 editor

 

To provide switching to a desired language of the interface, copy language files (with the extension .lng) to the same directory where the executable is running from. Then, after re-running the IDE, an option View \ Select language in menu allows to select a language from the list.

The author is providing Russian language translation (by default, the English is the interface language). It is possible to prepare a language file for any other language. If you have such ability (and time), you can send a language file prepared to provide it in the IDE distributive.

 

Specific features of code rendering in IDE AL4

Functions, methods headers and other declarations of a class level are shown using doubled font. To provide this feature working for a header, it is necessary to satisfy several requirements (additionally to just turning on the correspondent option in the "View" menu of the IDE), namely:
  • A previous line of code should be empty (enlarged text is using part of the previous line to be rendered);
  • A line of code (without trailing spaces) should not be larger then 40 characters (including the first spaces, where the first tabulations are replaced to spaces first);
  • Current position in text, current selection in text are not intersecting the line with the large header, and it not contains a phrase highlighted together with a current selection in text.
 

Colored lines are drawn from the block header to the block ending line showing its nesting level and completeness. Lines are drawn at the right side to avoid incorrect interpreting indentations at the left side.

Colors for nesting CASE / FOR statements (and its lines) are always in the order (in light colors scheme: LIGHT-GREEN, BLUE, BROWN, OLIVE). Colors and view style for nesting PUSH / DEBUG statements are another and mixing, so it is always easy to find that amount of nesting levels become too deep to be satisfying to basic code writing requirement (not more then 3 nesting CASE / FOR blocks, with possible 4th level which can contain not more then 1 simple statement).

An absence of a line between the start and the end of a block can be used as an indication that something is wrong in code (not enough or extra symbol ';' ending a block). To provide lines for a block, it is necessary also to satisfy additional requirements, such as:

  • It is desirable (but no obligated) that all the nesting statements have larger indent (but in some cases this can be ignored, e.g. in case of several nesting PUSH statements),
  • ending symbol ';' should be located either at the end of the last nesting statement or (if it is starting a separate line), leading spaces / tabs must be exactly the same as for a starting line of the block statement (and the symbol '.' ending the function or a comment to end of line starting from '//' still can follow it).

 

Specific text editing operations

 
  • By pressing CTRL+/, a block of code (starting in a current line) is commented / uncommented by adding / removing symbols // at the start of each line of the block, together with nested blocks if any present. The main purpose of such operation is quick commenting / uncommenting DEBUG blocks. It is conveniently in many cases not to remove DEBUG blocks, but just comment it, allowing to use these in future.
  • Searching by a pattern operation (CTRL-F / F3(forward) / F2(backward)) has additional options: "Ignore spaces", "Skip comments", which allows (i.e.) to search fast only not commented DEBUG statements, and others.
  • An operation "Insert recent" (Ctrl+Shift+V) is simplifying multiple changes in code, when it is necessary to insert different patterns of code in different places (e.g. at start and at the end of some blocks of code). Or, it is possible just to copy different portions of code in different places, and then paste them together in another place or separately in other places of code without jumping back again several times.
  • A CTRL+' operation allows to remove surrounding quotations for a block of code, which consists of quoted strings. Or, contrary, to enclose each line of selected code into quotas. This operation can be useful to transform native code from using it in a separate alien code or as a multi-line string literal in a native function.
  • After some changes in a current line, at the bottom of the edit window a hint can be displayed : xxxx ==> yyyy. If you press CTRL+R at that time, the replacement dialog is shown with values set: what to search = xxxx, replace to = yyyy. This can simplify mass renaming operations (including a restriction: only in the current function).

Navigating and getting help on functions, methods, etc.

  • Jumps to symbols definitions (CTRL-ENTER) defined in the same class are available always, even without opening a project. Navigating back (CTRL-<) and forward (CTRL->) are available always also.
  • It is possible to get hints on classes which are not loaded now: to do so, just build indexing on those classes (menu command File | Index classes). Then, select a directory which is root for all the classes indexing. E.g. to index all the library classes of the AL4, select AL4\Library. And certainly you can index classes of your own projects this way.
  • Indentation in code with TAB and SPACE and with SHIFT+TAB/SPACE.
    To change indentation on one tabulation, you should to select some text and press TAB (or Shift+TAB - to decrease indentation). To indent by one character position right/left use SPACE and Shift+SPACE. For lines of code enclosed into "quotation" or ''double apostrophes'', this indents the code in quotations without (if possible) repositioning such quotation marks.

 

Debugger with the embedded debugger


 

  • The embedded debugger is working only for projects prepared with Delphi (using VCL or KOL) or with Free Pascal (Lazarus). But launching a compiler and watching compiler messages in a GUI window works also for C# projects.
  • It is necessary first to "open a project" by the command File | Open Project. A project is a command file used to compile an AL-IV project with a correspondent compiler (and to run it if the key /run is present).
  • After that commands become available:
    F8 - compile+run (if already comoiled, the debugger command "Step over" is executed);
    Shift-F8 - compile(always) + run;
    Ctrl-F8 - compile and run w/o debugging;
    Ctrl-Shift-F8 - compile w/o running the project;
 
 
 
 

 

APPENDIX 1. AL-IV: Command files magician running a compiler

Configuring running a compiler

Let's see how command fileas are working on a certain example. In the directory A4\Test_projects\_Hello_world you can find a file _compile-C#.cmd. It contains:

%AL4%\AL4\CSharp_build\AL4CSharpCompiler.exe /run /op - /@ %AL4%\AL4\Test_projects\_Hello_world\compile-C#.txt

pause
 

The first path is a path to the compiler. It can be different depending on a target language to which your project is compiling by the command. To compile to C# (as in the example selected) the AL4CSharpCompiler.exe is used, to compile to the Delphi-Pascal - AL4DelphiCompiler.exe, etc. (and each such compiler is distributed in its own directory).

Then key options are following. The most important option is /@ path-to-configuration-file.

In such configuration file the rest of options are located. It is possible to place there all the keys, and keys in the configuration file will cover earlier applied keys in the command line (but if the command line contains key options after /@ path, then such options are applied later and have more weight then option in the configurations file). 

Let's look at configuration file now.

 

1

2
3
4

5
6
7

8
9

10
11

12

 

Hello_world.al4

/src %AL4%\AL4\Test_projects\_Hello_world
/src %AL4%\AL4\Library
/src %AL4%\AL4\Library\_CSharp

/ext cs
/ext2 al4
/v

/dst %AL4%\AL4\Test_projects\_Hello_world\Compiled
/prj Hello_world

/$REPORT_LEAKS=
/RUN

#/op -
 

And let us describe now.

 

1 - input file name. It is necessary to specify either a full path  (may be using environment variables in %...%), or just a name of file (but in such case a full path to the source directory should be added via a key option /src like in the example above).

 

2, 3, 4 - key /src path - specifies a list of paths in which the compiler should search for imported classes:

2 - a path to the project itself. It should be specified always, either with a key  /src, as in this example, or while specifying the main input file of the project.

3, 4 - paths to used library classes. These can differ depending on a target language / framework / OS. E.g., in this example:

4 - path to native classes specific only for C#. In case of another programming language it should be changed. E.g., for Delphi-VCL, this path should be replaced onto two following paths:
%AL%\Library\_Delphi
%AL%\Library\_Delphi\VCL

 

5, 6 - keys /ext, /ext22, /ext3 specify the main and additional extensions to search source files for classes. For the AL-IV itself, default extension is al4 (and it is not necessary to specify it). For a native class it is convenient to place AL-IV code into the source written on a target native language (enclosed into /* ... */ symbols).

 

7 - key /v specify a bit more detailed verbose output for the compiler (it is possible to add /vv for maximum verbosity).

 

8 - key /dst path - specify a apth to place output files. To compile tests, a string \TEST$ is added to the path specified. In case of success building, a resulting binary file (if any provided) can be found in the destination directory. As well as source files on a target programming language generated by the compiler.

 

9 - key /prj - allows to specify a project binary file name. It is not necessary, by default a name of the main input class is used.

 

10 - key /$REPORT_LEAKS= - is specific for the compiler version (but now it supports by all the versions). It is used to generate a report on objects created and destroyed in the application while executing.

 

11 - ./RUN - the compiled application will be run.

 

12 - /op nnnn - controls code optimizations. In case  /op - - all optimizations are off. In the example the line is commented with starting '#' symbol, so optimizations are on by default

 

 

There are some other keys, there keys of form /$LLLLLLLLL are depending on the compiler version. A list of main key can be obtained running the compiler in the command line without parameters.

For that time you see that there are no any magician here. If you want to create new project, uses some existing test application, copy its files and configuration files, edit it, replacing paths onto correct for your application paths, names onto your names and run the command for compiling it.

An advice: to debug, use a target language which is compiled quicker (like Delphi). After debugging/testing switch to more slower compiler like C++. 

 

APPENDIX 2. AL-IV: Gradual switching to AL-IV in an existing project

(not finished)

Formulation a task to migrate to AL-IV

 

Suppose we have an application created with Delphi + VCL or Delphi + KOL, with a lot of forms and code attached to them. And for some reasons we desire to move all such project to AL-IV (e.g. we want to provide running it on Linux or supporting of Delphi become stopped on modern computers or others). But to convert to AL-IV all 10 (or more) forms together with its code is not possible. Let us do it by another way.

 

Solution: change th AL-IV syntax to the Pascal-like

 

Starting from the version 1.3.0, the AL-IV supports the Pascal syntax. This means that the AL-IV compiler accepts Pascal classes though with some restrictions in syntax and semantics. The first we should place at the start of the Pascal unit the following 5 lines:
(*
/*
     [SYNTAX="PASCAL"]
*/
*)

 

After that the usual Pascal code should be located starting from the unit directive with the unit name as usual for Pascal code, and ending with the directive end with the dot. And it is possible to just add the comment above to the ordinal Pascal (Delphi) unit and try to pass it to the AL-IV compiler as an input.

 

Unsupported statements

 

But in the most cases the first attempt will not be successful, since the AL-IV compiler understands not all the Pascal syntax. E.g., following things are not supported:

 

- the do ... while statement;

- the with ... do block;

- arrays of arrays;

- redefining data types on base of already defined data types
type x = y;

- global variables;

- constructor parameters (these are just ignored with firing warnings);

- several classes (with methods) in a single unit [since the AL-IV unit is always a class already, and all other classes must be just STRUCTUREs];

- optional parameters and parameters with default values;

- arrays constructed enclosing into square brackets a list of any expressions;

- constant arrays in the AL-IV always should be indexed from the 0 unlike the Pascal where any integer number can be used to start from (or even a enumeration type can be used or Boolean to index items);

- the are no properties with several indexes;

 

Strong AL-IV rules in the Pascal code

 

Also, some strict rules of the AL-IV continue working (though some of them made ease). E.g.:

- a line of code (not accounting comments) should not exceed 80 characters length;

- a sequent code block can not contain more then 7 simple statements and 7 block statements, in other case the block should be separated with the operator comment statement (in case of the Pascal syntax it is written in form
{@------------------------------- 'label'}

- there are no var parameters in the AL-IV and all other parameters should be used as read only in functions (so the code which do not satisfy this requirement must be rewritten);

- names of fields, functions, constants should not be less then 8 characters length, or these should be extended in form (e.g.):
Name{|extended_name}: type1;
function Foo{|_douing_something}(...): type2;

 

Ease AL-IV rules in the Pascal code

 

For the syntax like the Pascal following ease rules are introduced allowing to use the Pascal with a minimum code conversions:

- case insensitivity for names of functions, variables, data types etc.;

- there is not a restriction on a nesting level for statements (if/case, for/while);

- it is allowed to not specify Clone/Dismiss while copying structures (records) - always cloning is used in such cases;

- it is allowed to assign values to fields and "methods" having a setter defined (very similar to Delphi properties);

 

 

 

Manual Pascal to AL-IV code conversion: conditional compiling

 

Sometimes it is necessary to write two versions of code: for usual Delphi or Free Pascal and for AL-IV. And, in case of the AL-IV, it can be desired to write code directly using AL-IV language, not the Pascal.

 

For case of the AL-IV, the construction is used
(*$ifdef al4code*)
    ... write here code for the AL-IV on the AL-IV language
    e.g.,
    DEBUG: << "We are here"#NL ;
(*$else*)
    The Pascal code for the previous Delphi/FPC (optional)
(*$endif*)

 

For the Pascal special code (or if the Pascal not needed at all):
(*$ifdef al4*)
    ... Write code on the Pascal - it will be converted to the  AL-IV and compiled with the AL-IV compiler
   ... Or do not write any code, if it is neccessary just to comment the Pascal code in the else branch below
(*$else*)
    ... The previous Pascal code leave here
(*$endif*)

 

Notes:

  • Comments of form (*$...*) must be used to write such conditional directives, rather then {$...} (which are totally ignored by the AL-IV compiler and can be freely used in (*$else*) branches);
  • Directives (*$...*) can be written using any letter cases but the space between ifdef and al4 (or al4code) must be single, and spaces between stars and letters are not allowed;
  • Directives (*$...*) must be written in separate lines of code;
  • The branch (*$else*) always can be omitted.

 

Manual Pascal to AL-IV code conversion: form transformation

 

Programming with the Delphi in most is perpendicular to the AL-IV (and not only in the Delphi), and in case of the visual programming the situation looks even deeper: there are no above the very bacsic set of controls, it is not possible to lay these on the form as desirable, handling events is very different, etc.

But all (or almost all) can be solved.

 

First: you will need not panels: AL-IV columns are not just replacements for them. So, it is better to hide these from the AL-IV compiler using directives (*$ifdef al4*) moving its declarations to the (*$else*) part.

If your form has not yet a constructo, create it. In its body, int the directive (*$ifdef al4code*) write creating columns and controls using AL-IV syntax directly.

Certainly for all the control types used on a form it is necessary to find a nearest replacement. And if there are no such replacements  then it is necesseray to re-write Delphi code to use another types of control having such analogues in the AL-IV.

E.g. in the project below (Glazomer - Eye-measure), 5 components of type TShape was used on the panel to click on these selecting correct answer. This part of code was first re-written to use single TPaintbox, and a list of TShape controls was replaced with the array of 5 rectangles.

 

The Delphi form events usually are written for each control as a sender and for each kind of an event, whereas in the AL-IV  only one function for each event kind is used in the form code (and certainly in this event handlers final functions can be called different for each sender if it is necessary). So, create a block of code on the unit level protected with the directive (*$ifdef al4code*), and place there handlers of the AL-IV form, redirecting handling of events onto correspondent procedures already written in Pascal. E.g.:


(*$IFDEF AL4CODE*)
OVERRIDE paint :
  CASE sender_alias ? ["HOUSE"]: House.Canvas.Units = 'PIXELS'
                                 HousePaint(THIS)
                      ["TESTS"]: Tests.Canvas.Units = 'PIXELS'
                                 TestsPaint(THIS) ; .

OVERRIDE mouse_down :
  CASE sender_alias ? ["TESTS"]: TestsMouseDown(THIS, mouse_button, 0,
                            X= Tests.Form_X_points_to_Control_pixels(mouse.X),
                            Y= Tests.Form_Y_Points_to_Control_pixels(mouse.Y))
                      ; .

OVERRIDE mouse_double_click :
  CASE "kol" IN Platform_info.Lower ? mouse_down ; .

OVERRIDE click :
  CASE sender_alias ? ["MORE"]: ButtonMoreClick(THIS) ; .

OVERRIDE timer :
  CASE sender_alias ? ["ANIM_T"]: AnimationTimerTimer(THIS) ; .
(*$ENDIF*)

 

If a drawing is used on a canvas, then it is necessary to take into account that in the Delphi, the pixel is used as a unit, but it the AL-IV  the point is used by default (but it is possible to switch using other units and pixels too among them). While calling a draw procedure for a TPaintbox, units of a Canvas are switched automatically to pixels, but in case of drawing on a bitmap canvas, you should do it by yourself.

The same is for mouse events: Delphi procedures want working with pixels whereas the AL-IV stores mouse coordinates in points and not from the sender control corner but relative to the form client area top-left corner. Still working with the mouse is not so wide-spread, convert coordinates by yourself in such events calling correspondent functions from the Delphi2AL4.pas unit.

 

Manual Pascal to AL-IV code conversion: global variables

 

There are no glbal variables in the AL-IV programming language, and the var statement on a unit level is not allowed in the code converter. To work same way in both versions of the code (in the previous Delphi project - a bit modified, and in its AL-IV-compliant mirror), it is necessary to move all such variables to the main form (making these its fields).

Suppose the main form is named as fmMain. In such case in the Delphi project migrating all the references onto global variables should be rewritten as fmMain.SomeVar. Particularly in case of a child form named fmChild1, we will refer to it as fmMain.fmChild1, obviously.

To allow in context of methods all the forms to recognize the identifier "fmMain" as the reference  onto the main form and not to go on the long way (* - see below), it is better to do following:

to define in the main form a function which name matches the main form name (in our example: fmMain). This must be the FUNCTON, not the METHOD (I think you should understand why). To avoid creating native classes for each possible target framework/compiler its own version which extract the reference onto the main form, just write in the body of the function created following code:

In case of the AL-IV code:
FUN fmMain|_form ==> {Fmmain} := Get_main_form.{Fmmain} .

In case of the Pascal code:
function fmMain: TfmMain;
begin
   Result := Get_main_form as TfmMain;
end;

 

(*) The long way could be in:

- creating a local variable named e.g. fmMain_ in each form;

- writing a function fmMain in each form returning value of such variable;

- and adding in all the points where such child forms objects are created additional assignments of the reference onto the main form to that local variables fmMain_.

Ant this way is not only long but it can lead to errors if you forget e.g. make such assignments in some cases.

 

   

Content

 

PART 1.   AL-IV:     How to start programming

PART 2. AL-IV:     Creating GUI applications

PART 3. Development environment: source editor IDE AL4

APPENDIX 1. AL-IV: Command files magician running a    compiler

APPENDIX 2. AL-IV: Gradual switching to AL-IV in an    existing project

Content

 


Home