# ============================================================================== # Boeing Navigation Display by Gijs de Rooy # See: http://wiki.flightgear.org/Canvas_ND_Framework # ============================================================================== # This file makes use of the MapStructure framework, see: http://wiki.flightgear.org/Canvas_MapStructure # # Sooner or later, some parts will be revamped by coming up with a simple animation framework: http://wiki.flightgear.org/NavDisplay#mapping_vs._SVG_animation ## # pseudo DSL-ish: use these as placeholders in the config hash below var ALWAYS = func 1; var NOTHING = func nil; ## # TODO: move ND-specific implementation details into this lookup hash # so that other aircraft and ND types can be more easily supported # # any aircraft-specific ND behavior should be wrapped here, # to isolate/decouple things in the generic NavDisplay class # # TODO: move this to an XML config file (maybe supporting SGCondition and/or SGStateMachine markup for the logic?) # canvas.NDStyles["Airbus"] = { font_mapper: func(family, weight) { if( family == "Liberation Sans" and weight == "normal" ) return "LiberationFonts/LiberationSans-Regular.ttf"; }, # where all the symbols are stored # TODO: SVG elements should be renamed to use boeing/airbus prefix # aircraft developers should all be editing the same ND.svg image # the code can deal with the differences now svg_filename: get_local_path("res/airbusND.svg"), ## ## this loads and configures existing layers (currently, *.layer files in Nasal/canvas/map) ## options: { position_callback: func(nd, pos){ if(nd.get_switch('toggle_centered') or nd.get_switch('toggle_display_mode') == 'PLAN') pos.range = (nd.rangeNm() * 1.6156087432822295); }, translation_callback: func(nd){ var t = {x: 512, y: 824}; if(nd.get_switch('toggle_centered') or nd.get_switch('toggle_display_mode') == 'PLAN') t.y = 512; return t; }, defaults: { # Configurable Global Options: # - fplan_active: the boolean property used to determine if the flight plan is active # - lat_ctrl: the property used to determine if lateral flight mode is managed # Lateral managed mode is similar to Boeing LNAV and indicates that the # aircraft should follow the current active flight plan. By default # the lat_ctrl property is checked against 'fmgc' (managed) value. # You can use a custom value instead on 'fmgc' by overriding 'managed_val' # - managed_val: the value that the property defined by 'lat_ctrl' should have in case # that the lateral flight mode is managed. # You can easily override these options before creating the ND, example: # canvas.NDStyles['Airbus'].options.defaults.fplan_active = 'my/autpilot/f-plan/active' fplan_active: 'autopilot/route-manager/active', lat_ctrl: 'flight-management/control/lat-ctrl', managed_val: 'fmgc', ver_ctrl: 'flight-management/control/ver-ctrl', spd_ctrl: '/flight-management/control/spd-ctrl', current_wp: '/autopilot/route-manager/current-wp', ap1: '/flight-management/control/ap1-master', ap2: '/flight-management/control/ap2-master', nav1_frq: 'instrumentation/nav/frequencies/selected-mhz', nav2_frq: 'instrumentation/nav[1]/frequencies/selected-mhz', vor1_frq: 'instrumentation/nav[2]/frequencies/selected-mhz', vor2_frq: 'instrumentation/nav[3]/frequencies/selected-mhz', adf1_frq: 'instrumentation/adf/frequencies/selected-khz', adf2_frq: 'instrumentation/adf[1]/frequencies/selected-khz', dep_rwy: '/autopilot/route-manager/departure/runway', dest_rwy: '/autopilot/route-manager/destination/runway', wp_count: 'autopilot/route-manager/route/num', level_off_alt: '/autopilot/route-manager/vnav/level-off-alt', athr: '/flight-management/control/a-thrust', app_mode: 'instrumentation/nd/app-mode', chrono_node: 'instrumentation/chrono', fpln_offset: 'autopilot/route-manager/offset', active_route_color: [0.4,0.7,0.4], inactive_route_color: [0.95,0.95,0.21] }, radio: { ils: [0, 1], vor: [2, 3], dme: [2, 3] } }, layers: [ { name:'WXR_live', isMapStructure:1, always_update: 1, update_on:[ 'toggle_range','toggle_weather','toggle_display_mode','toggle_weather_live'], predicate: func(nd, layer) { var visible=nd.get_switch('toggle_weather') and nd.get_switch('toggle_weather_live') and nd.get_switch('toggle_display_mode') != "PLAN"; layer.group.setVisible(visible); if (visible) { layer.update(); } }, # end of layer update predicate options: { viewport_radius: 706 }, 'z-index': -100, }, { name:'WXR', isMapStructure:1, update_on:[ {rate_hz: 0.1}, 'toggle_range','toggle_weather','toggle_display_mode', 'toggle_weather_live'], predicate: func(nd, layer) { #print("Running storms predicate"); var visible=nd.get_switch('toggle_weather') and !nd.get_switch('toggle_weather_live') and nd.get_switch('toggle_display_mode') != "PLAN"; layer.group.setVisible(visible); if (visible) { #print("storms update requested! (timer issue when closing the dialog?)"); layer.update(); } }, # end of layer update predicate 'z-index': -4, }, # end of storms/WXR layer { name:'FIX', isMapStructure:1, update_on:['toggle_range','toggle_waypoints', 'toggle_display_mode'], predicate: func(nd, layer) { var visible = nd.get_switch('toggle_waypoints') and nd.in_mode('toggle_display_mode', ['MAP']) and (nd.rangeNm() <= 40); layer.group.setVisible( visible ); if (visible) layer.update(); }, # end of layer update predicate style: { color: [0.69, 0, 0.39], text_offset: [20,10], text_color: [1,1,1] }, options: { draw_function: func(group){ group.createChild('path') .moveTo(-10,0) .lineTo(0,-17) .lineTo(10,0) .lineTo(0,17) .close() .setStrokeLineWidth(3) .setColor(color) .setScale(1); } } }, # end of FIX layer { name: 'ALT-profile', isMapStructure: 1, update_on: ['toggle_display_mode','toggle_range',{rate_hz: 2}], predicate: func(nd, layer) { var visible = nd.in_mode('toggle_display_mode', ['MAP', 'PLAN']);# and nd.get_switch('toggle_fplan'); layer.group.setVisible( visible ); if (visible) { layer.update(); } }, style: { default_color: [1,1,1], armed_color: [0.06,0.55,1], managed_color: [0.68, 0, 0.38] }, options: { # You can overwrite these with different nodes, before creating the ND # Example: canvas.NDStyles['Airbus'].layers['ALT-profile'].options.vnav_node = 'my/vnav/node'; # In order to display ALT-profile on your ND you have to create the various # nodes corresponding to the different ALT pseudowaypoint in your aircraft code. # Every node must be set into the 'vnav_node' configured here (you can override it). # Example: if you want to display the top-of-descent symbol you must create a 'td' # node into vnav_node. Something like this: # /autopilot/route-manager/vnav/td/ # Each node should have the latitude-deg and longitude-deg properties. # Available nodes are: # tc (top of climb) # td (top of descent) # ec (end of climb) # ed (end of descent) # sc (start of climb) # sd (start of descent) # If ec and ed are altitude constraints, their node should have the # boolean 'alt-cstr' property set to 1. vnav_node: "/autopilot/route-manager/vnav/", types: ["tc", "td", "ec", "ed","sc","sd"], svg_path: { tc: get_local_path('res/airbus_tc.svg'), td: get_local_path('res/airbus_td.svg'), ec: get_local_path('res/airbus_ec.svg'), ed: get_local_path('res/airbus_ed.svg'), sc: get_local_path('res/airbus_sc.svg'), sd: get_local_path('res/airbus_sd.svg') }, listen: [ 'fplan_active', 'ver_ctrl', 'ap1', 'ap2', 'current_wp' ], draw_callback: func(){ var name = me.model.getName(); var grp = me.element.getElementById(name~'_symbol'); if(grp == nil) return; var dfcolor = me.getStyle('default_color'); var armed_color = me.getStyle('armed_color'); var managed_color = me.getStyle('managed_color'); #print('Draw: -> ' ~ name); if(name == 'td' or name == 'sd' or name == 'sc'){ var vnav_armed = me.model.getValue('vnav-armed'); if(vnav_armed and name != 'td') grp.setColor(armed_color); else grp.setColor(dfcolor); } elsif(name == 'ed' or name == 'ec'){ var is_cstr = me.model.getValue('alt-cstr'); if(is_cstr) grp.setColor(managed_color); else grp.setColor(armed_color); } }, init_after_callback: func{ var name = me.model.getName(); var grp = me.element.getElementById(name~'_symbol'); if(name != 'td' and name != 'sd' and name != 'sc'){ grp.setTranslation(-66,0); } } } }, { name:'APT', isMapStructure:1, update_on:['toggle_range','toggle_airports', 'toggle_display_mode'], predicate: func(nd, layer) { var visible = nd.get_switch('toggle_airports') and nd.in_mode('toggle_display_mode', ['MAP']); layer.group.setVisible( visible ); if (visible) { layer.update(); } }, # end of layer update predicate style: { svg_path: get_local_path('res/airbus_airport.svg'), text_offset: [45, 35], label_font_color: [1,1,1], label_font_size: 28 } }, # end of APT layer { name:'VOR-airbus', isMapStructure:1, update_on:['toggle_range','toggle_vor','toggle_display_mode'], # FIXME: this is a really ugly place for controller code predicate: func(nd, layer) { # print("Running vor layer predicate"); # toggle visibility here var visible = nd.get_switch('toggle_vor') and nd.in_mode('toggle_display_mode', ['MAP']) and (nd.rangeNm() <= 40); layer.group.setVisible( visible ); if (visible) { layer.update(); } }, # end of layer update predicate # You can override default colors within the style # Default color: 'color' # Tuned color: 'tuned_color' # Example: # canvas.NDStyles['Airbus'].layers['VOR-airbus'].style.color = [1,1,1]; # canvas.NDStyles['Airbus'].layers['VOR-airbus'].style.tuned_color = [0,0,1]; style: {}, options:{ listen: [ 'vor1_frq', 'vor2_frq' ] } }, # end of VOR layer { name:'DME', disabled:1, isMapStructure:1, update_on:['toggle_display_mode','toggle_range','toggle_dme'], # FIXME: this is a really ugly place for controller code predicate: func(nd, layer) { var visible = nd.get_switch('toggle_dme') and nd.in_mode('toggle_display_mode', ['MAP']) and (nd.rangeNm() <= 40); # toggle visibility here layer.group.setVisible( visible ); if (visible) { #print("Updating MapStructure ND layer: DME"); layer.update(); } }, # end of layer update predicate options: { draw_dme: func(sym){ return sym.createChild("path") .moveTo(-13, 0) .arcSmallCW(13,13,0,26,0) .arcSmallCW(13,13,0,-26,0) .setStrokeLineWidth(2) .close(); }, draw_text: 1 }, style: { color_default: [0.9,0,0.47], color_tuned: [0,0.62,0.84], }, 'z-index': -2, }, # end of DME layer { name:'NDB', isMapStructure:1, update_on:['toggle_range','toggle_ndb','toggle_display_mode'], # FIXME: this is a really ugly place for controller code predicate: func(nd, layer) { var visible = nd.get_switch('toggle_ndb') and nd.in_mode('toggle_display_mode', ['MAP']) and (nd.rangeNm() <= 40); # print("Running vor layer predicate"); # toggle visibility here layer.group.setVisible( visible ); if (visible) { layer.update(); } }, # end of layer update predicate # You can override default colors within the style # Default color: 'color' # Tuned color: 'tuned_color' # Example: # canvas.NDStyles['Airbus'].layers['VOR-airbus'].style.color = [1,1,1]; # canvas.NDStyles['Airbus'].layers['VOR-airbus'].style.tuned_color = [0,0,1]; style: { #svg_path: get_local_path('res/airbus_ndb.svg') svg_path: '' }, options: { listen: [ 'adf1_frq', 'adf2_frq' ], init_after_callback: func{ #me.element.removeAllChildren(); me.text_ndb = me.element.createChild("text") .setDrawMode( canvas.Text.TEXT ) .setText(me.model.id) .setFont("LiberationFonts/LiberationSans-Regular.ttf") .setFontSize(28) .setTranslation(25,10); me.ndb_sym = me.element.createChild('path'); me.ndb_sym.moveTo(-15,15) .lineTo(0,-15) .lineTo(15,15) .close() .setStrokeLineWidth(3) .setColor(0.69,0,0.39) .setScale(1,1); }, draw_callback: func{ var frq = me.model.frequency; if(frq != nil){ var dfcolor = me.getStyle('color', [0.9,0,0.47]); var tuned_color = me.getStyle('tuned_color', [0,0.62,0.84]); frq = frq / 100; var adf1_frq = getprop(me.options.adf1_frq); var adf2_frq = getprop(me.options.adf2_frq); if(adf1_frq == frq or adf2_frq == frq){ me.element.setColor(tuned_color, [Path]); } else { me.element.setColor(dfcolor, [Path]); } } }, } }, # end of NDB layer { name:'TFC', #disabled:1, always_update: 1, isMapStructure:1, update_on:['toggle_range','toggle_traffic'], predicate: func(nd, layer) { var visible = nd.get_switch('toggle_traffic'); layer.group.setVisible( visible ); if (visible) { #print("Updating MapStructure ND layer: TFC"); layer.update(); } }, # end of layer update predicate }, # end of traffic layer { name:'RWY-profile', isMapStructure:1, update_on:['toggle_range','toggle_display_mode'], predicate: func(nd, layer) { var visible = (nd.rangeNm() <= 40) and nd.in_mode('toggle_display_mode', ['MAP','PLAN']) ; layer.group.setVisible( visible ); if (visible) { layer.update(); } }, # end of layer update predicate options: { listen: [ 'fplan_active', 'dep_rwy', 'dest_rwy' ] } }, # end of runway layer { name:'HOLD', isMapStructure: 1, always_update: 1, update_on:['toggle_range','toggle_display_mode','toggle_wpt_idx'], predicate: func(nd, layer) { var visible= nd.in_mode('toggle_display_mode', ['MAP','PLAN']); layer.group.setVisible( visible ); if (visible) { layer.update(); } }, options: { hold_node: '/flight-management/hold', hold_init: 'flight-management/hold/init', points_node: '/flight-management/hold/points', first_point_node: '/flight-management/hold/points/point/lat', hold_wp: '/flight-management/hold/wp', hold_wp_idx: '/flight-management/hold/wp_id', range_dependant: 1, listen: [ 'first_point_node', 'fplan_active', 'lat_ctrl', 'current_wp', 'hold_wp', 'hold_init', 'hold_wp_idx' ] } # end of layer update predicate }, # end of HOLD layer { name:'RTE', isMapStructure: 1, update_on:['toggle_range','toggle_display_mode', 'toggle_cstr', 'toggle_wpt_idx'], predicate: func(nd, layer) { var visible= (nd.in_mode('toggle_display_mode', ['MAP','PLAN'])); layer.group.setVisible( visible ); if (visible) { layer.update(); } }, # end of layer update predicate options: { display_inactive_rte: 1, listen: [ 'fplan_active', 'lat_ctrl', 'current_wp', 'wp_count' ], draw_after_callback: func{ me.setRouteStyle(); } }, style: { line_width: 5, #inactive_color: [0.95,0.95,0.21], #active_color: [0.4,0.7,0.4], color: func{ if(!contains(me, 'inactive_color')){ me.inactive_color = me.getStyle('inactive_color'); if(me.inactive_color == nil) me.inactive_color = me.getOption('inactive_route_color'); } if(!contains(me, 'active_color')){ me.active_color = me.getStyle('active_color'); if(me.active_color == nil) me.active_color = me.getOption('active_route_color'); } var is_active = getprop(me.options.fplan_active); (is_active ? me.active_color : me.inactive_color); }, color_alternate_active: [0,0.62,0.84], color_missed: [0,0.62,0.84], color_temporary: func me.getStyle('inactive_color', me.getOption('inactive_route_color')), color_secondary: [1,1,1], color_alternate_secondary: [1,1,1], line_dash: func{ var lat_ctrl = getprop(me.options.lat_ctrl); var is_managed = (lat_ctrl == me.options.managed_val); var is_active = getprop(me.options.fplan_active); (is_managed and is_active ? [] : [32, 16]); }, line_dash_alternate_active: [32,16], line_dash_temporary: [32,16], line_dash_original: [32,16] } }, # end of route layer { name:'WPT-airbus', isMapStructure: 1, update_on:['toggle_range','toggle_display_mode', 'toggle_cstr', 'toggle_wpt_idx'], style: { wp_color: [0.4,0.7,0.4], current_wp_color: [1,1,1], constraint_color: [1,1,1], active_constraint_color: [0.69,0,0.39], missed_constraint_color: [1,0.57,0.14] }, predicate: func(nd, layer) { var visible= (nd.in_mode('toggle_display_mode', ['MAP','PLAN'])); layer.group.setVisible( visible ); if (visible) { layer.toggle_cstr = nd.get_switch('toggle_cstr'); layer.update(); } }, # end of layer update predicate options: { listen: [ 'fplan_active', 'lat_ctrl', 'ver_ctrl', 'current_wp', 'wp_count', 'dep_rwy', 'dest_rwy', 'level_off_alt' ], } }, # end of WPT layer { name: 'SPD-profile', isMapStructure: 1, update_on: ['toggle_display_mode','toggle_range',{rate_hz: 2}], predicate: func(nd, layer) { var visible = nd.in_mode('toggle_display_mode', ['MAP', 'PLAN']); layer.group.setVisible( visible ); if (visible) { layer.update(); } }, style: { color: [0.69,0,0.39] }, options: { spd_node: "/autopilot/route-manager/spd/", listen: [ 'fplan_active' ] } }, { name: 'DECEL', isMapStructure: 1, update_on: ['toggle_display_mode','toggle_range'], predicate: func(nd, layer) { var visible = nd.in_mode('toggle_display_mode', ['MAP', 'PLAN']); layer.group.setVisible( visible ); if (visible) { layer.update(); } }, options: { # Overridable options: # decel_node: node containing latitude-deg and longitude-deg used to mark the deceleration point # managed_speed_node: boolean property indicating that the aircraft is flying in managed speed mode listen: [ 'fplan_active', 'spd_ctrl', 'ver_ctrl', 'athr' ] }, style: { # managed_color: decelaration symbol color when the aircraft flies in managed speed mode # selected_color: decelaration symbol color when the aircraft flies in selected speed mode managed_color: [0.68, 0, 0.38], selected_color: [1,1,1] } }, { name:'APS', isMapStructure:1, always_update: 1, update_on:['toggle_display_mode'], predicate: func(nd, layer) { var visible = nd.get_switch('toggle_display_mode') == "PLAN"; layer.group.setVisible( visible ); if (visible) { layer.update(); } }, style: { svg_path: get_local_path('res/airbusAirplane.svg'), #translate: [-45,-52] }, options: { model: { parents: [geo.Coord], id: 999999, pos: props.globals.getNode('position'), type: 'position', latlon: func(){ me.pos = props.globals.getNode('position'); return [ me.pos.getValue("latitude-deg"), me.pos.getValue("longitude-deg"), me.pos.getValue("altitude-ft") ]; }, equals: func(o){me.id == o.id} }, init_after_callback: func{ var aplSymbol = me.element.getElementById("airplane"); aplSymbol.setTranslation(-45,-52); } } }, { name: 'DEBUG', isMapStructure: 1, always_update: 1, update_on: ['toggle_display_mode'], predicate: func(nd, layer){ var map_mode = nd.in_mode('toggle_display_mode', ['MAP', 'PLAN']); var debug_actv = getprop('autopilot/route-manager/debug/active') or 0; var visible = (map_mode and debug_actv); layer.group.setVisible( visible ); if (visible) { layer.update(); } } } ## add other layers here, layer names must match the registered names as used in *.layer files for now ## this will all change once we're using Philosopher's MapStructure framework ], # end of vector with configured layers # This is where SVG elements are configured by providing "behavior" hashes, i.e. for animations # to animate each SVG symbol, specify behavior via callbacks (predicate, and true/false implementation) # SVG identifier, callback etc # TODO: update_on([]), update_mode (update() vs. timers/listeners) # TODO: support putting symbols on specific layers features: [ { id: 'compass_mask', impl: { init: func(nd, symbol), predicate: func(nd) !nd.get_switch('toggle_centered'), is_true: func(nd) nd.symbols.compass_mask.show(), is_false: func(nd) nd.symbols.compass_mask.hide(), } }, { id: 'compass_mask_ctr', impl: { init: func(nd, symbol), predicate: func(nd) nd.get_switch('toggle_centered') or nd.in_mode('toggle_display_mode',['PLAN']), is_true: func(nd) nd.symbols.compass_mask_ctr.show(), is_false: func(nd) nd.symbols.compass_mask_ctr.hide(), } }, { # TODO: taOnly doesn't need to use getprop polling in update(), use a listener instead! id: 'taOnly', # the SVG ID impl: { # implementation hash init: func(nd, symbol), # for updateCenter stuff, called during initialization in the ctor predicate: func(nd) getprop("instrumentation/tcas/inputs/mode") == 2, # the condition is_true: func(nd) nd.symbols.taOnly.show(), # if true, run this is_false: func(nd) nd.symbols.taOnly.hide(), # if false, run this }, # end of taOnly behavior/callbacks }, # end of taOnly { id: 'tas', impl: { init: func(nd,symbol), predicate: func(nd) nd.aircraft_source.get_spd() > 100, is_true: func(nd) { nd.symbols.tas.setText(sprintf("%3.0f",getprop("/velocities/TAS") )); nd.symbols.tas.show(); }, is_false: func(nd) nd.symbols.tas.hide(), }, }, { id: 'tasLbl', impl: { init: func(nd,symbol), predicate: func(nd) nd.aircraft_source.get_spd() > 100, is_true: func(nd) nd.symbols.tasLbl.show(), is_false: func(nd) nd.symbols.tasLbl.hide(), }, }, { id: 'ilsFreq', impl: { init: func(nd,symbol), predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP', 'VOR']), is_true: func(nd) { nd.symbols.ilsFreq.show(); var is_ils = (nd.get_switch('toggle_display_mode') == 'APP'); var type = (is_ils ? 'ils' : 'vor'); var path = nd.get_nav_path(type, 0); nd.symbols.ilsFreq.setText(getprop(path~ "frequencies/selected-mhz-fmt")); if(is_ils) nd.symbols.ilsFreq.setColor(0.69,0,0.39); else nd.symbols.ilsFreq.setColor(1,1,1); }, is_false: func(nd) nd.symbols.ilsFreq.hide(), }, }, { id: 'ilsLbl', impl: { init: func(nd,symbol), predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP', 'VOR']), is_true: func(nd) { nd.symbols.ilsLbl.show(); if(nd.get_switch('toggle_display_mode') == 'APP') nd.symbols.ilsLbl.setText('ILS'); else nd.symbols.ilsLbl.setText('VOR 1'); }, is_false: func(nd) nd.symbols.ilsLbl.hide(), }, }, { id: 'wpActiveId', impl: { init: func(nd,symbol), predicate: func(nd) getprop("/autopilot/route-manager/wp/id") != nil and getprop("autopilot/route-manager/active") and nd.in_mode('toggle_display_mode', ['MAP', 'PLAN']), is_true: func(nd) { nd.symbols.wpActiveId.setText(getprop("/autopilot/route-manager/wp/id")); nd.symbols.wpActiveId.show(); }, is_false: func(nd) nd.symbols.wpActiveId.hide(), }, # of wpActiveId.impl }, # of wpActiveId { id: 'wpActiveCrs', impl: { init: func(nd,symbol), predicate: func(nd) getprop("/autopilot/route-manager/wp/id") != nil and getprop("autopilot/route-manager/active") and nd.in_mode('toggle_display_mode', ['MAP', 'PLAN']), is_true: func(nd) { #var cur_wp = getprop("autopilot/route-manager/current-wp"); var deg = int(getprop("/autopilot/route-manager/wp/bearing-deg")); nd.symbols.wpActiveCrs.setText(''~deg~'°'); nd.symbols.wpActiveCrs.show(); }, is_false: func(nd) nd.symbols.wpActiveCrs.hide(), }, # of wpActiveId.impl }, # of wpActiveId { id: 'wpActiveDist', impl: { init: func(nd,symbol), predicate: func(nd) getprop("/autopilot/route-manager/wp/dist") != nil and getprop("autopilot/route-manager/active") and nd.in_mode('toggle_display_mode', ['MAP', 'PLAN']), is_true: func(nd) { var dst = getprop("/autopilot/route-manager/wp/dist"); nd.symbols.wpActiveDist.setText(sprintf("%3.01f",dst)); nd.symbols.wpActiveDist.show(); }, is_false: func(nd) nd.symbols.wpActiveDist.hide(), }, }, { id: 'wpActiveDistLbl', impl: { init: func(nd,symbol), predicate: func(nd) getprop("/autopilot/route-manager/wp/dist") != nil and getprop("autopilot/route-manager/active") and nd.in_mode('toggle_display_mode', ['MAP', 'PLAN']), is_true: func(nd) { nd.symbols.wpActiveDistLbl.show(); if(getprop("/autopilot/route-manager/wp/dist") > 1000) nd.symbols.wpActiveDistLbl.setText(" NM"); }, is_false: func(nd) nd.symbols.wpActiveDistLbl.hide(), }, }, { id: 'eta', impl: { init: func(nd,symbol), predicate: func(nd) getprop("autopilot/route-manager/wp/eta") != nil and getprop("autopilot/route-manager/active") and nd.in_mode('toggle_display_mode', ['MAP', 'PLAN']), is_true: func(nd) { var etaSec = getprop("/sim/time/utc/day-seconds")+ getprop("autopilot/route-manager/wp/eta-seconds"); var h = math.floor(etaSec/3600); etaSec = etaSec-3600*h; var m = math.floor(etaSec/60); etaSec = etaSec-60*m; var s = etaSec / 10; if (h > 24) h = h - 24; nd.symbols.eta.setText(sprintf("%02.0f:%02.0f",h,m)); nd.symbols.eta.show(); }, is_false: func(nd) nd.symbols.eta.hide(), }, # of eta.impl }, # of eta { id: 'gsGroup', impl: { init: func(nd,symbol), predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP']), is_true: func(nd) { if(nd.get_switch('toggle_centered')) nd.symbols.gsGroup.setTranslation(0,0); else nd.symbols.gsGroup.setTranslation(0,150); nd.symbols.gsGroup.show(); }, is_false: func(nd) nd.symbols.gsGroup.hide(), }, }, { id:'hdg', impl: { init: func(nd,symbol), predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP','MAP','VOR']), is_true: func(nd) { var hdgText = ""; if(nd.in_mode('toggle_display_mode', ['MAP'])) { if(nd.get_switch('toggle_true_north')) hdgText = nd.aircraft_source.get_trk_tru(); else hdgText = nd.aircraft_source.get_trk_mag(); } else { if(nd.get_switch('toggle_true_north')) hdgText = nd.aircraft_source.get_hdg_tru(); else hdgText = nd.aircraft_source.get_hdg_mag(); } nd.symbols.hdg.setText(sprintf("%03.0f", hdgText+0.5)); }, is_false: NOTHING, }, }, { id:'hdgGroup', impl: { init: func(nd,symbol), predicate: func(nd) {return 0},#nd.in_mode('toggle_display_mode', ['APP','MAP','VOR']), is_true: func(nd) { nd.symbols.hdgGroup.show(); if(nd.get_switch('toggle_centered')) nd.symbols.hdgGroup.setTranslation(0,100); else nd.symbols.hdgGroup.setTranslation(0,0); }, is_false: func(nd) nd.symbols.hdgGroup.hide(), }, }, { id:'altArc', impl: { init: func(nd,symbol), predicate: func(nd) {return 0},#nd.in_mode('toggle_display_mode', ['APP','MAP','VOR']), is_true: func(nd) { nd.symbols.altArc.show(); }, is_false: func(nd) nd.symbols.altArc.hide(), }, }, { id:'gs', impl: { init: func(nd,symbol), common: func(nd) nd.symbols.gs.setText(sprintf("%3.0f",nd.aircraft_source.get_gnd_spd() )), predicate: func(nd) nd.aircraft_source.get_gnd_spd() >= 30, is_true: func(nd) { #nd.symbols.gs.show(); nd.symbols.gs.setFontSize(36); }, is_false: func(nd) {},#nd.symbols.gs.hide(), }, }, { id:'compass', impl: { init: func(nd,symbol), predicate: func(nd) (!nd.get_switch('toggle_centered') and nd.get_switch('toggle_display_mode') != "PLAN"), is_true: func(nd) { nd.symbols.compass.setRotation(-nd.userHdgTrk*D2R); nd.symbols.compass.show() }, is_false: func(nd) nd.symbols.compass.hide(), }, # of compass.impl }, # of compass { id:'compassApp', impl: { init: func(nd,symbol), predicate: func(nd) (nd.get_switch('toggle_centered') and nd.get_switch('toggle_display_mode') != "PLAN"), is_true: func(nd) { nd.symbols.compassApp.setRotation(-nd.userHdgTrk*D2R); nd.symbols.compassApp.show() }, is_false: func(nd) nd.symbols.compassApp.hide(), }, # of compassApp.impl }, # of compassApp { id:'northUp', impl: { init: func(nd,symbol), predicate: func(nd) nd.get_switch('toggle_display_mode') == "PLAN", is_true: func(nd) nd.symbols.northUp.show(), is_false: func(nd) nd.symbols.northUp.hide(), }, # of northUp.impl }, # of northUp { id:'planArcs', impl: { init: func(nd,symbol), predicate: func(nd) ((nd.in_mode('toggle_display_mode', ['APP','VOR','PLAN'])) or ((nd.get_switch('toggle_display_mode') == "MAP") and (nd.get_switch('toggle_centered')))), is_true: func(nd) nd.symbols.planArcs.show(), is_false: func(nd) nd.symbols.planArcs.hide(), }, # of planArcs.impl }, # of planArcs { id:'rangeArcs', impl: { init: func(nd,symbol), predicate: func(nd) ((nd.get_switch('toggle_display_mode') == "MAP") and (!nd.get_switch('toggle_centered'))), is_true: func(nd) nd.symbols.rangeArcs.show(), is_false: func(nd) nd.symbols.rangeArcs.hide(), }, # of rangeArcs.impl }, # of rangeArcs { id:'rangePln1', impl: { init: func(nd,symbol), predicate: func(nd) {return 0}, is_true: func(nd) { nd.symbols.rangePln1.show(); nd.symbols.rangePln1.setText(sprintf("%3.0f",nd.rangeNm())); }, is_false: func(nd) nd.symbols.rangePln1.hide(), }, }, { id:'rangePln2', impl: { init: func(nd,symbol), predicate: func(nd) nd.get_switch('toggle_display_mode') == "MAP" and !nd.get_switch('toggle_centered'), is_true: func(nd) { nd.symbols.rangePln2.show(); nd.symbols.rangePln2.setText(sprintf("%3.0f",(nd.rangeNm()/2) + (nd.rangeNm()/4))); }, is_false: func(nd) nd.symbols.rangePln2.hide(), }, }, { id:'rangePln3', impl: { init: func(nd,symbol), predicate: func(nd) nd.get_switch('toggle_display_mode') == "PLAN" or nd.get_switch('toggle_centered'), is_true: func(nd) { nd.symbols.rangePln3.show(); nd.symbols.rangePln3.setText(sprintf("%3.0f",nd.rangeNm()/2)); }, is_false: func(nd) nd.symbols.rangePln3.hide(), }, }, { id:'rangePln4', impl: { init: func(nd,symbol), predicate: func(nd) nd.get_switch('toggle_display_mode') == "PLAN" or nd.get_switch('toggle_centered'), is_true: func(nd) { nd.symbols.rangePln4.show(); nd.symbols.rangePln4.setText(sprintf("%3.0f",nd.rangeNm())); }, is_false: func(nd) nd.symbols.rangePln4.hide(), }, }, { id:'rangePln5', impl: { init: func(nd,symbol), predicate: func(nd) nd.get_switch('toggle_display_mode') == "MAP" and !nd.get_switch('toggle_centered'), is_true: func(nd) { nd.symbols.rangePln5.show(); nd.symbols.rangePln5.setText(sprintf("%3.0f",(nd.rangeNm()/2) + (nd.rangeNm()/4))); }, is_false: func(nd) nd.symbols.rangePln5.hide(), }, }, { id:'range', impl: { init: func(nd,symbol), predicate: func(nd) !nd.get_switch('toggle_centered'), is_true: func(nd) { nd.symbols.range.show(); nd.symbols.range.setText(sprintf("%3.0f",nd.rangeNm()/2)); }, is_false: func(nd) nd.symbols.range.hide(), }, }, { id:'range_r', impl: { init: func(nd,symbol), predicate: func(nd) !nd.get_switch('toggle_centered'), is_true: func(nd) { nd.symbols.range_r.show(); nd.symbols.range_r.setText(sprintf("%3.0f",nd.rangeNm()/2)); }, is_false: func(nd) nd.symbols.range_r.hide(), }, }, { id:'aplSymMap', impl: { init: func(nd,symbol), predicate: func(nd) (nd.get_switch('toggle_display_mode') == "MAP" and !nd.get_switch('toggle_centered')), is_true: func(nd) { nd.symbols.aplSymMap.set('z-index', 10); nd.symbols.aplSymMap.show(); }, is_false: func(nd) nd.symbols.aplSymMap.hide(), }, }, { id:'aplSymMapCtr', impl: { init: func(nd,symbol), predicate: func(nd) ((nd.get_switch('toggle_display_mode') == "MAP" and nd.get_switch('toggle_centered')) or nd.in_mode('toggle_display_mode', ['APP','VOR'])), is_true: func(nd) { nd.symbols.aplSymMapCtr.set('z-index', 10); nd.symbols.aplSymMapCtr.show(); }, is_false: func(nd) nd.symbols.aplSymMapCtr.hide(), }, }, { id:'aplSymVor', impl: { init: func(nd,symbol), predicate: func(nd) {return 0;}, is_true: func(nd) { nd.symbols.aplSymVor.show(); }, is_false: func(nd) nd.symbols.aplSymVor.hide(), }, }, { id:'crsLbl', impl: { init: func(nd,symbol), predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP','VOR']), is_true: func(nd) nd.symbols.crsLbl.show(), is_false: func(nd) nd.symbols.crsLbl.hide(), }, }, { id:'crs', impl: { init: func(nd,symbol), predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP','VOR']), is_true: func(nd) { nd.symbols.crs.show(); var is_ils = (nd.get_switch('toggle_display_mode') == 'APP'); var type = (is_ils ? 'ils' : 'vor'); var path = nd.get_nav_path(type, 0); var crs = getprop(path~ "radials/selected-deg"); if(crs != nil) nd.symbols.crs.setText(sprintf("%03.0f", crs)); }, is_false: func(nd) nd.symbols.crs.hide(), }, }, { id:'dmeLbl', impl: { init: func(nd,symbol), predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP','VOR']), is_true: func(nd) nd.symbols.dmeLbl.show(), is_false: func(nd) nd.symbols.dmeLbl.hide(), }, }, { id:'dme', impl: { init: func(nd,symbol), predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP','VOR']), is_true: func(nd) { nd.symbols.dme.show(); var is_ils = (nd.get_switch('toggle_display_mode') == 'APP'); var type = (is_ils ? 'ils' : 'vor'); var path = nd.get_nav_path(type, 0); nd.symbols.dme.setText(getprop(path~ "nav-id")); if(is_ils) nd.symbols.dme.setColor(0.69,0,0.39); else nd.symbols.dme.setColor(1,1,1); }, is_false: func(nd) nd.symbols.dme.hide(), }, }, { id:'trkline', impl: { init: func(nd,symbol), predicate: func(nd){ nd.get_switch('toggle_display_mode') == 'MAP' and !nd.get_switch('toggle_centered') and ( getprop(nd.options.defaults.lat_ctrl) != nd.options.defaults.managed_val or nd.get_switch('toggle_trk_line') ) }, is_true: func(nd) { nd.symbols.trkline.show(); }, is_false: func(nd) nd.symbols.trkline.hide(), }, }, { id:'trkInd2', impl: { init: func(nd,symbol), predicate: func(nd) (nd.in_mode('toggle_display_mode', ['APP','VOR','MAP']) and nd.get_switch('toggle_centered')), is_true: func(nd) { nd.symbols.trkInd2.show(); nd.symbols.trkInd2.setRotation((nd.aircraft_source.get_trk_mag()-nd.aircraft_source.get_hdg_mag())*D2R); }, is_false: func(nd) nd.symbols.trkInd2.hide(), }, }, { id:'trkline2', impl: { init: func(nd,symbol), predicate: func(nd) (nd.get_switch('toggle_display_mode') == 'MAP' and nd.get_switch('toggle_centered') and getprop(nd.options.defaults.lat_ctrl) != nd.options.defaults.managed_val), is_true: func(nd) { nd.symbols.trkline2.show(); }, is_false: func(nd) nd.symbols.trkline2.hide(), }, }, { id:'vorCrsPtr', impl: { init: func(nd,symbol), predicate: func(nd) (nd.in_mode('toggle_display_mode', ['APP','VOR']) and !nd.get_switch('toggle_centered')), is_true: func(nd) { nd.symbols.vorCrsPtr.show(); if (is_ils) { nd.symbols.vorCrsPtr.setRotation((getprop("instrumentation/nav[0]/radials/selected-deg")-nd.aircraft_source.get_hdg_tru())*D2R); } else { nd.symbols.vorCrsPtr.setRotation((getprop("instrumentation/nav[2]/radials/selected-deg")-nd.aircraft_source.get_hdg_tru())*D2R); } }, is_false: func(nd) nd.symbols.vorCrsPtr.hide(), }, }, { id:'vorCrsPtr2', impl: { init: func(nd,symbol), predicate: func(nd) (nd.in_mode('toggle_display_mode', ['APP','VOR']) and nd.get_switch('toggle_centered')), is_true: func(nd) { nd.symbols.vorCrsPtr2.show(); var is_ils = (nd.get_switch('toggle_display_mode') == 'APP'); var type = (is_ils ? 'ils' : 'vor'); var path = nd.get_nav_path(type, 0); if (is_ils) { nd.symbols.vorCrsPtr2.setRotation((getprop("/instrumentation/nav[0]/radials/selected-deg")-nd.aircraft_source.get_hdg_tru())*D2R); } else { nd.symbols.vorCrsPtr2.setRotation((getprop("/instrumentation/nav[2]/radials/selected-deg")-nd.aircraft_source.get_hdg_tru())*D2R); } var line = nd.symbols.vorCrsPtr2.getElementById('vorCrsPtr2_line'); if(!is_ils){ line.setColor(0,0.62,0.84); line.setColorFill(0,0.62,0.84); } else { line.setColor(0.9,0,0.47); line.setColorFill(0.9,0,0.47); } }, is_false: func(nd) nd.symbols.vorCrsPtr2.hide(), }, }, { id: 'gsDiamond', impl: { init: func(nd,symbol), predicate: func(nd) nd.in_mode('toggle_display_mode', ['APP']), is_true: func(nd) { if(getprop("instrumentation/nav/gs-needle-deflection-norm") != nil) nd.symbols.gsDiamond.setTranslation(getprop("/instrumentation/nav[0]/gs-needle-deflection-norm")*150,0); }, is_false: func(nd) nd.symbols.gsGroup.hide(), }, }, { id:'locPtr', impl: { init: func(nd,symbol), predicate: func(nd) (nd.in_mode('toggle_display_mode', ['APP','VOR']) and !nd.get_switch('toggle_centered') and getprop("instrumentation/nav/in-range")), is_true: func(nd) { nd.symbols.locPtr.show(); var deflection = getprop("/instrumentation/nav[0]/heading-needle-deflection-norm"); nd.symbols.locPtr.setTranslation(deflection*150,0); }, is_false: func(nd) nd.symbols.locPtr.hide(), }, }, { id:'locPtr2', impl: { init: func(nd,symbol), predicate: func(nd) { var curmode = nd.get_switch('toggle_display_mode'); var is_ils = (curmode == 'APP'); var type = (is_ils ? 'ils' : 'vor'); var path = nd.get_nav_path(type, 0); return (nd.in_mode('toggle_display_mode', ['APP','VOR']) and nd.get_switch('toggle_centered') and getprop(path~ "in-range")); }, is_true: func(nd) { var curmode = nd.get_switch('toggle_display_mode'); var is_ils = (curmode == 'APP'); var type = (is_ils ? 'ils' : 'vor'); var path = nd.get_nav_path(type, 0); nd.symbols.locPtr2.show(); var deflection = getprop(path~ "heading-needle-deflection-norm"); nd.symbols.locPtr2.setTranslation(deflection*150,0); var line = nd.symbols.locPtr2.getElementById('locPtr2_line'); var arr1 = nd.symbols.locPtr2.getElementById('locPtr2_arr1'); var arr2 = nd.symbols.locPtr2.getElementById('locPtr2_arr2'); if(!is_ils){ #nd.symbols.vorCrsPtr2.setColor(0,0.62,0.84); line.setColor(0,0.62,0.84); line.setColorFill(0,0.62,0.84); arr1.show(); arr2.show(); } else { line.setColor(0.9,0,0.47); line.setColorFill(0.9,0,0.47); arr1.hide(); arr2.hide(); } }, is_false: func(nd) nd.symbols.locPtr2.hide(), }, }, { id:'locTrkPointer', impl: { init: func(nd,symbol), predicate: func(nd) { var nav_id = getprop("/instrumentation/nav/nav-id"); var ils_mode = getprop('/flight-management/freq/ils-mode'); var has_ils = (nav_id != nil and nav_id != ''); (nd.get_switch('toggle_display_mode') == 'MAP' and !nd.get_switch('toggle_centered') and has_ils and ils_mode); }, is_true: func(nd) { nd.symbols.locTrkPointer.show(); var crs = getprop("instrumentation/nav/radials/selected-deg"); var rotation = (crs - nd.aircraft_source.get_hdg_tru())*D2R; nd.symbols.locTrkPointer.setRotation(rotation); }, is_false: func(nd) nd.symbols.locTrkPointer.hide(), }, }, { id:'locTrkPointer2', impl: { init: func(nd,symbol), predicate: func(nd) { var nav_id = getprop("/instrumentation/nav/nav-id"); var ils_mode = getprop('/flight-management/freq/ils-mode'); var has_ils = (nav_id != nil and nav_id != ''); (nd.get_switch('toggle_display_mode') == 'MAP' and nd.get_switch('toggle_centered') and has_ils and ils_mode); }, is_true: func(nd) { nd.symbols.locTrkPointer2.show(); var crs = getprop("instrumentation/nav/radials/selected-deg"); var rotation = (crs - nd.aircraft_source.get_hdg_tru())*D2R; nd.symbols.locTrkPointer2.setRotation(rotation); }, is_false: func(nd) nd.symbols.locTrkPointer2.hide(), }, }, { id:'wind', impl: { init: func(nd,symbol), predicate: ALWAYS, is_true: func(nd) { var windDir = getprop("environment/wind-from-heading-deg"); if(!nd.get_switch('toggle_true_north')) windDir = windDir + getprop("environment/magnetic-variation-deg"); nd.symbols.wind.setText(sprintf("%03.0f / %02.0f",windDir,getprop("environment/wind-speed-kt"))); }, is_false: NOTHING, }, }, { id:'windArrow', impl: { init: func(nd,symbol), predicate: func(nd) (!(nd.in_mode('toggle_display_mode', ['PLAN']) and (nd.get_switch('toggle_display_type') == "LCD"))), is_true: func(nd) { nd.symbols.windArrow.show(); var windArrowRot = getprop("environment/wind-from-heading-deg"); if(nd.in_mode('toggle_display_mode', ['MAP','PLAN'])) { if(nd.get_switch('toggle_true_north')) windArrowRot = windArrowRot - nd.aircraft_source.get_trk_tru(); else windArrowRot = windArrowRot - nd.aircraft_source.get_trk_mag(); } else { if(nd.get_switch('toggle_true_north')) windArrowRot = windArrowRot - nd.aircraft_source.get_hdg_tru(); else windArrowRot = windArrowRot - nd.aircraft_source.get_hdg_mag(); } nd.symbols.windArrow.setRotation(windArrowRot*D2R); }, is_false: func(nd) nd.symbols.windArrow.hide(), }, }, { id:'staToL2', impl: { init: func(nd,symbol), predicate: func(nd) { var path = nd.get_nav_path('vor', 0); return !(nd.in_mode('toggle_display_mode', ['PLAN'])) and nd.get_switch('toggle_centered') and ((getprop(path~ "in-range") and nd.get_switch('toggle_lh_vor_adf') == 1) or (getprop("instrumentation/adf/in-range") and nd.get_switch('toggle_lh_vor_adf') == -1)); }, is_true: func(nd) { if(nd.get_switch('toggle_lh_vor_adf') < 0){ nd.symbols.staToL2.setColor(0.195,0.96,0.097); nd.symbols.staFromL2.setColor(0.195,0.96,0.097); } else { nd.symbols.staToL2.setColor(1,1,1); nd.symbols.staFromL2.setColor(1,1,1); } nd.symbols.staToL2.show(); nd.symbols.staFromL2.show(); }, is_false: func(nd){ nd.symbols.staToL2.hide(); nd.symbols.staFromL2.hide(); } } }, { id:'staToR2', impl: { init: func(nd,symbol), predicate: func(nd) { var path = nd.get_nav_path('vor', 1); return !(nd.in_mode('toggle_display_mode', ['PLAN'])) and nd.get_switch('toggle_centered') and ((getprop(path~ "in-range") and nd.get_switch('toggle_rh_vor_adf') == 1) or (getprop("instrumentation/adf[1]/in-range") and nd.get_switch('toggle_rh_vor_adf') == -1)); }, is_true: func(nd) { if(nd.get_switch('toggle_rh_vor_adf') < 0){ nd.symbols.staToR2.setColor(0.195,0.96,0.097); nd.symbols.staFromR2.setColor(0.195,0.96,0.097); } else { nd.symbols.staToR2.setColor(1,1,1); nd.symbols.staFromR2.setColor(1,1,1); } nd.symbols.staToR2.show(); nd.symbols.staFromR2.show(); }, is_false: func(nd){ nd.symbols.staToR2.hide(); nd.symbols.staFromR2.hide(); } } }, { id:'staToL', impl: { init: func(nd,symbol), predicate: func(nd) { var path = nd.get_nav_path('vor', 0); return nd.in_mode('toggle_display_mode', ['MAP']) and !nd.get_switch('toggle_centered') and ((getprop(path~ "in-range") and nd.get_switch('toggle_lh_vor_adf') == 1) or (getprop("instrumentation/adf/in-range") and nd.get_switch('toggle_lh_vor_adf') == -1)); }, is_true: func(nd) { if(nd.get_switch('toggle_lh_vor_adf') < 0){ nd.symbols.staToL.setColor(0.195,0.96,0.097); nd.symbols.staFromL.setColor(0.195,0.96,0.097); } else { nd.symbols.staToL.setColor(1,1,1); nd.symbols.staFromL.setColor(1,1,1); } nd.symbols.staToL.show(); nd.symbols.staFromL.show(); }, is_false: func(nd){ nd.symbols.staToL.hide(); nd.symbols.staFromL.hide(); } } }, { id:'staToR', impl: { init: func(nd,symbol), predicate: func(nd) { var path = nd.get_nav_path('vor', 1); return nd.in_mode('toggle_display_mode', ['MAP']) and !nd.get_switch('toggle_centered') and ((getprop(path~ "in-range") and nd.get_switch('toggle_rh_vor_adf') == 1) or (getprop("instrumentation/adf[1]/in-range") and nd.get_switch('toggle_rh_vor_adf') == -1)); }, is_true: func(nd) { if(nd.get_switch('toggle_rh_vor_adf') < 0){ nd.symbols.staToR.setColor(0.195,0.96,0.097); nd.symbols.staFromR.setColor(0.195,0.96,0.097); } else { nd.symbols.staToR.setColor(1,1,1); nd.symbols.staFromR.setColor(1,1,1); } nd.symbols.staToR.show(); nd.symbols.staFromR.show(); }, is_false: func(nd){ nd.symbols.staToR.hide(); nd.symbols.staFromR.hide(); } } }, { id:'dmeL', impl: { init: func(nd,symbol), predicate: func(nd) (nd.get_switch('toggle_lh_vor_adf') != 0), is_true: func(nd) { nd.symbols.dmeL.show(); if(nd.get_switch('toggle_lh_vor_adf') < 0){ nd.symbols.vorL.setText("ADF 1"); nd.symbols.vorL.setColor(0.195,0.96,0.097); nd.symbols.vorLId.setColor(0.195,0.96,0.097); nd.symbols.dmeLDist.setColor(0.195,0.96,0.097); } else{ nd.symbols.vorL.setText("VOR 1"); nd.symbols.vorL.setColor(1,1,1); nd.symbols.vorLId.setColor(1,1,1); nd.symbols.dmeLDist.setColor(1,1,1); } nd.symbols.dmeL.setText('NM'); nd.symbols.dmeL.setColor(0,0.59,0.8); }, is_false: func(nd){ nd.symbols.dmeL.hide(); } } }, { id:'dmeR', impl: { init: func(nd,symbol), predicate: func(nd) (nd.get_switch('toggle_rh_vor_adf') != 0), is_true: func(nd) { nd.symbols.dmeR.show(); if(nd.get_switch('toggle_rh_vor_adf') < 0){ nd.symbols.vorR.setText("ADF 2"); nd.symbols.vorR.setColor(0.195,0.96,0.097); nd.symbols.vorRId.setColor(0.195,0.96,0.097); nd.symbols.dmeRDist.setColor(0.195,0.96,0.097); } else { nd.symbols.vorR.setText("VOR 2"); nd.symbols.vorR.setColor(1,1,1); nd.symbols.vorRId.setColor(1,1,1); nd.symbols.dmeRDist.setColor(1,1,1); } nd.symbols.dmeR.setText('NM'); nd.symbols.dmeR.setColor(0,0.59,0.8); }, is_false: func(nd){ nd.symbols.dmeR.hide(); } } }, { id: 'vorL', impl: { init: func(nd,symbol), predicate: func(nd) (nd.get_switch('toggle_lh_vor_adf') != 0), is_true: func(nd) { nd.symbols.vorL.show(); nd.symbols.vorLId.show(); nd.symbols.dmeLDist.show(); if(nd.get_switch('toggle_lh_vor_adf') < 0){ var adf = 'instrumentation/adf/'; var navident = getprop(adf~ "ident"); var frq = getprop(adf~ "frequencies/selected-khz"); if(navident != "") nd.symbols.vorLId.setText(navident); else nd.symbols.vorLId.setText(sprintf("%3d", frq)); nd.symbols.dmeLDist.setText(""); } else { var nav = nd.get_nav_path('vor', 0); var navID = getprop(nav~"nav-id"); var frq = getprop(nav~"frequencies/selected-mhz-fmt"); var dme = nd.get_nav_path('dme', 0); var dst = getprop(dme~ "indicated-distance-nm"); #print(dme~ "indicated-distance-nm"); if(getprop(nav~ "in-range")) nd.symbols.vorLId.setText(navID); else nd.symbols.vorLId.setText(frq); if(getprop(dme~ "in-range")) nd.symbols.dmeLDist.setText(sprintf("%3.1f", dst)); else nd.symbols.dmeLDist.setText(" ---"); } }, is_false: func(nd){ nd.symbols.vorL.hide(); nd.symbols.vorLId.hide(); nd.symbols.dmeLDist.hide(); } } }, { id:'vorLSym', impl: { init: func(nd,symbol), predicate: func(nd) (nd.get_switch('toggle_lh_vor_adf') != 0), is_true: func(nd) { nd.symbols.vorLSym.show(); }, is_false: func(nd){ nd.symbols.vorLSym.hide(); } } }, { id:'vorRSym', impl: { init: func(nd,symbol), predicate: func(nd) (nd.get_switch('toggle_rh_vor_adf') != 0), is_true: func(nd) { nd.symbols.vorRSym.show(); }, is_false: func(nd){ nd.symbols.vorRSym.hide(); } } }, { id:'appMode', impl: { init: func(nd,symbol), predicate: func(nd) { var mode = getprop(nd.options.defaults.app_mode); return (mode != '' and mode != nil); }, is_true: func(nd) { var mode = getprop(nd.options.defaults.app_mode); nd.symbols.appMode.show(); nd.symbols.appMode.setText(mode); }, is_false: func(nd){ nd.symbols.appMode.hide(); } } }, { id:'chrono_box', impl: { init: func(nd,symbol), predicate: func(nd) nd.get_switch('toggle_chrono'), is_true: func(nd) { var efis_node = props.globals.getNode(nd.efis_path); var idx = efis_node.getIndex() or 0; var chronoNode = nd.options.defaults.chrono_node~'['~idx~']'; chronoNode = props.globals.getNode(chronoNode); var time = nil; if(chronoNode != nil){ time = chronoNode.getValue('text'); } nd.symbols.chrono_box.show(); if(time != nil and time != '') nd.symbols.chrono_text.setText(time); }, is_false: func(nd){ nd.symbols.chrono_box.hide(); } } }, { id:'chrono_text', impl: { init: func(nd,symbol), predicate: func(nd) 1, is_true: func(nd) nd.symbols.chrono_text.show(), is_false: func(nd) nd.symbols.chrono_text.hide(), } }, { id:'degreeArrows', impl: { init: func(nd,symbol), predicate: func(nd) (nd.get_switch('toggle_display_mode') != 'PLAN' and nd.get_switch('toggle_centered')), is_true: func(nd) { nd.symbols.degreeArrows.show(); }, is_false: func(nd){ nd.symbols.degreeArrows.hide(); } } }, { id: 'legDistL', impl: { init: func(nd,symbol), predicate: func(nd) (nd.get_switch('toggle_display_mode') == 'MAP' and !nd.get_switch('toggle_centered')), is_true: func(nd){ var active = getprop('autopilot/route-manager/active'); var lat_ctrl = getprop(nd.options.defaults.lat_ctrl); var managed_v = nd.options.defaults.managed_val; var is_managed = (lat_ctrl == managed_v); var toggle_xtrk_err = nd.get_switch('toggle_xtrk_error'); if((!active or is_managed) and !toggle_xtrk_err){ nd.symbols.legDistL.hide(); } else { var dist = getprop('instrumentation/gps/wp/wp[1]/course-error-nm'); if(dist == nil or dist == '' or dist > -0.1){ nd.symbols.legDistL.hide(); } else { dist = sprintf('%.1fL', math.abs(dist)); nd.symbols.legDistL.setText(dist); nd.symbols.legDistL.show(); } } }, is_false: func(nd){ nd.symbols.legDistL.hide(); } } }, { id: 'legDistR', impl: { init: func(nd,symbol), predicate: func(nd) (nd.get_switch('toggle_display_mode') == 'MAP' and !nd.get_switch('toggle_centered')), is_true: func(nd){ var active = getprop('autopilot/route-manager/active'); var lat_ctrl = getprop(nd.options.defaults.lat_ctrl); var managed_v = nd.options.defaults.managed_val; var is_managed = (lat_ctrl == managed_v); var toggle_xtrk_err = nd.get_switch('toggle_xtrk_error'); if((!active or is_managed) and !toggle_xtrk_err){ nd.symbols.legDistR.hide(); } else { var dist = getprop('instrumentation/gps/wp/wp[1]/course-error-nm'); if(dist == nil or dist == '' or dist < 0.1){ nd.symbols.legDistR.hide(); } else { dist = sprintf('%.1fR', math.abs(dist)); nd.symbols.legDistR.setText(dist); nd.symbols.legDistR.show(); } } }, is_false: func(nd){ nd.symbols.legDistR.hide(); } } }, { id: 'legDistCtrL', impl: { init: func(nd,symbol), predicate: func(nd) (nd.get_switch('toggle_display_mode') == 'MAP' and nd.get_switch('toggle_centered')), is_true: func(nd){ var active = getprop('autopilot/route-manager/active'); var lat_ctrl = getprop(nd.options.defaults.lat_ctrl); var managed_v = nd.options.defaults.managed_val; var is_managed = (lat_ctrl == managed_v); var toggle_xtrk_err = nd.get_switch('toggle_xtrk_error'); if((!active or is_managed) and !toggle_xtrk_err){ nd.symbols.legDistCtrL.hide(); } else { var dist = getprop('instrumentation/gps/wp/wp[1]/course-error-nm'); if(dist == nil or dist == '' or dist > -0.1){ nd.symbols.legDistCtrL.hide(); } else { dist = sprintf('%.1fL', math.abs(dist)); nd.symbols.legDistCtrL.setText(dist); nd.symbols.legDistCtrL.show(); } } }, is_false: func(nd){ nd.symbols.legDistCtrL.hide(); } } }, { id: 'legDistCtrR', impl: { init: func(nd,symbol), predicate: func(nd) (nd.get_switch('toggle_display_mode') == 'MAP' and nd.get_switch('toggle_centered')), is_true: func(nd){ var active = getprop('autopilot/route-manager/active'); var lat_ctrl = getprop(nd.options.defaults.lat_ctrl); var managed_v = nd.options.defaults.managed_val; var is_managed = (lat_ctrl == managed_v); var toggle_xtrk_err = nd.get_switch('toggle_xtrk_error'); if((!active or is_managed) and !toggle_xtrk_err){ nd.symbols.legDistCtrR.hide(); } else { var dist = getprop('instrumentation/gps/wp/wp[1]/course-error-nm'); if(dist == nil or dist == '' or dist < 0.1){ nd.symbols.legDistCtrR.hide(); } else { dist = sprintf('%.1fR', math.abs(dist)); nd.symbols.legDistCtrR.setText(dist); nd.symbols.legDistCtrR.show(); } } }, is_false: func(nd){ nd.symbols.legDistCtrR.hide(); } } }, { id: 'offsetLbl', impl: { init: func(nd,symbol), predicate: func(nd) (nd.in_mode('toggle_display_mode', ['MAP', 'PLAN'])), is_true: func(nd){ var active = getprop('autopilot/route-manager/active'); var lat_ctrl = getprop(nd.options.defaults.lat_ctrl); var managed_v = nd.options.defaults.managed_val; var is_managed = (lat_ctrl == managed_v); var offset = getprop(nd.options.defaults.fpln_offset); var has_offset = (offset != nil and offset != '' and offset != 0); if(!active or !is_managed or !has_offset){ nd.symbols.offsetLbl.hide(); } else { nd.symbols.offsetLbl.setText("OFST\n"~ offset); nd.symbols.offsetLbl.show(); } }, is_false: func(nd){ nd.symbols.offsetLbl.hide(); } } } ], # end of vector with features };