Since patch 2.5 is finally out, I decided to release a little tutorial on menus I wrote some time ago. It will especially describe the new menu commands coming with patch 2.5.
To fully understand this tutorial you should at least know how arrays work, because they are the basis for menus.
Other than that, there is not much to know.
- 1. lib.scrat.format
- 1.1. Files:
- 1.2. Purpose
- 1.3. Example usage
- 1.4. Arguments
- 1.5. Detailed information
- 1.6. Performance
- 1.7. Dynamics
- 2. lib.scrat.expand
- lib.scrat.format.xml.zip (contains the following script file: lib.scrat.format.xml)
This library formats input data for menus. The input is an array of arrays which can either represent rows or columns and the library outputs a menu array, ready to be used in a custom menu. The advantage of this library over the manual approach is, that you have to specify your column format only once and it will automatically be applied to your input data. Additionally your code becomes more compact and less error prone.
1.3. Example usage
|arrays||Var/Array||Array of arrays, which hold the rows or columns to be formatted||None|
|column format||Value||Describes how columns should be formatted||Left aligned with calculated widths|
|format||Var/Number||Describes format of input data||Row major|
|menu type||Var/Number||Describes for which menu type the input data is formatted||Small menu|
|page ref||Var/Number||Reference page id for integer entries||None|
1.5. Detailed information
The library takes an array of arrays as input. Each array can either represent a row (as seen in the usage example) or a column.
1.5.2. Column format
The column format can be specified either explicitly or implicitly.
To explictly tell the library how the columns should be formatted simply pass it an array of integers with the formatting values. The library then will use these exact integers to format the menu. This way of formatting a menu can be seen in the usage example above.
There are two ways to implicitly format your menu. The simplest is to pass either
-1 to the library, where
1 means that all columns will be left aligned and
-1 means that all columns will be right aligned. The widths of each column will be calculated by the library depending on the texts that each column will hold. This algorithm is not heavily tested so might not always produce perfect results.
The second way to implicitly format your menu is to pass it an array of just
1 stands for a right aligned column and
-1 for a left aligned one. The width of each column will again be calculated by the library. If you don't supply only
-1s the library will use the array as an explicit format array. Following are two examples of implicit formatting:
1.5.3. Input format
To distinguish between row major (input arrays represent rows) and column major (input arrays represent columns) you have to specify an integer, which is either
0 means that the input arrays represent rows,
1 means that they represent columns.
1.5.4. Menu types
Since there are two different custom menu types (normal and info) the library also has to consider those. This is done via the fourth parameter. Passing
'menu' to the library will make it use the width values for normal custom menus, passing it
'info' makes it use the width values for the info menu. This argument is of course only considered if the menu has to calculate the widths of each row by itself.
1.5.5. Item types
As you can see in the usage example normal menu items are created with their return value as the first array item and then the texts for the columns. In a similar manner all other item types have to be specified. All item types are supported of course and can be specified as stated in the following overview.
To put the above structure in words, the menu item has the return value as the first array element and the texts for the columns in the following elements.
In words: The info line has as the first element the string
'info' which is followed by the texts for the columns.
The section is simple an array of one element containing the string
|Content||text1...textn-1||[value array, default, return id]|
Since the value selection has the most complicated structure, it deserves a longer explanation.
The first element is either
'valsel'. The elements from 1 to n-1 are the texts for the columns, as in the other item types. Note that there is one text column less in a value selection since the last column is used by the selection. The last element of the value selection array should be known to you from the built-in command to create value selections. Here
value array holds the values which are displayed and which can be chosen by the player,
default is the default index into that
value array and
return id is the return id which is part of the return value of a menu containing a value selection. These three things packed together into an array make up the last element of the whole array.
As you see, creating a value selection for the library is not harder than creating one for the built-in command - you have to create the same data, but pack them differently.
1.5.6. Page Ref
Setting up the input array can get cumbersome, if your menu contains many texts from a text file. To avoid this, I recently added this parameter, which allows you to specify a reference page id for text lookup. Thus, if any element in the input array is an integer the corresponding text will be fetched from the specified page. Note that the script doesn't load any textfile. If the page doesn't contain a text with the given text id, the text will not be loaded, so you won't get ReadText errors.
For the best performance, the input data should be in row major order and the column format passed explicitly. Like this, the library will perfom merely more than assembling column format and input data together into a menu array. If the input data are in column major order, the library first has to transpose it into row major order, but even for large menus this turned out to be reasonably fast. Only if the library has to calculate the widhts of the columns by itself it can take considerably longer, depending on the size of your input data.
The library doesn't support dynamic menus directly. As you can see in the usage example, the input data are in a different format than the output data. Thus the library has to copy values from the input array into the ouptut array. So a change to the input array after it was passed to the library, will not change the contents of the output array. Of course you can still use the output array as a dynamic array, since it is a normal menu array. E.g. you could let the library build your menu once in a setup script and use it dynamically afterwards.
- lib.scrat.expand.zip (contains the following script files: lib.scrat.expand.add.xml, lib.scrat.expand.open.xml, lib.scrat.expand.monitor.xml, lib.scrat.expand.open.xml, lib.scrat.expand.remove.xml, lib.scrat.expand.todefault.xml)
This library allows you to add dynamic content to your menu in form of expandable value selections, which change the menu when the user changes the selected value. For every possible selection you can add a sub-menu which will be displayed after the value selection when the user selects the corresponding value.
2.3. Example usage
The usage is as simple as it gets. Unfortunately, as it is always the case with dynamic menus, the examples tend to be a little longer, so I won't explain the example here, but offer a working example script which can be tested ingame. This example script will create a menu with an expandable value selection. It therefor also uses my other menu library lib.scrat.expand. You can download the script as part of the lib.scrat.expand.zip package under the "Files" link above. Below, you see the test script in action:
lib.scrat.expand consists of four scripts, but as a user of the library you'll only need to work with two of them.
To facilitate adding an expandable menu selection to your menu this library script can be used. As you can see in the code itself, the script doesn't do very much. It simply adds two entries to a normal value selection, which are used by the library.
|to menu||Var/Array||Menu the expandable value selection should be added to|
|text||Value||Text that should be placed in front of the value selection|
|value array||Var/Array||values that are displayed by the value selection|
|default||Var/Number||Default index into the value array|
|return id||Var/String||string which can be used to identify the value of a value selection in the return value|
|insert array||Var/Array||Array of arrays where each array represents one sub-menu|
The first five arguments are the same as in the built-in command. Only the last argument requires a bit more explanation.
As you can see in the example usage, when you change the value selection the lines below it are changed aswell. These lines are simply normal menu arrays, which is why I'll call them sub-menus. For each value in the value array there can be one sub-menu in the insert array. When you have the second value selected in the value selection, below the second sub-menu will be displayed.
The real work is done in the script lib.scrat.monitor. It has to run while the menu is opened to change the menu content dynamically.
|menu array||Var/Array||Menu whose value selections can be expanded|
|global var||Var/String||Name of the global variable which makes the script finish|
Since the library runs parallel to the menu task, it has to know when to stop. Therefor a global variable is used, which has to be not-false as long as the menu is opened. This script doesn't need to be used directly, since I recently added a helper script, which handles opening and closing menus with expandable menu selections.
This script handles menus with expandable menus selections, without the need to keep track of global variables for yourself. Its interface resembles the built-in
open menu commans. Since I expect anyone working with this library to have used the built-in menus before, there should be no need for further explanation of the arguments.
|title||Var/String||Title of the menu|
|description||Var/String||Description of the menu|
|option array||Var/Array||Menu array|
|as info menu||Var/Boolean||[TRUE] to open menu as info menu, [FALSE] otherwise|
Helper script to reset all expandable menu selections of a menu to their default column.
|menu||Var/Array||Menu array to reset|
As it is always the case with dynamic menus, the contents of the menu will only update once per second. It may thus sometimes seem as if the menu needs a little time to load the new sub-menu, but actually that's just the window system and there's nothing we can do about it (at least I don't know how).
The menu preserves arrays as they are and it simply inserts or removes them from the menu array. Thus, you can manipulate the input array and the menu will change with it.
This tutorial and the included scripts were written by ScRaT_GER from the Egosoft forum. Originally, it has been published in the X3: Terran Conflict Scripts and Modding forum in this topic after the release of Update 2.5 for X3: Terran Conflict. Due to the unavailibility of ScRaT_GER's website, where the tutorials and files were hosted, it has been slightly adjusted and republished in this wiki now. X2-Illuminatus