diff --git a/Nasal/canvas/MFD_Generic.nas b/Nasal/canvas/MFD_Generic.nas new file mode 100644 index 000000000..c13c717cb --- /dev/null +++ b/Nasal/canvas/MFD_Generic.nas @@ -0,0 +1,240 @@ +# Generic Page switching cockpit display device. +# I'm calling this a PFD as im Programmable Function Display. +# --------------------------- +# 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. +# Page switching displays +# * MFD +# * PFD +# * FMCS +# etc. +# Based on F-15 MPCD +# --------------------------- +# Richard Harrison: 2015-10-17 : rjh@zaretto.com +# --------------------------- + +# +# 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; +# printf("New MenuItem %s,%s,%s",menu_id, title, page); + 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 = []; +# print("Load page ",title); + 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); +# print("Set visible ",me.layer_id); + + if (vis) + { + me.ondisplay(); + foreach(mi ; me.menus) + { +# printf("load menu %s %\n",mi.title, mi); + } + } + else + me.offdisplay(); + }, +# +# +# Perform action when button is pushed + notifyButton : func(button_id) + { foreach(var mi; me.menus) + { + if (mi.menu_id == button_id) + { +# printf("Page: found button %s, selecting page\n",mi.title); + 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); +# printf("New menu %s %s on page ", menu_id, title, page.layer_id); + append(me.menus, nm); +# printf("Page %s: add menu %s [%s]",me.layer_id, menu_id, title); +# foreach(mi ; me.menus) + # { +# printf("--menu %s",mi.title); + # } + 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 + { + }, +# +# 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 + { + }, +}; + + +var PFD_Device = +{ +# +# create acontainer device for pages. +# - 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. + new : func(svg, num_menu_buttons, button_prefix) + { + var obj = {parents : [PFD_Device] }; + obj.svg = svg; + obj.current_page = nil; + obj.pages = []; + 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)); + } + } +# for(var idx = 0; idx < size(obj.buttons); idx += 1) +# { +# printf("Button %d %s",idx,obj.buttons[idx]); +# } + return obj; + }, +# +# called when a button is pushed + 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) + { +# printf("Button routing to %s",me.current_page.title); + 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); + np.setVisible(0); + return np; + }, +# +# manage the update of the currently selected page + update : func + { + if (me.current_page != nil) + me.current_page.update(); + }, +# +# select a page for display. + 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) + { +# printf("selectPage: load menu %d %s",mi.menu_id, mi.title); + 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; + }, +}; +