ea32a92fe7
When using a data provider, or Emesary it is useful to be able to pass an optional element into the update method for the pages.
325 lines
11 KiB
Text
325 lines
11 KiB
Text
# Generic Page switching cockpit display device.
|
|
# ---------------------------
|
|
# Richard Harrison: 2015-10-17 : rjh@zaretto.com
|
|
# ---------------------------
|
|
# I'm calling this a PFD as in Programmable Function Display.
|
|
# ---------------------------
|
|
# documentation: see http://wiki.flightgear.org/Canvas_MFD_Framework
|
|
# See FGAddon/Aircraft/F-15/Nasal/MPCD/MPCD_main.nas for an example usage
|
|
# ---------------------------
|
|
# This is but a straightforwards wrapper to provide the core logic that page switching displays require.
|
|
# Examples of Page switching displays
|
|
# * MFD
|
|
# * PFD
|
|
# * FMCS
|
|
# * F-15 MPCD
|
|
|
|
#
|
|
# Menu Item. There is a list of these for each page changing button per display page
|
|
# Parameters:
|
|
# menu_id : page change event id for this menu item. e.g. button number
|
|
# title : Title Text (for display on the device)
|
|
# page : Instance of page usually returned from PFD.addPage
|
|
|
|
var PFD_MenuItem =
|
|
{
|
|
new : func (menu_id, title, page)
|
|
{
|
|
var obj = {parents : [PFD_MenuItem] };
|
|
obj.page = page;
|
|
obj.menu_id = menu_id;
|
|
obj.title = title;
|
|
return obj;
|
|
},
|
|
};
|
|
|
|
#
|
|
#
|
|
# Create a new PFD Page
|
|
# - related svg
|
|
# - Title: Page title
|
|
# - SVG element for the page
|
|
# - Device to attach the page to
|
|
|
|
var PFD_Page =
|
|
{
|
|
new : func (svg, title, layer_id, device)
|
|
{
|
|
var obj = {parents : [PFD_Page] };
|
|
obj.title = title;
|
|
obj.device = device;
|
|
obj.layer_id = layer_id;
|
|
obj.menus = [];
|
|
obj.svg = svg.getElementById(layer_id);
|
|
if(obj.svg == nil)
|
|
printf("PFD_Device: Error loading %s: svg layer %s ",title, layer_id);
|
|
|
|
return obj;
|
|
},
|
|
|
|
#
|
|
# Makes a page visible.
|
|
# It is the responsibility of the caller to manage the visibility of pages - i.e. to
|
|
# make a page that is currenty visible not visible before making a new page visible,
|
|
# however more than one page could be visible - but only one set of menu buttons can be active
|
|
# so if two pages are visible (e.g. an overlay) then when the overlay removed it would be necessary
|
|
# to call setVisible on the base page to ensure that the menus are seutp
|
|
setVisible : func(vis)
|
|
{
|
|
if(me.svg != nil)
|
|
me.svg.setVisible(vis);
|
|
|
|
if (vis)
|
|
me.ondisplay();
|
|
else
|
|
me.offdisplay();
|
|
},
|
|
|
|
#
|
|
# Perform action when button is pushed
|
|
notifyButton : func(button_id)
|
|
{ foreach(var mi; me.menus)
|
|
{
|
|
if (mi.menu_id == button_id)
|
|
{
|
|
me.device.selectPage(mi.page);
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
|
|
#
|
|
# Add an item to a menu
|
|
# Params:
|
|
# menu button id (that is set in controls/PFD/button-pressed by the model)
|
|
# title of the menu for the label
|
|
# page that will be selected when pressed
|
|
#
|
|
# The corresponding menu for the selected page will automatically be loaded
|
|
addMenuItem : func(menu_id, title, page)
|
|
{
|
|
var nm = PFD_MenuItem.new(menu_id, title, page);
|
|
append(me.menus, nm);
|
|
return nm;
|
|
},
|
|
|
|
# base method for update; this can be overriden per page instance to provide update of the
|
|
# elements on display (e.g. to display updated properties)
|
|
update : func(notification=nil)
|
|
{
|
|
},
|
|
|
|
#
|
|
# notify the page that it is being displayed. use to load any static framework or perform one
|
|
# time initialisation
|
|
ondisplay : func
|
|
{
|
|
},
|
|
|
|
#
|
|
# notify the page that it is going off display; use to clean up any created elements or perform
|
|
# any other required functions
|
|
offdisplay : func
|
|
{
|
|
},
|
|
};
|
|
|
|
|
|
#
|
|
# Container device for pages.
|
|
var PFD_Device =
|
|
{
|
|
# - svg is the page elements from the svg.
|
|
# - num_menu_buttons is the Number of menu buttons; starting from the bottom left then right, then top, then left.
|
|
# - button prefix (e.g MI_) is the prefix of the labels in the SVG for the menu boxes.
|
|
# - _canvas is the canvas group.
|
|
#NOTE:
|
|
# This does not actually create the canvas elements, or parse the SVG, that would typically be done in
|
|
# a higher level class that contains an instance of this class.
|
|
# see: http://wiki.flightgear.org/Canvas_MFD_Framework
|
|
new : func(svg, num_menu_buttons, button_prefix, _canvas)
|
|
{
|
|
var obj = {parents : [PFD_Device] };
|
|
obj.svg = svg;
|
|
obj.canvas = _canvas;
|
|
obj.current_page = nil;
|
|
obj.pages = [];
|
|
obj.page_index = {};
|
|
obj.buttons = setsize([], num_menu_buttons);
|
|
|
|
for(var idx = 0; idx < num_menu_buttons; idx += 1)
|
|
{
|
|
var label_name = sprintf(button_prefix~"%d",idx);
|
|
var msvg = obj.svg.getElementById(label_name);
|
|
if (msvg == nil)
|
|
printf("PFD_Device: Failed to load %s",label_name);
|
|
else
|
|
{
|
|
obj.buttons[idx] = msvg;
|
|
obj.buttons[idx].setText(sprintf("M",idx));
|
|
}
|
|
}
|
|
return obj;
|
|
},
|
|
#
|
|
# called when a button is pushed - connecting the property to this method is implemented in the outer class
|
|
notifyButton : func(button_id)
|
|
{
|
|
#
|
|
# by convention the buttons we have are 0 based; however externally 0 is used
|
|
# to indicate no button pushed.
|
|
if (button_id > 0)
|
|
{
|
|
button_id = button_id - 1;
|
|
if (me.current_page != nil)
|
|
{
|
|
me.current_page.notifyButton(button_id);
|
|
}
|
|
else
|
|
printf("PFD_Device: Could not locate page for button ",button_id);
|
|
}
|
|
},
|
|
#
|
|
#
|
|
# add a page to the device.
|
|
# - page title.
|
|
# - svg element id
|
|
addPage : func(title, layer_id)
|
|
{
|
|
var np = PFD_Page.new(me.svg, title, layer_id, me);
|
|
append(me.pages, np);
|
|
me.page_index[layer_id] = np;
|
|
np.setVisible(0);
|
|
return np;
|
|
},
|
|
#
|
|
# manage the update of the currently selected page
|
|
update : func(notification=nil)
|
|
{
|
|
if (me.current_page != nil)
|
|
me.current_page.update(notification);
|
|
},
|
|
#
|
|
# Change to display the selected page.
|
|
# - the page object method controls the visibility
|
|
selectPage : func(p)
|
|
{
|
|
if (me.current_page != nil)
|
|
me.current_page.setVisible(0);
|
|
if (me.buttons != nil)
|
|
{
|
|
foreach(var mb ; me.buttons)
|
|
if (mb != nil)
|
|
mb.setVisible(0);
|
|
|
|
foreach(var mi ; p.menus)
|
|
{
|
|
if (me.buttons[mi.menu_id] != nil)
|
|
{
|
|
me.buttons[mi.menu_id].setText(mi.title);
|
|
me.buttons[mi.menu_id].setVisible(1);
|
|
}
|
|
else
|
|
printf("PFD_device: Menu for button not found. Menu ID '%s'",mi.menu_id);
|
|
}
|
|
}
|
|
p.setVisible(1);
|
|
me.current_page = p;
|
|
},
|
|
#
|
|
# ensure that the menus are display correctly for the current page.
|
|
updateMenus : func
|
|
{
|
|
foreach(var mi ; me.current_page.menus)
|
|
{
|
|
if (me.buttons[mi.menu_id] != nil)
|
|
{
|
|
me.buttons[mi.menu_id].setText(mi.title);
|
|
me.buttons[mi.menu_id].setVisible(1);
|
|
}
|
|
else
|
|
printf("No corresponding item '%s'",mi.menu_id);
|
|
}
|
|
},
|
|
};
|
|
|
|
var PFD_NavDisplay =
|
|
{
|
|
#
|
|
# Instantiate parameters:
|
|
# 1. pfd_device (instance of PFD_Device)
|
|
# 2. instrument display ident (e.g. mfd-map, or mfd-map-left mfd-map-right for multiple displays)
|
|
# (this is used to map to the property tree)
|
|
# 3. layer_id: main layer in the SVG
|
|
# 4. nd_group_ident : group (usually within the main layer) to place the NavDisplay
|
|
# 5. switches - used to connect the property tree to the nav display. see the canvas nav display
|
|
# documentation
|
|
new : func (pfd_device, title, instrument_ident, layer_id, nd_group_ident, switches=nil, map_style="Boeing")
|
|
{
|
|
var obj = pfd_device.addPage(title, layer_id);
|
|
|
|
# if no switches given then use a default set.
|
|
if (switches != nil)
|
|
obj.switches = switches;
|
|
else
|
|
obj.switches = {
|
|
'toggle_range': { path: '/inputs/range-nm', value: 50, type: 'INT' },
|
|
'toggle_weather': { path: '/inputs/wxr', value: 0, type: 'BOOL' },
|
|
'toggle_airports': { path: '/inputs/arpt', value: 1, type: 'BOOL' },
|
|
'toggle_stations': { path: '/inputs/sta', value: 1, type: 'BOOL' },
|
|
'toggle_waypoints': { path: '/inputs/wpt', value: 1, 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: 1, type: 'BOOL' },
|
|
'toggle_centered': { path: '/inputs/nd-centered', value: 1, type: 'BOOL' },
|
|
'toggle_lh_vor_adf': { path: '/inputs/lh-vor-adf', value: 1, type: 'INT' },
|
|
'toggle_rh_vor_adf': { path: '/inputs/rh-vor-adf', value: 1, 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: 1, type: 'BOOL' },
|
|
};
|
|
|
|
obj.nd_initialised = 0;
|
|
obj.nd_placeholder_ident = nd_group_ident;
|
|
obj.nd_ident = instrument_ident;
|
|
obj.pfd_device = pfd_device;
|
|
|
|
obj.nd_init = func
|
|
{
|
|
me.ND = canvas.NavDisplay;
|
|
if (!me.nd_initialised)
|
|
{
|
|
me.nd_initialised = 1;
|
|
|
|
me.NDCpt = me.ND.new("instrumentation/"~me.nd_ident, me.switches,map_style);
|
|
|
|
me.group = me.pfd_device.svg.getElementById(me.nd_placeholder_ident);
|
|
me.group.setScale(0.39,0.45);
|
|
me.group.setTranslation(45,0);
|
|
me.NDCpt.newMFD(me.group, pfd_device.canvas);
|
|
}
|
|
me.NDCpt.update();
|
|
};
|
|
#
|
|
# Method overrides
|
|
#-----------------------------------------------
|
|
# Called when the page goes on display - need to delay initialization of the NavDisplay until later (it fails
|
|
# if done too early).
|
|
# NOTE: This causes a display "wobble" the first time on display as resizing happens. I've seen similar things
|
|
# happen on real avionics (when switched on) so it's not necessarily unrealistic -)
|
|
obj.ondisplay = func
|
|
{
|
|
if (!me.nd_initialised)
|
|
me.nd_init();
|
|
};
|
|
#
|
|
# most updates performed by the canvas nav display directly.
|
|
obj.update = func
|
|
{
|
|
};
|
|
return obj;
|
|
},
|
|
};
|