From 339064ce31ccf52325ecb3143172bd00a0a9b061 Mon Sep 17 00:00:00 2001 From: Stuart Buchanan Date: Sat, 3 Feb 2018 20:25:48 +0000 Subject: [PATCH] VOR symbology and Nearest VOR page. --- .../Instruments-3d/FG1000/Nasal/MFDPage.nas | 8 + .../Nasal/NavigationMap/NavigationMap.nas | 2 +- .../NavigationMap/NavigationMapController.nas | 2 +- .../NavigationMap/NavigationMapStyles.nas | 20 ++- .../NearestIntersections.nas | 2 - .../FG1000/Nasal/NearestVOR/NearestVOR.nas | 140 ++++++++++++++++-- .../Nasal/NearestVOR/NearestVORController.nas | 119 +++++++++++++-- Nasal/canvas/MapStructure.nas | 2 + 8 files changed, 260 insertions(+), 35 deletions(-) diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPage.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPage.nas index 7a8784fc4..d07257f1d 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPage.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPage.nas @@ -54,6 +54,14 @@ getTextElement : func(symbolName) { return me._symbols[symbolName]; }, +highlightTextElement : func(symbolName) { + me._symbols[symbolName].highlightElement(); +}, + +unhighlightTextElement : func(symbolName) { + me._symbols[symbolName].unhighlightElement(); +}, + getTextValue : func(symbolName) { var sym = me._symbols[symbolName]; assert(sym != nil, "Unknown text element " ~ symbolName ~ " (check your addTextElements call?)"); diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/NavigationMap/NavigationMap.nas b/Aircraft/Instruments-3d/FG1000/Nasal/NavigationMap/NavigationMap.nas index 676b66087..fc89c9e3a 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/NavigationMap/NavigationMap.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/NavigationMap/NavigationMap.nas @@ -55,7 +55,7 @@ var NavigationMap = var r = func(name,vis=1,zindex=nil) return caller(0)[0]; # TODO: we'll need some z-indexing here, right now it's just random - foreach(var type; [r('GRID'),r('DTO',0),r('TFC',0),r('APT'),r('DME'),r('VOR'),r('FIX',0),r('NDB'),r('GPS'),r('RTE'),r('WPT'),r('FLT'),r('WXR',0),r('APS')] ) { + foreach(var type; [r('GRID'),r('DTO',0),r('TFC',0),r('APT'),r('DME'),r('VOR_FG1000'),r('NDB'),r('FIX',0),r('GPS'),r('RTE'),r('WPT'),r('FLT'),r('WXR',0),r('APS')] ) { obj.MFDMap.addLayer( factory: canvas.SymbolLayer, type_arg: type.name, diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/NavigationMap/NavigationMapController.nas b/Aircraft/Instruments-3d/FG1000/Nasal/NavigationMap/NavigationMapController.nas index 939738a3d..8a0d84c43 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/NavigationMap/NavigationMapController.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/NavigationMap/NavigationMapController.nas @@ -51,7 +51,7 @@ var NavigationMapController = GRID : { enabled: 0, declutter: 1, range: 20, max_range: 2000 }, DME : { enabled: 1, declutter: 1, range: 150, max_range: 300 }, - VOR : { enabled: 1, declutter: 1, range: 150, max_range: 300 }, + VOR_FG1000 : { enabled: 1, declutter: 1, range: 150, max_range: 300 }, NDB : { enabled: 1, declutter: 1, range: 15, max_range: 30 }, FIX : { enabled: 1, declutter: 1, range: 15, max_range: 30 }, RTE : { enabled: 1, declutter: 3, range: 2000, max_range: 2000 }, diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/NavigationMap/NavigationMapStyles.nas b/Aircraft/Instruments-3d/FG1000/Nasal/NavigationMap/NavigationMapStyles.nas index 01a4ccd40..de21e943b 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/NavigationMap/NavigationMapStyles.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/NavigationMap/NavigationMapStyles.nas @@ -49,7 +49,7 @@ var NavigationMapStyles = me.Styles.FIX = {}; me.Styles.FIX.color = [0,0,0]; # White outline me.Styles.FIX.fill_color = [1,1,1,1]; # Black fill - me.Styles.FIX.scale_factor = 0.5; # 60% + me.Styles.FIX.scale_factor = 0.5; # 50% me.Styles.FIX.text_offset = [0, -12]; me.Styles.FIX.text_color = [0,0,0,1]; # Black text ... @@ -68,11 +68,19 @@ var NavigationMapStyles = me.Styles.NDB.text_padding = 2; me.Styles.NDB.text_alignment = 'center-bottom'; - - me.Styles.VOR = {}; - me.Styles.VOR.range_line_width = 2; - me.Styles.VOR.radial_line_width = 1; - me.Styles.VOR.scale_factor = 0.6; # 60% + me.Styles.VOR_FG1000 = {}; + me.Styles.VOR_FG1000.line_width = 1; + me.Styles.VOR_FG1000.scale_factor = 1.0; # 50% + me.Styles.VOR_FG1000.circle_radius = 128; + me.Styles.VOR_FG1000.icon_color = [0.0,0.0,0.5]; + me.Styles.VOR_FG1000.circle_color = [0.2,0.8,0.8]; + me.Styles.VOR_FG1000.text_offset = [0, -12]; + me.Styles.VOR_FG1000.text_color = [0,0,0,1]; # Black text ... + me.Styles.VOR_FG1000.text_bgcolor = [1,1,1,1]; # ... on a white background + me.Styles.VOR_FG1000.text_mode = canvas.Text.TEXT + canvas.Text.FILLEDBOUNDINGBOX; + me.Styles.VOR_FG1000.text_padding = 2; + me.Styles.VOR_FG1000.text_alignment = 'center-bottom'; + me.Styles.VOR_FG1000.font_size = 14; me.Styles.APS = {}; me.Styles.APS.scale_factor = 0.25; diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/NearestIntersections/NearestIntersections.nas b/Aircraft/Instruments-3d/FG1000/Nasal/NearestIntersections/NearestIntersections.nas index a44bd5978..c562b5551 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/NearestIntersections/NearestIntersections.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/NearestIntersections/NearestIntersections.nas @@ -113,8 +113,6 @@ var NearestIntersections = if (nav == nil) return; - debug.dump(nav); - if (nav.lat < 0.0) { me.setTextElement("Lat", sprintf("S %.4f", -nav.lat)); } else { diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/NearestVOR/NearestVOR.nas b/Aircraft/Instruments-3d/FG1000/Nasal/NearestVOR/NearestVOR.nas index ef71a9bec..4742e497b 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/NearestVOR/NearestVOR.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/NearestVOR/NearestVOR.nas @@ -10,34 +10,148 @@ var NearestVOR = ], }; - obj.topMenu(device, obj, nil); - obj.setController(fg1000.NearestVORController.new(obj, svg)); + # Dynamic elements. There is a single dynamic element containing the list of + # the 25 nearest intersections. + obj.select = PFD.GroupElement.new( + obj.pageName, + svg, + [ "Arrow", "ID", "CRS", "DST"], + 11, + "Arrow", + 1, + "ScrollTrough", + "ScrollThumb", + 250 - 116 + ); + + # Other dynamic text elements + obj.addTextElements(["Lat", "Lon", "Name", "Freq"]); + + obj.topMenu(device, obj, nil); + return obj; }, + + # Indicate which group is selected by colour of the softkeys + display_toggle : func(device, svg, mi, group) { + var bg_name = sprintf("SoftKey%d-bg",mi.menu_id); + if (me.getController().getSelectedGroup() == group) { + device.svg.getElementById(bg_name).setColorFill(0.5,0.5,0.5); + svg.setColor(0.0,0.0,0.0); + } else { + device.svg.getElementById(bg_name).setColorFill(0.0,0.0,0.0); + svg.setColor(1.0,1.0,1.0); + } + svg.setText(mi.title); + svg.setVisible(1); # display function + }, + + # Function to highlight the VOR softkey - used when CRSR is pressed to indicate + # that we're editing the VOR selection. + selectVOR : func() { + me.resetMenuColors(); + var bg_name = sprintf("SoftKey%d-bg",4); + var tname = sprintf("SoftKey%d",4); + me.device.svg.getElementById(bg_name).setColorFill(0.5,0.5,0.5); + me.device.svg.getElementById(tname).setColor(0.0,0.0,0.0); + }, + + hideCRSR : func() { + me.select.hideCRSR(); + me.unhighlightTextElement("Freq"); + me.resetMenuColors(); + }, + offdisplay : func() { - me._group.setVisible(0); + # The Nearest... pages use the underlying navigation map. + me.mfd.NavigationMap.offdisplayPartial(); # Reset the menu colours. Shouldn't have to do this here, but # there's not currently an obvious other location to do so. - for(var i = 0; i < 12; i +=1) { - var name = sprintf("SoftKey%d",i); - me.device.svg.getElementById(name ~ "-bg").setColorFill(0.0,0.0,0.0); - me.device.svg.getElementById(name).setColor(1.0,1.0,1.0); - } + me.resetMenuColors(); + me.getController().offdisplay(); }, ondisplay : func() { - me._group.setVisible(1); - me.mfd.setPageTitle(me.title); me.getController().ondisplay(); + + # The Nearest... pages use the underlying navigation map. + me.mfd.NavigationMap.ondisplayPartial(); + + me.mfd.setPageTitle(me.title); }, + updateNavData : func(navdata) { + + if ((navdata == nil) or (size(navdata) == 0)) return; + + var navDataList = []; + for (var i = 0; i < size(navdata); i = i + 1) { + var nav = navdata[i]; + var crsAndDst = courseAndDistance(nav); + + # Display the course and distance in NM . + # 248 is the extended ASCII code for the degree symbol + var crs = sprintf("%i%c", crsAndDst[0], 248); + var dst = sprintf("%.1fnm", crsAndDst[1]); + + # Convert into something we can pass straight to the UIGroup. + append(navDataList, { + Arrow : nav.id, + ID: nav.id, + CRS: crs, + DST: dst, + }); + } + + me.select.setValues(navDataList); + + if (size(navDataList) > 0) { + me.updateNavDataItem(navdata[0]); + } else { + me.setTextElement("Name", "NONE WITHIN 200NM"); + me.setTextElement("Lon", ""); + me.setTextElement("Lat", ""); + me.setTextElement("Frequency", ""); + } + }, + updateNavDataItem : func(nav) { + + if (nav == nil) return; + + if (nav.lat < 0.0) { + me.setTextElement("Lat", sprintf("S %.4f", -nav.lat)); + } else { + me.setTextElement("Lat", sprintf("N %.4f", nav.lat)); + } + + if (nav.lon < 0.0) { + me.setTextElement("Lon", sprintf("W%3.4f", -nav.lon)); + } else { + me.setTextElement("Lon", sprintf("E%3.4f", nav.lon)); + } + + me.setTextElement("Freq", sprintf("%.2f", nav.frequency / 100.0)); + me.setTextElement("Name", nav.name); + + # Display the DTO line to the airport + me.mfd.NavigationMap.getController().setDTOLineTarget(nav.lat, nav.lon); + }, + topMenu : func(device, pg, menuitem) { pg.clearMenu(); pg.resetMenuColors(); - device.updateMenus(); + pg.addMenuItem(0, "ENGINE", pg, pg.mfd.EIS.engineMenu); + pg.addMenuItem(2, "MAP", pg, pg.mfd.NavigationMap.mapMenu); + pg.addMenuItem(4, "VOR", pg, + func(dev, pg, mi) { pg.getController().selectVOR(); device.updateMenus(); }, # callback + func(svg, mi) { pg.display_toggle(device, svg, mi, NearestVORController.UIGROUP.VOR); } + ); + + pg.addMenuItem(5, "FREQ", pg, + func(dev, pg, mi) { pg.getController().selectFrequencies(); device.updateMenus(); }, # callback + func(svg, mi) { pg.display_toggle(device, svg, mi, NearestVORController.UIGROUP.FREQ); } + ); }, - - }; diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/NearestVOR/NearestVORController.nas b/Aircraft/Instruments-3d/FG1000/Nasal/NearestVOR/NearestVORController.nas index 5e5b5fd7c..0ad03ee5a 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/NearestVOR/NearestVORController.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/NearestVOR/NearestVORController.nas @@ -1,59 +1,154 @@ # NearestVOR Controller var NearestVORController = { + + UIGROUP : { + NONE : 0, # No group currently selected, + VOR : 1, + FREQ : 2, + }, + new : func (page, svg) { - var obj = { - parents : [ NearestVORController, MFDPageController.new(page) ], - _crsrToggle : 0, - _recipient : nil, - _page : page, - }; + var obj = { parents : [ NearestVORController, MFDPageController.new(page) ] }; + + obj.page = page; + obj._currentGroup = NearestVORController.UIGROUP.NONE; + obj._crsrToggle = 0; return obj; }, + selectVOR : func() { + me.selectGroup(NearestVORController.UIGROUP.VOR) + }, + selectFrequencies : func() { + me.selectGroup(NearestVORController.UIGROUP.FREQ); + }, + getSelectedGroup : func() { + return me._currentGroup; + }, + selectGroup : func(grp) { + me._currentGroup = grp; + if (grp == NearestVORController.UIGROUP.VOR) me.page.select.showCRSR() else me.page.select.hideCRSR(); + if (grp == NearestVORController.UIGROUP.FREQ) me.page.highlightTextElement("Freq") else me.page.unhighlightTextElement("Freq"); + me._crsrToggle = 1; + }, + # Input Handling handleCRSR : func() { me._crsrToggle = (! me._crsrToggle); if (me._crsrToggle) { + me.page.topMenu(me.page.device, me.page, nil); + me.page.selectVOR(); + me.selectVOR(); } else { - me._page.hideCRSR(); + me.page.hideCRSR(); } + return emesary.Transmitter.ReceiptStatus_Finished; }, handleFMSInner : func(value) { if (me._crsrToggle == 1) { - # Scroll through whatever is the current list + if (me._currentGroup == NearestVORController.UIGROUP.VOR) { + # Scroll through whatever is the current list + me.page.select.incrSmall(value); + var id = me.page.select.getValue(); + var data = me.getNavDataItem(id); + if ((data != nil) and (size(data) >0)) me.page.updateNavDataItem(data[0]); + } return emesary.Transmitter.ReceiptStatus_Finished; } else { - # Pass to the page group controller to display and scroll through the page group menu - return me._page.mfd.SurroundController.handleFMSInner(value); + return me.page.mfd.SurroundController.handleFMSInner(value); } }, handleFMSOuter : func(value) { if (me._crsrToggle == 1) { + if (me._currentGroup == NearestVORController.UIGROUP.VOR) { + # Scroll through whatever is the current list + me.page.select.incrSmall(value); + var id = me.page.select.getValue(); + var data = me.getNavDataItem(id); + if ((data != nil) and (size(data) >0)) me.page.updateNavDataItem(data[0]); + } return emesary.Transmitter.ReceiptStatus_Finished; } else { - # Pass to the page group controller to display and scroll through the page group menu - return me._page.mfd.SurroundController.handleFMSOuter(value); + return me.page.mfd.SurroundController.handleFMSOuter(value); } }, handleEnter : func(value) { if (me._crsrToggle == 1) { + if (me._currentGroup == NearestVORController.UIGROUP.VOR) { + # Scroll through whatever is the current list + me.page.select.incrSmall(value); + var id = me.page.select.getValue(); + var data = me.getNavDataItem(id); + if ((data != nil) and (size(data) >0)) me.page.updateNavDataItem(data[0]); + } + if (me._currentGroup == NearestVORController.UIGROUP.FREQ) { + var freq = me.page.getTextValue("Freq"); + if (freq != nil) { + me.page.mfd.SurroundController.setStandbyNavComFreq(freq); + } + } + return emesary.Transmitter.ReceiptStatus_Finished; } else { return emesary.Transmitter.ReceiptStatus_NotProcessed; } }, + handleRange : func(val) + { + # Pass any range entries to the NavMapController + me.page.mfd.NavigationMap.getController().handleRange(val); + }, + # Reset controller if required when the page is displayed or hidden ondisplay : func() { me.RegisterWithEmesary(); + var fixes = me.getNearestNavData("vor"); + me.page.updateNavData(fixes); + me.page.mfd.NavigationMap.getController().enableDTO(1); + me._crsrToggle = 0; + me.page.hideCRSR(); }, offdisplay : func() { + me.page.mfd.NavigationMap.getController().enableDTO(0); me.DeRegisterWithEmesary(); }, + getNearestNavData : func(type) { + var notification = notifications.PFDEventNotification.new( + "MFD", + 1, + notifications.PFDEventNotification.NavData, + {Id: "NavDataWithinRange", Value: type}); + + var response = me._transmitter.NotifyAll(notification); + + if (! me._transmitter.IsFailed(response)) { + return notification.EventParameter.Value; + } else { + return nil; + } + }, + + getNavDataItem : func(id) { + # Use Emesary to get the Navigation data + var notification = notifications.PFDEventNotification.new( + "MFD", + 1, + notifications.PFDEventNotification.NavData, + {Id: "NavAidByID", Value: { id: id, type: "vor"} }); + + var response = me._transmitter.NotifyAll(notification); + + if (! me._transmitter.IsFailed(response)) { + return notification.EventParameter.Value; + } else { + return nil; + } + }, }; diff --git a/Nasal/canvas/MapStructure.nas b/Nasal/canvas/MapStructure.nas index f1102d395..48c42382f 100644 --- a/Nasal/canvas/MapStructure.nas +++ b/Nasal/canvas/MapStructure.nas @@ -1491,6 +1491,7 @@ OverlayLayer.Controller = { ### # set up a cache for 32x32 symbols (initialized below in load_MapStructure) var SymbolCache32x32 = nil; +var SymbolCache256x256 = nil; var MapStructure = { # Generalized load methods used to load various symbols, layer controllers,... @@ -1609,6 +1610,7 @@ var load_MapStructure = func { # sets up a shared symbol cache, which will be used by all MapStructure maps and layers canvas.SymbolCache32x32 = SymbolCache.new(1024,32); + canvas.SymbolCache256x256 = SymbolCache.new(1024,256); # Find files and load them: var contents_dir = FG_ROOT~"/Nasal/canvas/map/";