Tutorial

XML Gauges

Contents
Related Links

XML Gauge Tutorial

The ACE resource tool can be used to build a number of components for Prepar3D. The term gauge is used to describe all the instruments in an aircraft's cockpit. This tutorial goes through all the steps required to add a panel to an aircraft, and add existing and new gauges to that panel. The tutorial also covers creating a cabinet file for the gauges, and finally testing them.


Preface

This tutorial will demonstrate the following implementations for the basic Mooney Bravo aircraft:

The artwork for these gauges is considered placeholder art. Any images can be replaced later with more aesthetically pleasing images once the gauge mechanics are functioning correctly.


Step 1: Setup

The building and testing of gauges requires a lot of trial and error, so it is a good idea to set up the tools required to be very convenient for frequent use. The following set up makes the test process reasonably quick:

  1. Check to ensure that the ACE.exe tool runs from the following folder:
    SDK\Panels Gauges User Interface\Panels
    It requires the simpropace.dll, which should be in the same folder, and the latest version of the DirectX® 9 runtime. Close the tool for now, it is not needed until Step 4.
  2. Create a directory, under Documents, called something appropriate like New Gauges.
  3. Create a subdirectory of New Gauges, with the name Test Gauges. Place the cabbing tools handy (see the Creating Cabinet Files documentation), perhaps under New Gauges, but not under Test Gauges.
  4. Have the artwork creation tools handy, though for this tutorial Paint will suffice.
  5. In order to receive run-time error messages on gauge scripts, add the following line to the [Panels] section of the Prepar3D.cfg file (found in the %APPDATA%\Lockheed Martin\Prepar3D v4 folder):
    [Panels]
    GaugeDevDebug=1

Step 2: Add the new Panel

Unlike gauges, panels are particular to an aircraft. Go to the following directory:

C:\Program Files\Lockheed Martin\Prepar3D v4\SimObjects\Airplanes\Mooney_Bravo\panel
Open up the panel configuration files (panel.cfg) in a text editor. Notepad is quite sufficient for this.


In order to add a new test panel, add the line shown in bold under the Window titles section. The Window titles section should now look like this:

// Panel Configuration file
// Mooney Bravo
// Copyright (c) 2009-2015 Lockheed Martin Corporation.  All rights reserved.


[Window titles]
Window00=Main Panel
Window01=Radio Stack
Window02=GPS
Window03=Annunciator
Window04=Overhead Panel
Window05=Mini Panel
Window06=Test Panel

[VIEWS]
VIEW_FORWARD_DIR=2.000, 0.000, 0.000


The name Test Panel will now appear in Prepar3D. To add the panel itself, find the entry for Mini Panel and add the lines shown in bold below:

[Window05]
Background_color=0,0,0
size_mm=550,90
windowsize_ratio=1.6
position=7
visible=1 ident=MINIPANEL
no_luminous=1 child_3d=1

gauge00=Mooney_Bravo!Airspeed, 0,6, 81,78
gauge01=Mooney_Bravo!Turn Coordinator, 90, 6, 78,76
gauge02=Mooney_Bravo!Attitude, 180, 0, 93,87
gauge03=Mooney_Bravo!HSI, 283,0, 91,85
gauge04=Mooney_Bravo!Altimeter, 386,5, 73,76
gauge05=Mooney_Bravo!Vertical Speed, 470,6,77,77

[Window06]
file=Test_Panel_Background.bmp
position=6
size_mm=240,240
visible=00
ident=10001
gauge00=Mooney_Bravo!Airspeed, 5, 5, 81,78
gauge01=TestGauges!FuelPressure,     100, 5
gauge02=TestGauges!Stopwatch,        75,95

[VCockpit01]]
ffile=Mooney_Panel_G1000_Decals_Gray.bmp
size_mm=1024,1024


-The position simply refers to the default position where the panel will appear on the screen (6 is bottom left).
-The size_mm field is a misnomer, it does not represent millimeters, but arbitrary design units. However as it is much easier to create panels where these units are identical to the size of the elements in pixels, it is recommended that this entry is the pixel size of the panel background bitmap (240 by 240 for this tutorial).
-With visible set to 0 the panel will not be visible
-The ident field is an identifier number that can be any number above 10000. Lower codes are reserved for use by the simulation itself.

