240 lines
7.7 KiB
Text
240 lines
7.7 KiB
Text
# DirectTo Controller
|
|
var DirectToController =
|
|
{
|
|
# Vertical ranges, and labels.
|
|
# Unlike some other map displays, we keep the range constant at 4nm an change
|
|
# the ScreenRange to zoom in. Otherwise as we zoom in, the center of the
|
|
# runways moves out of the range of the display and they are not drawn.
|
|
# Ranges are scaled to the display height with range 1 displaying 4nm vertically.
|
|
# 2000nm = 12,152,000ft.
|
|
RANGES : [{range: 500/6076.12, label: "500ft"},
|
|
{range: 750/6076.12, label: "750ft"},
|
|
{range: 1000/6076.12, label: "1000ft"},
|
|
{range: 1500/6076.12, label: "1500ft"},
|
|
{range: 2000/6076.12, label: "2000ft"},
|
|
{range: 0.5, label: "0.5nm"},
|
|
{range: 0.75, label: "0.75nm"},
|
|
{range: 1, label: "1nm"},
|
|
{range: 2, label: "2nm"},
|
|
{range: 3, label: "3nm"},
|
|
{range: 4, label: "4nm"},
|
|
{range: 6, label: "6nm"},
|
|
{range: 8, label: "8nm"},
|
|
{range: 10, label: "10nm"},
|
|
{range: 12, label: "12nm"},
|
|
{range: 15, label: "15nm"},
|
|
{range: 20, label: "20nm"},
|
|
{range: 25, label: "25nm"},
|
|
{range: 30, label: "30nm"},
|
|
{range: 40, label: "40nm"},
|
|
{range: 50, label: "50nm"},
|
|
{range: 75, label: "75nm"},
|
|
{range: 100, label: "100nm"},
|
|
{range: 200, label: "200nm"},
|
|
{range: 500, label: "500nm"},
|
|
{range: 1000, label: "1000nm"},
|
|
{range: 1500, label: "1500nm"},
|
|
{range: 2000, label: "2000nm"}, ],
|
|
|
|
new : func (page, svg)
|
|
{
|
|
var obj = { parents : [ DirectToController, MFDPageController.new(page)] };
|
|
obj.id = "";
|
|
obj.page = page;
|
|
obj.current_zoom = 7;
|
|
|
|
obj.setZoom(obj.current_zoom);
|
|
|
|
obj._cursorElements = [
|
|
obj.page.IDEntry,
|
|
obj.page.VNVAltEntry,
|
|
obj.page.VNVOffsetEntry,
|
|
obj.page.CourseEntry,
|
|
obj.page.Activate
|
|
];
|
|
|
|
# -1 indicates nothing selected at present
|
|
obj._selectedElement = -1;
|
|
|
|
return obj;
|
|
},
|
|
|
|
setCursorElement : func(value) {
|
|
|
|
if (me._selectedElement != -1) {
|
|
# Unhighlight the current element, if one is highlighted
|
|
me._cursorElements[me._selectedElement ].unhighlightElement();
|
|
}
|
|
|
|
if (value < 0) value = 0;
|
|
if (value > (size(me._cursorElements) -1)) value = size(me._cursorElements) -1;
|
|
me._selectedElement = value;
|
|
me._cursorElements[me._selectedElement].highlightElement();
|
|
},
|
|
|
|
nextCursorElement : func(value) {
|
|
var incr_or_decr = (value > 0) ? 1 : -1;
|
|
me.setCursorElement(me._selectedElement + incr_or_decr);
|
|
},
|
|
|
|
# Control functions for Input
|
|
zoomIn : func() {
|
|
me.setZoom(me.current_zoom -1);
|
|
},
|
|
zoomOut : func() {
|
|
me.setZoom(me.current_zoom +1);
|
|
},
|
|
handleRange : func(val)
|
|
{
|
|
var incr_or_decr = (val > 0) ? 1 : -1;
|
|
me.setZoom(me.current_zoom + incr_or_decr);
|
|
},
|
|
setZoom : func(zoom) {
|
|
if ((zoom < 0) or (zoom > (size(me.RANGES) - 1))) return;
|
|
me.current_zoom = zoom;
|
|
me.page.setRange(me.RANGES[zoom].range, me.RANGES[zoom].label);
|
|
},
|
|
handleCRSR : func() {
|
|
# No effect, but shouldn't be passed to underlying page?
|
|
return emesary.Transmitter.ReceiptStatus_Finished;
|
|
},
|
|
handleFMSInner : func(value) {
|
|
if (me._selectedElement == -1) {
|
|
# TODO: handle display of waypoint submenu on anti-clockwise initial rotation!
|
|
# If no element is selected, then the inner FMS knob selects the ID field
|
|
me.nextCursorElement(1);
|
|
}
|
|
|
|
me._cursorElements[me._selectedElement].incrSmall(value);
|
|
return emesary.Transmitter.ReceiptStatus_Finished;
|
|
},
|
|
handleFMSOuter : func(value) {
|
|
if (me._selectedElement == -1) {
|
|
# If no element is selected, then the Outer FMS knob has no effect
|
|
return emesary.Transmitter.ReceiptStatus_Finished;
|
|
}
|
|
|
|
if (me._cursorElements[me._selectedElement].isInEdit()) {
|
|
me._cursorElements[me._selectedElement].incrLarge(value);
|
|
} else {
|
|
me.nextCursorElement(value);
|
|
}
|
|
|
|
return emesary.Transmitter.ReceiptStatus_Finished;
|
|
},
|
|
handleEnter : func(value) {
|
|
if (me._selectedElement == -1) {
|
|
# If no element is selected, then the ENT key has no effect
|
|
return emesary.Transmitter.ReceiptStatus_Finished;
|
|
}
|
|
|
|
# If we're on the Activate button, then set up the DirectTo and hide the
|
|
# page. We're finished
|
|
if (me._cursorElements[me._selectedElement] == me.page.Activate) {
|
|
var mappage = me._page.getMFD().getPage("NavigationMap");
|
|
assert(mappage != nil, "Unable to find NavigationMap page");
|
|
me._page.getDevice().selectPage(mappage);
|
|
return emesary.Transmitter.ReceiptStatus_Finished;
|
|
}
|
|
|
|
# If we're editing an element, complete the data entry.
|
|
if (me._cursorElements[me._selectedElement].isInEdit()) {
|
|
me._cursorElements[me._selectedElement].enterElement();
|
|
}
|
|
|
|
if (me._cursorElements[me._selectedElement] == me.page.IDEntry) {
|
|
# We've finished entering an ID, so load it.
|
|
var destination = me.getDestination(me.page.IDEntry.getValue());
|
|
if (destination != nil) {
|
|
|
|
# set the course and distance to the destination if required
|
|
var (course, dist) = courseAndDistance(destination);
|
|
var d = {
|
|
id: destination.id,
|
|
name: destination.name,
|
|
lat: destination.lat,
|
|
lon: destination.lon,
|
|
course : course,
|
|
range_nm : dist,
|
|
};
|
|
me.page.displayDestination(d);
|
|
}
|
|
}
|
|
|
|
# Determine where to highlight next. In most cases, we go straight to ACTIVATE.
|
|
# The exception is the VNV Alt field which goes to the VNV Distance field;
|
|
if (me._cursorElements[me._selectedElement] == me.page.VNVAltEntry) {
|
|
# VNV DIS entry is the next element
|
|
me.nextCursorElement(1);
|
|
} else {
|
|
# ACTIVATE is the last element of the group
|
|
me.setCursorElement(size(me._cursorElements) - 1);
|
|
}
|
|
|
|
return emesary.Transmitter.ReceiptStatus_Finished;
|
|
},
|
|
handleClear : func(value) {
|
|
var mappage = me._page.getMFD().getPage("NavigationMap");
|
|
assert(mappage != nil, "Unable to find NavigationMap page");
|
|
me._page.getDevice().selectPage(mappage);
|
|
return emesary.Transmitter.ReceiptStatus_Finished;
|
|
},
|
|
|
|
handleSoftKey : func(key) {
|
|
# DirectTo has no softkeys, but if the user presses one from the underlying
|
|
# page we should switch outselves off.
|
|
me.page.setVisible(0);
|
|
return emesary.Transmitter.ReceiptStatus_OK;
|
|
},
|
|
|
|
# Reset controller if required when the page is displayed or hidden
|
|
ondisplay : func() {
|
|
me.RegisterWithEmesary();
|
|
for (var i = 0; i < size(me._cursorElements); i = i+1) {
|
|
me._cursorElements[i].unhighlightElement();
|
|
}
|
|
|
|
me.setCursorElement(0);
|
|
|
|
me.page.IDEntry.setValue("KHAF");
|
|
|
|
var destination = me.getDestination(me.page.IDEntry.getValue());
|
|
if (destination != nil) {
|
|
|
|
# set the course and distance to the destination if required
|
|
var (course, dist) = courseAndDistance(destination);
|
|
var d = {
|
|
id: destination.id,
|
|
name: destination.name,
|
|
lat: destination.lat,
|
|
lon: destination.lon,
|
|
course : course,
|
|
range_nm : dist,
|
|
};
|
|
me.page.displayDestination(d);
|
|
}
|
|
|
|
|
|
},
|
|
offdisplay : func() {
|
|
me.DeRegisterWithEmesary();
|
|
},
|
|
|
|
getDestination : func(id) {
|
|
# Use Emesary to get the destination
|
|
var notification = notifications.PFDEventNotification.new(
|
|
"MFD",
|
|
1,
|
|
notifications.PFDEventNotification.NavData,
|
|
{Id: "NavDataByID", Value: id});
|
|
|
|
var response = me._transmitter.NotifyAll(notification);
|
|
var retval = notification.EventParameter.Value;
|
|
|
|
if ((! me._transmitter.IsFailed(response)) and (size(retval) > 0)) {
|
|
return retval[0];
|
|
} else {
|
|
return nil;
|
|
}
|
|
},
|
|
};
|