Howto:Prototyping a new NavDisplay Style

From FlightGear wiki
Revision as of 15:53, 12 October 2016 by Clm76 (talk | contribs) (→‎Status)
Jump to navigation Jump to search
This article is a stub. You can help the wiki by expanding it.
Screenshot showing a PUI dialog with two embedded Canvas regions for displaying two independent NavDisplay instances.

Objective

Demonstrate how a simple PUI/XML dialog can be used to easily prototype new NavDisplay styles, showing two instances for each pilot, which can be controlled/tested independently.

Approach

This is a PUI/XML dialog with two embedded CanvasWidget areas that instantiate independent ND instances using a subset of the code commonly found in the aircraft specific ND.nas file, adapted to use the embedded Canvas region for rendering the two NDs and GUI buttons/widgets added to control the whole thing without necessarily requiring a fully developed cockpit.

Roadmap

  • add buttons for controlling each ND instance (range, zoom, centering)
  • use io.include to directly reload the styles stuff (for rapid prototyping)
  • procedurally add buttons for each switch by enhancing the myCockpit_switches hash with legends/labels for the UI use-case (use checkboxes for boolean props)
  • add a dropdown menu to select the position source (main aircraft vs. AI/MP traffic)

Status

For now this is heavily based on ideas, and code, borrowed from the original MapStructure Debugger (code still available at [1])

WIP.png Work in progress
This article or section will be worked on in the upcoming hours or days.
See history for the latest developments.
Note  For testing purposes, put the following dialog into $FG_ROOT/gui/dialogs/canvas-nd.xml and use the Nasal Console to run the dialog (or extend the Menubar accordingly):
fgcommand("dialog-show", props.Node.new({'dialog-name':'canvas-nd'}) );
<?xml version="1.0" encoding="UTF-8"?>

<PropertyList>

<name>canvas-nd</name>
<modal>false</modal>
<layout>vbox</layout>
<text>
  <label>Canvas ND</label>
</text>

<nasal>
  <open><![CDATA[
    print("nasal/opening block");
    var show_canvas_id = func(c) {
        print("Canvas is:", c.getPath());
    };

    # to be used for shutting down each created instances upon closing the dialog (see the close block below)
    var MFDInstances = [];

    #### 
    ## an adapted version of ND.nas
    ##

    var setupND = func(property_root, my_canvas) {

        var myCockpit_switches = {
            # symbolic alias : relative property (as used in bindings), initial value, type
            'toggle_range':         {path: '/inputs/range-nm', value:40, type:'INT'},
            'toggle_weather':       {path: '/inputs/wxr', value:0, type:'BOOL'},
            'toggle_airports':      {path: '/inputs/arpt', value:0, type:'BOOL'},
            'toggle_stations':      {path: '/inputs/sta', value:0, type:'BOOL'},
            'toggle_waypoints':     {path: '/inputs/wpt', value:0, type:'BOOL'},
            'toggle_position':      {path: '/inputs/pos', value:0, type:'BOOL'},
            'toggle_data':          {path: '/inputs/data',value:0, type:'BOOL'},
            'toggle_terrain':       {path: '/inputs/terr',value:0, type:'BOOL'},
            'toggle_traffic':       {path: '/inputs/tfc',value:0, type:'BOOL'},
            'toggle_centered':      {path: '/inputs/nd-centered',value:0, type:'BOOL'},
            'toggle_lh_vor_adf':    {path: '/inputs/lh-vor-adf',value:0, type:'INT'},
            'toggle_rh_vor_adf':    {path: '/inputs/rh-vor-adf',value:0, type:'INT'},
            'toggle_display_mode':  {path: '/mfd/display-mode', value:'MAP', type:'STRING'},
            'toggle_display_type':  {path: '/mfd/display-type', value:'LCD', type:'STRING'},
            'toggle_true_north':    {path: '/mfd/true-north', value:0, type:'BOOL'},
            'toggle_rangearc':      {path: '/mfd/rangearc', value:0, type:'BOOL'},
            'toggle_track_heading': {path: '/hdg-trk-selected', value:0, type:'BOOL'},
            'toggle_hdg_bug_only':  {path: '/hdg-bug-only', value:0, type:'BOOL'},
            # add new switches here
        };

        ###
        # entry point, this will set up an ND instance

        # get a handle to the NavDisplay in canvas namespace (for now), see $FG_ROOT/Nasal/canvas/map/navdisplay.mfd
        var ND = canvas.NavDisplay;

        ##
        # set up a  new ND instance, under 'instrumentation/efis' and use the
        # myCockpit_switches hash to map control properties
        # FIXME: use cmdarg() here to use a dialog specific path for all switches
        var myND = ND.new("instrumentation/efis", myCockpit_switches, 'Boeing');

        var group = my_canvas.createGroup();
        myND.newMFD(group, my_canvas);
        myND.update();
        # store the instance for later cleanup
        append(MFDInstances, myND);

        return myND;
    } # setupND()
  ]]></open>

  <close><![CDATA[
    print("nasal/closing block");
    foreach(var mfd; MFDInstances) {
        mfd.del();
    }
  ]]></close>
</nasal>

<group>
  <layout>hbox</layout>

  <canvas>
    <name>mfd1</name>
    <valign>fill</valign>
    <halign>fill</halign>
    <stretch>true</stretch>
    <pref-width>512</pref-width>
    <pref-height>512</pref-height>
    <view>1024</view>
    <view>1024</view>
    <nasal>      
      <!--
           this is the Nasal/canvas section where you can run your own Nasal code 
           to access the canvas section 
      -->
      <load><![CDATA[
        # you can add your canvas-specific code here
        var my_canvas = canvas.get(cmdarg()); # this will get a handle to the parent canvas:
        show_canvas_id(my_canvas);
        setupND(property_root: cmdarg(), my_canvas: my_canvas);
      ]]></load>
    </nasal>
  </canvas>

  <canvas>
    <name>mfd2</name>
    <valign>fill</valign>
    <halign>fill</halign>
    <stretch>true</stretch>
    <pref-width>512</pref-width>
    <pref-height>512</pref-height>
    <view>1024</view>
    <view>1024</view>
    <nasal>      
      <!--
           this is the Nasal/canvas section where you can run your own Nasal code 
           to access the canvas section 
      -->
      <load><![CDATA[
        # you can add your canvas-specific code here
        var my_canvas = canvas.get(cmdarg()); # this will get a handle to the parent canvas:
        show_canvas_id(my_canvas);
        setupND(property_root: cmdarg(), my_canvas: my_canvas);
      ]]></load>
    </nasal>
  </canvas>

</group>

<group>
  <layout>hbox</layout>

  <button>
    <legend>Reload</legend>
    <default>1</default>
    <border>2</border>
    <binding>
      <command>reinit</command>
      <subsystem>gui</subsystem>
    </binding>
  </button>

  <button>
    <legend>Exit</legend>
    <equal>true</equal>
    <key>Esc</key>
    <binding>
      <command>dialog-close</command>
    </binding>
  </button>

</group>

</PropertyList>