-The three gauge entries give the gauge number, cabinet file, gauge name, and then x and y coordinates relative to the top left hand corner of the panel, and optional width and height parameters (which will scale the gauge if they are not identical to the gauge sizes).


This completes the changes to the configuration file, so save the file.


Artwork needs to be created for the new entries made in the panel configuration file above. Create a colored square with a size of 240 by 240 pixels using Paint. Save it with the name Test_Panel_Background.bmp in the same directory as the panel configuration file.


This is all that is necessary to add a panel for the 2D cockpit view.

NOTE: Comment marks ("//") work in the panel configuration files. Test the new panel by commenting out the two lines beginning with gauge01 and gauge02, and then running Prepar3D. Try to turn the panel on and off, and notice that the airspeed indicator responds exactly as the one in the main panel. If this does not happen, carefully go over this step again.


Step 3: Create a simple Fuel Pressure Gauge

The fuel pressure gauge is certainly the simplest of the two methods to build gauges. All it is doing is displaying a single reading that is readily available in the simulator.

Start up the ACE tool, and select New Document. Right click on the new entry in the Property Sets column, and select Insert. An Insert dialog should appear, and select SimGauge in the Namespace box. Then scroll down and click on Gauge in the long list of properties. A gauge icon should now appear in the Property Sets column. Clicking on one of these entries will bring up all the object's properties. However, first save off the file, calling it FuelPressure.xml, to the folder: %USERPROFILE%\Documents\New Gauges\Test Gauges. Upon re-opening it, note that the parent node properties includes Filename and id. Change the id to any string that helps identify the gauge, such as "Fuel Pressure Gauge" in this case.


In the properties for the Gauge entry, change the ArtDirectory to the location %USERPROFILE%\Documents\New Gauges\Test Gauges for this tutorial. This is the location of the artwork for the tool, not for Prepar3D (which requires the art to be cabbed up with the XML gauge). However, if the location is set to be %USERPROFILE%\Documents\New Gauges\Test Gauges  then the artwork is in the right location, both for the ACE tool and for creating the cabinet files.

Add Background Art to the Fuel Pressure Gauge

Next, right click on the Gauge and select Image. This will be the background image for the gauge. Open up the properties for this image, and make an entry for Name (the filename), such as FuelPressureBackground.bmp.

Open up Paint again, to create artwork for this background, and save off a solid rectangular block of color, 100 pixels wide by 80 pixels in height. Call this file, FuelPressureBackground.bmp, and save it in the Test Gauges directory.

Add Elements to the Fuel Pressure Gauge

Right click on the Gauge node again, and add an Element. Do this three times to add three elements. Click on the first element to bring up its properties. Notice that the id entry for each element is simply "Element". Click on these and change the ids to Fixed Text for the first element, Output box for the second element, and Display text for the third element. This text is simply there to help in gauge development, and does not appear anywhere in the simulator. It is good to get into the practice of changing the ids to meaningful names, as some gauges will contain many elements. Each element is used to describe a small area of functionality of the gauge.

Properties of  the Fixed Text element

The location of elements is relative to their parent object in the design of the gauge. So for the Fixed Text element, change FloatPosition to 5,10. This will start the text 5 pixels in, 10 pixels down, on the gauge background.

This element describes no more than the words "Fuel Pressure" on the gauge. To do this right click on the element, select Insert then GaugeText, and then change just a few properties of the GaugeText object as outlined below:


Property Entry
FontFace Arial
FontColor gold
FontHeight 13
GaugeString Fuel Pressure
Size 90, 15

Properties of the Output box element

The output box is simply a rectangle where the display text is to appear within. Change its FloatPosition to 5, 40. Then insert a Rectangle object as a child of this element. Change the Rectangle properties to those shown below:


Property Entry
LineWidth 1
Width 90
Height 24
LineColor darkslateblue
FillColor black

The colors for text, lines and shapes can be entered either as names, or as hex RGB values (in the format 0xBBGGRR). The document XML Gauge Colors contains the full list.

Properties of the Display text element

This is the third and final element in the gauge. Set its FloatPosition to 10, 44. Then insert another GaugeText object as a child of this element. There is one important difference between this text and that for the first element, in that for this element it is necessary to display the value of a simulation variable, not fixed text. Make the following entries in the new GaugeText object:


Property Entry
FontFace Courier
FontColor red
FontHeight 16
GaugeString %( (A:GENERAL ENG FUEL PRESSURE:1, psi) )%!09d!
HorizontalAlign LEFT
Size 90, 16

The key here is the GaugeString. The A:GENERAL ENG FUEL PRESSURE, is a simulation variable (there are many hundreds of these, listed in the Simulation Variables document). The index :1 is necessary as the fuel pressure is measured per engine, and psi requests that the result be returned as pounds per square inch. Simulation variables must be enclosed by parentheses. The % signs indicate that the contents should be evaluated rather than output as a string. The %!09d! indicate that nine digits should be output, that leading 0s should be included (up to nine of them!), and that the result should be treated as a decimal integer.  The section on Scripting goes over the full process for evaluating gauge scripts, which can be quite long and complex. Be very careful to enter the text exactly as shown (perhaps cut and paste it from this document), as a wrong space or missing parentheses can cause the expression evaluation to fail (it is not very flexible or forgiving in this regard).


Previewing the Fuel Pressure Gauge

The fuel pressure gauge is now complete and ready for testing. The tree structure of the gauge, when fully expanded, should look like this:



In the View menu, select Preview, then click on one of the gauge elements to view a preview in the right pane. It should look something like this:



Make sure to save off the XML document reasonably frequently. Before testing the fuel pressure gauge, the stopwatch will be built.



Step 4: Create a Stopwatch Gauge

The stopwatch will show a rotary dial of seconds, and have an active start/stop toggle button, and an active reset button.


This makes the gauge considerably more complex than the simple text display of the fuel pressure gauge. The stopwatch will require handling of a rotation (the seconds needle), active mouse clicks (the two buttons), but also the task of persisting information about the gauge from one mouse click to the next, this is necessary in the simplest case for the toggle button -- its state must be recorded in order for it to be changed from start to stop, or vice versa.


In order to keep things a little bit simpler, the stopwatch will be built from simple graphics primitives, and the stopwatch will have a single second hand.


The Stopwatch Elements


Create the following stopwatch elements:


The Stopwatch Rim

Insert an element, change the id to Rim, and give it a FloatPosition of 50, 60. Then insert a Circle object with the following properties:


Property Entry
Axis 50, 50
Radius 50
FillColor black
LineWidth 3
LineColor steelblue

The Stopwatch numerals

For this tutorial, limit the stopwatch to 4 numerals: 60, 30, 45 and 15. To develop the stopwatch fully, replace these elements with background art, with the numerals appearing on that art.


Create four elements, change their ids to 60,  30, 45 and 15, and give them FloatPositions of:


Numeral FloatPosition
60 40, 14
30 40, 96
45 4, 55
15 84, 55


Next, insert GaugeText entries for all four elements, with the following properties:

Property Entry
FontFace Arial
FontColor gold
FontHeight 12
GaugeString 15, 30, 45 and 60 (appropriately for each gauge element)
HorizontalAlign CENTER
Size 20, 20

The Start/Stop button

Add another element, change its id to Start/Stop button, and give it a FloatPosition of  44, 1. Then insert a Rectangle object with the following properties:

Property Entry
LineWidth 1
Width 12
Height 10
LineColor silver
FillColor silver

The Reset button

Add another element, change its id to Reset button, and give it a FloatPosition of  17,17. Then insert a Rectangle object with the following properties:

Property Entry
Axis 5, 5
LineWidth 1
Width 10
Height 10
LineColor silver


Note the entry in the Axis property, so that the rectangle will rotate about its center. The button should look as if it is attached to the stopwatch rim. Insert a Rotation object as a child of the Reset button element, and delete the automatically created sub-objects, except Expression. Do not change any of the Rotation objects properties, and simply add the number -0.7 as the entry for the Script property of the expression (this will rotate the rectangle minus 0.7 radians, which is about right).


The Needle

Add another element, change its id to Needle, and give it a FloatPosition of 50,60. Then, insert a Polygon object, and give it the following properties:


Property Entry
Axis 50, 60
FillColor red
LineWidth 1
LineColor red

A polygon consists of a list of Points, so insert three points with the following FloatPosition entries (to define a simple triangle):


Point FloatPosition
1 48, 62
2 50, 12
3 52, 62

The needle will also need a rotation object, so insert a Rotation, and entries for Rotation, Expression, FailureTable and Failure, will all appear. Leave this object for now, except change the following in the Failure object (this indicates that if the user fails the electrical system, the stopwatch should freeze).


Property Entry
Fail_Key SYSTEM_ELETRICAL_PANELS
Fail_Action Freeze

This expression object will be revisited, after first creating the MouseArea and MouseClick objects, as the logic of the expressions are all connected and complicated.


The Main MouseArea

There can only be one main mouse area for a gauge, so insert a MouseArea object and give it the following properties (which simply indicate it covers the full area of the stopwatch, with a normal cursor):


Property Entry
id
MouseArea all
FloatPosition
0, 0
Size 100, 110
CursorType normal

The start/stop MouseArea

Insert another MouseArea as a child of the main mouse area. This area is to be active, and related to a mouse click.


Property Entry
id
start/stop
FloatPosition
41, 1
Size 12, 10
CursorType Hand

The reset MouseArea

Insert yet another MouseArea as a child of the main mouse area, and a peer of the start/stop area. This area is also to be active, and related to a mouse click.


Property Entry
id
reset
FloatPosition
14, 14
Size 10, 10
CursorType Hand

The MouseClick objects

MouseClick objects should be inserted for both the start/stop and reset mouse areas. Both should have their ClickType properties set to:

LeftSingle+LeftRelease


The only other property to change is the Script, which is explained next.


The Stopwatch Expression Logic


The next step is entering expression logic for both the mouse clicks and the needle rotation. Expression logic is entered using reverse polish notation (though refer to the Infix2Postfix tool that can assist in creating and understanding this notation).


Starting with the reset button, enter the following text for the mouse click Script:

(M:Event) 'LeftSingle' scmp 0 == if{ 1 (>L:RST Pressed,bool) 0 (>L:TotalRunning,seconds) 0 (>L:Running,bool) } (M:Event) 'LeftRelease' scmp 0 == if{ 0 (>L:RST Pressed,bool) }

The logic here is based around local variables, three of which have been used here:

Note also the use of the M:Event mouse variable. The (M:Event) 'LeftSingle' scmp 0 == if{ entry is processed as if the mouse event and the text string 'LeftSingle' are compared, and are equal, then the contents of the if statement block is processed. Similarly for the mouse button release. Reverse polish notation is explained in more detail in the article on RPN Scripting.

Next enter the Script for the mouse click of the start/stop button. Note that this single button has two functions: starting or stopping the stopwatch depending on its current state.

(M:Event) 'LeftSingle' scmp 0 == if{ 1 (>L:STSTP Pressed,bool) (L:Running,bool) ! (>L:Running,bool) } (L:Running, bool) ! if{ (P:Absolute time, seconds) (>L:Offset, seconds) } (M:Event) 'LeftRelease' scmp 0 == if{ 0 (>L:STSTP Pressed,bool) }

Notice how the first if statement toggles the L:Running local variable: (L:Running,bool) ! (>L:Running,bool) assigns the NOT value of the boolean back to the variable. The second if statement then tests the value of L:Running and if it is false (the stopwatch is not running). The absolute time in seconds is assigned to another local variable L:Offset. This variable is used to calculate the rotation of the needle. The variable P:Absolute time can be found along with all the other program variables, in the Simulation Variables document.


Again there is a local variable L:STSTP Pressed to handle different graphic images for the button, if this functionality is desired.

Finally, enter the expression for the needle element's rotation, enter:

(L:Running,bool) if{ (P:Absolute time, seconds) (L:Offset,seconds) - (>L:TotalRunning,seconds) } els{ (P:Absolute time, seconds) (L:TotalRunning,seconds) - (>L:Offset,seconds) } (L:TotalRunning, seconds) 0.104719 *

The logic here is that if the stopwatch is running (L:Running is true) then the total running time is the absolute time in seconds, minus the offset (the absolute time when the stopwatch was last stopped). If the stopwatch is not running then the absolute time in seconds, minus the running time in seconds, is assigned to the offset. Finally the value of L:TotalRunning is applied to the rotation. To do this, this value (in seconds) is converted to radians by multiplying by 0.104719 (which is 2 * pi -- one full circle -- divided by 60, or the number of radians per sixtieth of a full rotation).

The stopwatch is now ready for testing, but first preview it to ensure the various elements are in the right place.


Previewing the Stopwatch


When completed, the stopwatch component tree should look like this:



And in the Preview window the stopwatch should appear.



Testing the Stopwatch in Preview mode

It is possible to do some limited testing within the tool by overriding the above scripts. For example, to test the rotation of the needle select the Expression of the Rotation of the Needle element -- this expression begins with (L:Running,bool).....


Change the expression by adding the following text:

pi quit (L:Running,bool)....

The quit entry forces all evaluation to stop, so the value pi is used for the rotation. The stopwatch in the preview screen should show the needle hand pointing at 30 (pi radians is 180 degrees). Next change the entry to:

1.5 pi * quit (L:Running,bool)

The needle should now point at 45. If this is the observed result, delete the testing text. If not, re-examine all the entries for the Needle element, checking that the entries have been entered correctly.


Both the new gauges are now complete. Delete the changes made above. The next steps are to create a cabinet file and test them in Prepar3D.



Step 5: Create a Cabinet file

Run the cabdir tool on the New Gauges\TestGauges directory. This will compress the three files, FuelPressure.xml, Stopwatch.xml and FuelPressureBackground.xml into one .cab file, called TestGauges.cab. The cabdir tool can be used in a number of ways:

  1. Drag the TestGauges directory and drop it onto the Cabdir icon (in the root folder of the SDK installation). This is the simplest way, but does not allow any of cabdir's parameters to be changed (which in most cases is fine). The cab file will be located in the root directory of the TestGauges directory.
  2. Change the working directory in the command line to the bin folder of the SDK, and run cabdir from the command line (see the Creating Cabinet Files documentation).

Copy the cab file (which has a cabinet style icon) into the ..\Prepar3D\Gauges directory. These gauges are independent of the simulation aircraft, so can be used in any panel of any of the aircraft. For this tutorial though, the gauges are simply added to the Mooney Bravo.


The process of creating a panel and new gauges, and adding them to the simulation, is now complete. The next stage is to test them.


NOTE: This step is included in the tutorial because cab files are recommended for final release and distribution. While developing and debugging, the uncompressed folder can be placed in the Prepar3D/Gauges directory. If a gauge is not intended to be shared between aircraft, the folder or cab file can also be placed in the same folder as the panels.cfg file that references it.



Step 6: Testing the new Gauges

Run Prepar3D, and select the Mooney_Bravo (which is the default aircraft) to load up the new gauges. Select the panel from the Instrument Panel menu, and then watch the fuel pressure gauge rise slowly as the aircraft speed increases. Click on the stopwatch buttons and watch the needle rotate.



Step 7: Adding Artwork to the Stopwatch

The stopwatch includes local variables that indicate the status of the start/stop and reset buttons. This allows the gauge to be extended so that the button depression can be observed as selected. This involves a new gauge element, the Select element, with two child Case objects (representing the buttons in an up and down state).


Using any appropriate image editing tool, create two bitmaps 12 pixels wide by 10 pixels in height, which look like a button extended and depressed. For example:


Extended Image
StartStopUpGraphic.jpg
Depressed Image
StartStopDownGraphic.jpg

Replace the start/stop rectangle with one of two small images, which one depending on whether the button is being pressed or not. Save these to the TestGauges directory.

NOTE: Pure black is the transparent color.


Next, delete the rectangle of the Start/Stop button element, and then insert a Select element. This will automatically add an Expression and two Case objects to the gauge.

Now edit the objects as follows:

The Select element in the tree view of the gauge should now look like this:



Now, go back to step 5, update the gauges, and test the new action. All the simple art can be replaced with images to build a polished stopwatch.