1
0
Fork 0

FG1000: Active Flight Plan MFD Page

- View and edit the active flightplan
This commit is contained in:
Stuart Buchanan 2018-04-06 19:52:18 +01:00
parent f8f2e2913a
commit 7f09b1f3c6
25 changed files with 2897 additions and 172 deletions

File diff suppressed because it is too large Load diff

After

Width:  |  Height:  |  Size: 79 KiB

View file

@ -15,7 +15,7 @@
version="1.1"
id="SVGRoot"
inkscape:version="0.91 r13725"
sodipodi:docname="MFD.svg">
sodipodi:docname="Surround.svg">
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
@ -23,11 +23,11 @@
borderopacity="0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.828427"
inkscape:cx="445.86013"
inkscape:cy="589.65442"
inkscape:zoom="1.9999999"
inkscape:cx="645.49836"
inkscape:cy="276.18699"
inkscape:document-units="px"
inkscape:current-layer="MFD-navbox"
inkscape:current-layer="FPLPageGroup"
showgrid="true"
inkscape:window-width="2495"
inkscape:window-height="1416"
@ -1363,7 +1363,7 @@
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:15px;line-height:125%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="774.98926"
y="685.68018"
id="ActiveFlightPlanWide"
id="ActiveFlightPlanNarrow"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5217"

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 78 KiB

View file

@ -23,11 +23,11 @@
borderopacity="0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.828427"
inkscape:cx="510.83575"
inkscape:cy="676.04552"
inkscape:zoom="1.9999999"
inkscape:cx="950.95075"
inkscape:cy="113.96381"
inkscape:document-units="px"
inkscape:current-layer="g57958"
inkscape:current-layer="FPLPageGroup"
showgrid="true"
inkscape:window-width="2495"
inkscape:window-height="1416"
@ -1347,7 +1347,7 @@
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:15px;line-height:125%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="774.98926"
y="685.68018"
id="ActiveFlightPlanWide"
id="ActiveFlightPlanNarrow"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5217"

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 77 KiB

View file

@ -0,0 +1,522 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1024px"
height="768px"
viewBox="0 0 1024 768"
version="1.1"
id="SVGRoot"
inkscape:version="0.91 r13725"
sodipodi:docname="WaypointEntry.svg">
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#ffffff"
borderopacity="0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.1481278"
inkscape:cx="776.8472"
inkscape:cy="382.52948"
inkscape:document-units="px"
inkscape:current-layer="layer3"
showgrid="true"
inkscape:window-width="2495"
inkscape:window-height="1416"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:snap-global="true"
inkscape:snap-grids="true"
inkscape:snap-bbox="true"
inkscape:snap-others="true"
inkscape:snap-to-guides="true"
inkscape:bbox-paths="false"
inkscape:snap-nodes="true"
inkscape:snap-page="true"
inkscape:bbox-nodes="true">
<inkscape:grid
type="xygrid"
id="grid4269" />
</sodipodi:namedview>
<defs
id="defs7962" />
<metadata
id="metadata7965">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="WaypointEntryGroup">
<g
id="WaypointEntryGroup"
inkscape:label="#g4310">
<rect
style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4252"
width="315"
height="325"
x="705"
y="278"
inkscape:label="#rect59059" />
<g
id="WaypointEntryMap"
inkscape:label="#g60873"
transform="translate(0,-64.700026)">
<rect
inkscape:label="#rect59059"
y="278"
x="705"
height="325"
width="315"
id="WaypointEntryMap-bg"
style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
</g>
<path
style="opacity:1;fill:#181818;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 698.99609,58.498047 0,622.303953 325.00391,0 0,-622.303953 z M 705.5,212.73335 l 314.4277,0 0,322.2793 -314.4277,0 z"
id="rect4230"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccc" />
<rect
y="102.92673"
x="704.92676"
height="94.646538"
width="315.14658"
id="rect9743"
style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<rect
y="564.0752"
x="704.77563"
height="74.724365"
width="315.22437"
id="rect9747"
style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<rect
y="93.154411"
x="720.15442"
height="19.691175"
width="139.19115"
id="rect9753"
style="opacity:1;fill:#4b4b4b;fill-opacity:1;fill-rule:nonzero;stroke:#fffcfa;stroke-width:1.30882514;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<text
sodipodi:linespacing="125%"
id="text9749"
y="108"
x="725"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:125%;font-family:'Liberation Sans';-inkscape-font-specification:'Liberation Sans';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#fffcfa;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="108"
x="725"
id="tspan9751"
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed'">IDENT, FACILITY, CITY</tspan></text>
<rect
style="opacity:1;fill:#4b4b4b;fill-opacity:1;fill-rule:nonzero;stroke:#fffcfa;stroke-width:1;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4150"
width="34.834621"
height="20.334629"
x="719.8327"
y="203.65253" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:15px;line-height:125%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#fffcfa;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="725"
y="218.81982"
id="text4152"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4154"
x="725"
y="218.81982">MAP</tspan></text>
<rect
y="554.75623"
x="719.98303"
height="20.033949"
width="74.533913"
id="rect4156"
style="opacity:1;fill:#1a3030;fill-opacity:1;fill-rule:nonzero;stroke:#fffcfa;stroke-width:1;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<text
sodipodi:linespacing="125%"
id="text4158"
y="569.77319"
x="725"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:15px;line-height:125%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#fffcfa;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="569.77319"
x="725"
sodipodi:role="line"
id="tspan4162">LOCATION</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:20px;line-height:125%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#80ffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="711.10352"
y="136.96484"
id="WaypointEntryID"
sodipodi:linespacing="125%"
inkscape:label="#text4166"><tspan
sodipodi:role="line"
id="tspan4168"
x="711.10352"
y="136.96484">KSFO</tspan></text>
<text
sodipodi:linespacing="125%"
id="WaypointEntryName"
y="161.86719"
x="711.70898"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:20px;line-height:125%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#80ffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"
inkscape:label="#text4170"><tspan
y="161.86719"
x="711.70898"
id="tspan4172"
sodipodi:role="line">SAN FRANCISCO INTERNATIONAL</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:20px;line-height:125%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#80ffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="711.01562"
y="187.80469"
id="WaypointEntryCity"
sodipodi:linespacing="125%"
inkscape:label="#text4174"><tspan
sodipodi:role="line"
id="tspan4176"
x="711.01562"
y="187.80469">CITY</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:20px;line-height:125%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#80ffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="711.10352"
y="182.80469"
id="WaypointEntryRegion"
sodipodi:linespacing="125%"
inkscape:label="#text4198"><tspan
sodipodi:role="line"
id="tspan4200"
x="711.10352"
y="182.80469">REGION</tspan></text>
<text
inkscape:label="#text4166"
sodipodi:linespacing="125%"
id="WaypointEntryID0"
y="137.16016"
x="711.10352"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:20px;line-height:125%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#80ffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="137.16016"
x="711.10352"
id="tspan4227"
sodipodi:role="line">K</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:20px;line-height:125%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#80ffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="722.25781"
y="136.96484"
id="WaypointEntryID1"
sodipodi:linespacing="125%"
inkscape:label="#text4166"><tspan
sodipodi:role="line"
id="tspan4232"
x="722.25781"
y="136.96484">S</tspan></text>
<text
inkscape:label="#text4166"
sodipodi:linespacing="125%"
id="WaypointEntryID2"
y="137.16016"
x="732.99805"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:20px;line-height:125%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#80ffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="137.16016"
x="732.99805"
id="tspan4236"
sodipodi:role="line">F</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:20px;line-height:125%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#80ffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="743.24805"
y="136.96484"
id="WaypointEntryID3"
sodipodi:linespacing="125%"
inkscape:label="#text4166"><tspan
sodipodi:role="line"
id="tspan4240"
x="743.24805"
y="136.96484">O</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:125%;font-family:'Liberation Sans';-inkscape-font-specification:'Liberation Sans';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#fffcfa;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="785.59717"
y="77.353516"
id="text3449"
sodipodi:linespacing="125%"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed'"
sodipodi:role="line"
id="tspan3451"
x="785.59717"
y="77.353516">WAYPOINT INFORMATION</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:20px;line-height:125%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="711.10352"
y="593.60425"
id="text3549"
sodipodi:linespacing="125%"
inkscape:label="#text4166"><tspan
sodipodi:role="line"
id="tspan3551"
x="711.10352"
y="593.60425">BRG</tspan></text>
<text
inkscape:label="#text4166"
sodipodi:linespacing="125%"
id="WaypointEntryLocationBRG"
y="593.60425"
x="760.69336"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:20px;line-height:125%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#80ffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="593.60425"
x="760.69336"
id="tspan3555"
sodipodi:role="line">189</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:20px;line-height:125%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#80ffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="758.75"
y="623.60425"
id="WaypointEntryLocationDIS"
sodipodi:linespacing="125%"
inkscape:label="#text4166"><tspan
sodipodi:role="line"
id="tspan3559"
x="758.75"
y="623.60425">12.3</tspan></text>
<text
inkscape:label="#text4166"
sodipodi:linespacing="125%"
id="text3565"
y="623.60425"
x="713.65234"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:20px;line-height:125%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="623.60425"
x="713.65234"
id="tspan3567"
sodipodi:role="line">DIS</tspan></text>
<rect
y="510.89764"
x="951.39722"
height="24.004704"
width="68.004707"
id="rect8420"
style="display:inline;opacity:1;fill:#4b4b4b;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.99528456;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<text
sodipodi:linespacing="0%"
inkscape:label="RangeDisplay"
transform="scale(0.95485858,1.0472755)"
id="WaypointEntryRangeDisplay"
y="506.28864"
x="1032.0643"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:11.80263901px;line-height:0%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow, Condensed';text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;display:inline;fill:#31ffff;fill-opacity:1;stroke:none"
xml:space="preserve"><tspan
style="font-size:17.21218109px;line-height:1.25;fill:#31ffff;fill-opacity:1"
y="506.28864"
x="1032.0643"
id="tspan5131-3-5-3"
sodipodi:role="line">Zoom nm</tspan></text>
<rect
style="display:inline;opacity:1;fill:#4b4b4b;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4265"
width="75.057129"
height="19.057156"
x="944.07098"
y="213.77084" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:11.80263901px;line-height:0%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow, Condensed';text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;display:inline;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none"
x="1027.9818"
y="218.78036"
id="WaypointEntryOrientationDisplay"
transform="scale(0.95485858,1.0472755)"
inkscape:label="RangeDisplay"
sodipodi:linespacing="0%"><tspan
sodipodi:role="line"
id="tspan4269"
x="1027.9818"
y="218.78036"
style="font-size:17.21218109px;line-height:1.25;fill:#ffffff;fill-opacity:1;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none">NORTH UP</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:20px;line-height:125%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#80ffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="873.37891"
y="593.60425"
id="WaypointEntryLocationLat"
sodipodi:linespacing="125%"
inkscape:label="#text4166"><tspan
sodipodi:role="line"
id="tspan4748"
x="873.37891"
y="593.60425">________</tspan></text>
<text
inkscape:label="#text4166"
sodipodi:linespacing="125%"
id="WaypointEntryLocationLon"
y="621.09448"
x="873.37891"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:20px;line-height:125%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#80ffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="621.09448"
x="873.37891"
id="tspan4752"
sodipodi:role="line">________</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4754"
y="664.77319"
x="800.20532"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:125%;font-family:'Liberation Sans';-inkscape-font-specification:'Liberation Sans';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#fffcfa;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="664.77319"
x="800.20532"
id="tspan4756"
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed'">Press &quot;ENT&quot; to accept</tspan></text>
</g>
<g
inkscape:groupmode="layer"
id="layer1"
inkscape:label="Shortcuts"
style="display:inline">
<g
transform="translate(5.3346157e-6,0)"
inkscape:label="#g4271"
id="WaypointEntryWaypointSubmenuGroup">
<rect
style="opacity:1;fill:#4b4b4b;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.77672273;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4232"
width="115.22327"
height="149.22327"
x="709.38837"
y="143.38834" />
<rect
y="147.38759"
x="713.38757"
height="141.22482"
width="107.22482"
id="rect4239"
style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.77518052;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
ry="0" />
<text
inkscape:label="#text4198"
sodipodi:linespacing="125%"
id="WaypointEntryWaypointSubmenuSelect"
y="170.66508"
x="765.59869"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:20px;line-height:125%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow, Condensed';text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#80ffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="170.66508"
x="765.59869"
id="tspan4243"
sodipodi:role="line">REGION</tspan></text>
<path
style="fill:#feffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 800.5,153.35355 0,20 10,-10 -10,-10"
id="WaypointEntryWaypointSubmenuSelectRight"
inkscape:connector-curvature="0"
inkscape:label="#path4245" />
<path
inkscape:connector-curvature="0"
id="WaypointEntryWaypointSubmenuSelectLeft"
d="m 730.70711,153.35355 0,20 -10,-10 10,-10"
style="fill:#feffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
inkscape:label="#path4247" />
<path
style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#4b4b4b;stroke-width:0.85485041px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 720,178 95,0"
id="path4249"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:20px;line-height:125%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#80ffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="718.65234"
y="201.96484"
id="WaypointEntryWaypointSubmenuScroll0"
sodipodi:linespacing="125%"
inkscape:label="#text4198"><tspan
sodipodi:role="line"
id="tspan4253"
x="718.65234"
y="201.96484">REGION</tspan></text>
<text
inkscape:label="#text4198"
sodipodi:linespacing="125%"
id="WaypointEntryWaypointSubmenuScroll1"
y="226.96484"
x="718.65234"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:20px;line-height:125%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#80ffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="226.96484"
x="718.65234"
id="tspan4257"
sodipodi:role="line">REGION</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:20px;line-height:125%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#80ffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="718.65234"
y="251.96484"
id="WaypointEntryWaypointSubmenuScroll2"
sodipodi:linespacing="125%"
inkscape:label="#text4198"><tspan
sodipodi:role="line"
id="tspan4261"
x="718.65234"
y="251.96484">REGION</tspan></text>
<text
inkscape:label="#text4198"
sodipodi:linespacing="125%"
id="WaypointEntryWaypointSubmenuScroll3"
y="276.96484"
x="718.65234"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:20px;line-height:125%;font-family:'Liberation Sans Narrow';-inkscape-font-specification:'Liberation Sans Narrow Condensed';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#80ffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
y="276.96484"
x="718.65234"
id="tspan4265"
sodipodi:role="line">REGION</tspan></text>
<rect
style="opacity:1;fill:#c0c0c0;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="WaypointEntryWaypointSubmenuScrollTrough"
width="5"
height="90"
x="810"
y="188"
inkscape:label="#rect4267" />
<rect
y="188"
x="810"
height="30"
width="5"
id="WaypointEntryWaypointSubmenuScrollThumb"
style="opacity:1;fill:#808080;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
inkscape:label="#rect4269" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 29 KiB

View file

@ -15,6 +15,7 @@
# along with FlightGear. If not, see <http://www.gnu.org/licenses/>.
#
# FMS Driver using Emesary to publish data from the inbuilt FMS properties
var GenericFMSPublisher =
{
@ -23,6 +24,7 @@ var GenericFMSPublisher =
parents : [
GenericFMSPublisher,
],
_running : 0,
};
# We have two publishers here:
@ -119,12 +121,88 @@ var GenericFMSPublisher =
start : func() {
me._triggeredPublisher.start();
me._periodicPublisher.start();
me._running = 1;
},
stop : func() {
me._triggeredPublisher.stop();
me._periodicPublisher.stop();
me._running = 0;
},
isRunning : func() {
return me._running;
},
};
# FMS Delegate which will be triggered by the underlying route manager
var FMSDataDelegate = {
new : func(fp) {
var obj = {
parents : [FMSDataDelegate],
flightplan : fp,
};
return obj;
},
currentWaypointChanged : func (fp) {
var notification = notifications.PFDEventNotification.new(
"MFD",
1,
notifications.PFDEventNotification.FMSData,
{"FMSFlightPlanSequenced" : fp.current});
emesary.GlobalTransmitter.NotifyAll(notification);
},
departureChanged : func (fp) {
var notification = notifications.PFDEventNotification.new(
"MFD",
1,
notifications.PFDEventNotification.FMSData,
{"FMSFlightPlanEdited" : 1});
emesary.GlobalTransmitter.NotifyAll(notification);
},
arrivalChanged : func (fp) {
var notification = notifications.PFDEventNotification.new(
"MFD",
1,
notifications.PFDEventNotification.FMSData,
{"FMSFlightPlanEdited" : 1});
emesary.GlobalTransmitter.NotifyAll(notification);
},
waypointsChanged : func (fp) {
var notification = notifications.PFDEventNotification.new(
"MFD",
1,
notifications.PFDEventNotification.FMSData,
{"FMSFlightPlanEdited" : 1});
emesary.GlobalTransmitter.NotifyAll(notification);
},
activated : func (fp) {
var notification = notifications.PFDEventNotification.new(
"MFD",
1,
notifications.PFDEventNotification.FMSData,
{"FMSFlightPlanEdited" : 1});
emesary.GlobalTransmitter.NotifyAll(notification);
},
cleared : func (fp) {
me.sendFMSNotification({"FMSFlightPlanEdited" : 1});
var notification = notifications.PFDEventNotification.new(
"MFD",
1,
notifications.PFDEventNotification.FMSData,
{"FMSFlightPlanEdited" : 1});
},
endOfFlightPlan: func (fp) {
var notification = notifications.PFDEventNotification.new(
"MFD",
1,
notifications.PFDEventNotification.FMSData,
{"FMSFlightPlanFinished" : 1});
emesary.GlobalTransmitter.NotifyAll(notification);
},
};
var dd = FMSDataDelegate.new(flightplan());
registerFlightPlanDelegate(FMSDataDelegate.new);

View file

@ -27,7 +27,6 @@ io.load_nasal(nasal_dir ~ 'Interfaces/GenericFMSPublisher.nas', "fg1000");
io.load_nasal(nasal_dir ~ 'Interfaces/GenericFMSUpdater.nas', "fg1000");
io.load_nasal(nasal_dir ~ 'Interfaces/GenericADCPublisher.nas', "fg1000");
var GenericInterfaceController = {
_instance : nil,
@ -54,6 +53,7 @@ var GenericInterfaceController = {
obj.gpsPublisher = fg1000.GenericFMSPublisher.new();
obj.gpsUpdater = fg1000.GenericFMSUpdater.new();
obj.adcPublisher = fg1000.GenericADCPublisher.new();
return obj;
},

View file

@ -20,6 +20,14 @@
var NavDataInterface = {
# Valid FMS Modes
FMS_MODES : {
direct : 1,
leg : 1,
obs : 1,
},
new : func ()
{
var obj = { parents : [ NavDataInterface ] };
@ -142,6 +150,47 @@ getFlightplan : func ()
return flightplan();
},
insertWaypoint : func (data)
{
assert(data["index"] != nil, "InsertWaypoint message with no index parameter");
assert(data["wp"] != nil, "InsertWaypoint message with no wp parameter");
var wp = data["wp"];
var idx = int(data["index"]);
# Simple data verification that we have the parameters we need
assert(idx != nil, "InsertWaypoint index parameter does not contain an integer index");
assert(wp.id != nil, "InsertWaypoint wp parameter does not contain an id");
assert(wp.lat != nil, "InsertWaypoint wp parameter does not contain a lat");
assert(wp.lon != nil, "InsertWaypoint wp parameter does not contain an lon");
var newwp = createWP(wp.lat, wp.lon, wp.id);
var fp = flightplan();
fp.insertWP(newwp, idx);
# Set a suitable name.
if ((fp.id == nil) or (fp.id == "default-flightplan")) {
var from = "????";
var dest = "????";
if ((fp.getWP(0) != nil) and (fp.getWP(0).wp_name != nil)) {
from = fp.getWP(0).wp_name;
}
if ((fp.getWP(fp.getPlanSize() -1) != nil) and (fp.getWP(fp.getPlanSize() -1).wp_name != nil)) {
dest = fp.getWP(fp.getPlanSize() -1).wp_name;
}
if (fp.departure != nil) from = fp.departure.id;
if (fp.destination != nil) dest = fp.destination.id;
fp.id == from ~ " / " ~ dest;
}
# Activate flightplan
if (fp.getPlanSize() == 2) fgcommand("activate-flightplan", props.Node.new({"activate": 1}));
},
# Retrieve the Airway waypoints on the current leg.
getAirwayWaypoints : func() {
var fp = flightplan();
@ -220,6 +269,15 @@ setDirectTo : func(param)
setprop("/instrumentation/gps/command", "direct");
},
setFMSMode : func(mode) {
if (NavDataInterface.FMS_MODES[mode] != nil) {
# mode is valid, so simply set it as the GPS command
setprop("/instrumentation/gps/command", mode);
} else {
die("Invalid FMS Mode " ~ mode);
}
},
# Return the current DTO location to use
getCurrentDTO : func()
{
@ -301,6 +359,15 @@ RegisterWithEmesary : func()
controller.setDefaultDTO(notification.EventParameter.Value);
return emesary.Transmitter.ReceiptStatus_Finished;
}
if (id == "SetFMSMode") {
controller.setFMSMode(notification.EventParameter.Value);
return emesary.Transmitter.ReceiptStatus_Finished;
}
if (id == "InsertWaypoint") {
controller.insertWaypoint(notification.EventParameter.Value);
return emesary.Transmitter.ReceiptStatus_Finished;
}
}
return emesary.Transmitter.ReceiptStatus_NotProcessed;
};

View file

@ -38,8 +38,8 @@ var MFDPages = [
"XMRadio",
"XMInfo",
"SystemStatus",
"ActiveFlightPlanWide",
"ActiveFlightPlanNarrow",
"ActiveFlightPlanWide",
"FlightPlanCatalog",
"StoredFlightPlan",
"Checklist1",
@ -54,6 +54,7 @@ var MFDPages = [
"NearestUserWPT",
"NearestFrequencies",
"NearestAirspaces",
"WaypointEntry",
"DirectTo",
"Surround",
];
@ -117,6 +118,11 @@ var MFDDisplay =
obj._DTO = fg1000.DirectTo.new(obj, myCanvas, obj._MFDDevice, obj._svg);
obj._DTO.getController().RegisterWithEmesary();
# Next, the WaypointEntry "Page" so that it too receives any Emesary notifications
# _before_ the actual page.
obj._WaypointEntry = fg1000.WaypointEntry.new(obj, myCanvas, obj._MFDDevice, obj._svg);
obj._WaypointEntry.getController().RegisterWithEmesary();
obj._MFDDevice.RegisterWithEmesary();
# Surround dynamic elements
@ -139,7 +145,7 @@ var MFDDisplay =
# Now load the other pages normally;
foreach (var page; MFDPages) {
if ((page != "NavigationMap") and (page != "EIS") and (page != "DirectTo")) {
if ((page != "NavigationMap") and (page != "EIS") and (page != "DirectTo") and (page != "WaypointEntry")) {
#var code = "obj.Surround.addPage(\"" ~ page ~ "\", fg1000." ~ page ~ ".new(obj, myCanvas, obj._MFDDevice, obj._svg));";
var code = "obj.addPage(\"" ~ page ~ "\", fg1000." ~ page ~ ".new(obj, myCanvas, obj._MFDDevice, obj._svg));";
var addPageFn = compile(code);

View file

@ -129,6 +129,37 @@ setTextElement : func(symbolName, value) {
sym.setValue(value);
},
setTextElementLat : func(symbolName, value) {
var degrees_part = int(value);
if (degrees_part == nil) {
me.setTextElement(symbolName, "_ __°__.__'");
} else {
var minutes_part = 100.0 * (value - degrees_part);
if (value < 0.0) {
me.setTextElement(symbolName, sprintf("S %2d°%.2f'", -degrees_part, -minutes_part));
} else {
me.setTextElement(symbolName, sprintf("N %2d°%.2f'", degrees_part, minutes_part));
}
}
},
setTextElementLon : func(symbolName, value) {
var degrees_part = int(value);
if (degrees_part == nil) {
me.setTextElement(symbolName, "____°__.__'");
} else {
var minutes_part = 100.0 * (value - degrees_part);
if (value < 0.0) {
me.setTextElement(symbolName, sprintf("W%3d°%.2f'", -degrees_part, -minutes_part));
} else {
me.setTextElement(symbolName, sprintf("E%3d°%.2f'", degrees_part, minutes_part));
}
}
},
# Function to undo any colors set by display_toggle when loading a new menu
resetMenuColors : func() {
for(var i = 0; i < 12; i +=1) {
@ -159,6 +190,6 @@ getSVG : func() {
},
getGroup : func() {
return me._group;
}
},
};

View file

@ -30,10 +30,6 @@ new : func (page)
obj._page = page;
obj._transmitter = emesary.GlobalTransmitter;
obj._registered = 0;
# DirectTo controls
obj._directTo = 0;
return obj;
},
@ -70,9 +66,19 @@ handleComFreqTransferHold : func (value) { return me.page.mfd.SurroundController
handleComVol : func (value) { return me.page.mfd.SurroundController.handleComVol(value); },
handleComVolToggle : func (value) { return me.page.mfd.SurroundController.handleComVolToggle(value); },
# DTO button brings up the DirectTo Page.
handleDTO : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; },
handleFPL : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; },
handleFPL : func (value) {
var fppage = me._page.getMFD().getPage("ActiveFlightPlanNarrow");
if (fppage != nil) {
me._page.getDevice().selectPage(fppage);
return emesary.Transmitter.ReceiptStatus_Finished;
} else {
return emesary.Transmitter.ReceiptStatus_NotProcessed;
}
},
handleClear : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; },
# Holding the Clear button goes straight to the Navigation Map page.
@ -203,7 +209,7 @@ setDefaultDTOWayPoint : func(id)
},
getDeviceID : func() {
return me.page.mfd.getDeviceID();
return me._page.mfd.getDeviceID();
},

View file

@ -17,6 +17,8 @@
# ActiveFlightPlanNarrow
var ActiveFlightPlanNarrow =
{
SHORTCUTS : [ "FPL", "NRST", "RECENT", "USER", "AIRWAY" ],
new : func (mfd, myCanvas, device, svg)
{
var obj = {
@ -24,8 +26,45 @@ var ActiveFlightPlanNarrow =
ActiveFlightPlanNarrow,
MFDPage.new(mfd, myCanvas, device, svg, "ActiveFlightPlanNarrow", "FPL - ACTIVE FLIGHT PLAN")
],
current_flightplan : nil,
};
# Scrolling list of waypoints. We have _two_ lists here as we use one
# Arrow highlight element to show the current leg, and another to allow
# the FMS knob to highlight a waypoint for insertion/deletion or to make
# active.
obj.flightplanList = PFD.GroupElement.new(
obj.pageName,
svg,
[ "Header", "Leg", "DTK", "DIS", "ALT"],
11,
"Leg",
0,
"ScrollTrough",
"ScrollThumb",
180
);
obj.currentLegIndicator = PFD.GroupElement.new(
obj.pageName,
svg,
[ "Arrow"],
11,
"Arrow",
1,
);
obj.Map = fg1000.NavMap.new(
obj,
obj.getElement("NavMap"),
#[360, 275],
#[fg1000.MAP_PARTIAL.CENTER.X, fg1000.MAP_PARTIAL.CENTER.Y],
[860,400],
#"rect(345, 233, -345, -233)",
"",
-50,
2);
obj.topMenu(device, obj, nil);
obj.setController(fg1000.ActiveFlightPlanNarrowController.new(obj, svg));
@ -42,18 +81,111 @@ var ActiveFlightPlanNarrow =
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.getElement("NavMap").setVisible(0);
me.Map.setVisible(0);
me.getController().offdisplay();
},
ondisplay : func() {
me._group.setVisible(1);
me.mfd.setPageTitle(me.title);
me.getElement("NavMap").setVisible(1);
me.Map.setVisible(1);
me.getController().ondisplay();
},
topMenu : func(device, pg, menuitem) {
pg.clearMenu();
pg.resetMenuColors();
pg.addMenuItem(0, "ENGINE", pg, pg.mfd.EIS.engineMenu);
pg.addMenuItem(2, "MAP", pg, pg.mfd.NavigationMap.mapMenu);
device.updateMenus();
},
# Update the FlightPlan display with an updated flightplan.
setFlightPlan : func(fp, current_wp) {
var elements = [];
var arrowElements = [];
if (fp == nil) {
me.flightplanList.setValues([]);
me.flightplanList.setCRSR(0);
me.flightplanList.displayGroup();
me.currentLegIndicator.setValues([]);
me.currentLegIndicator.setCRSR(0);
me.currentLegIndicator.displayGroup();
return;
}
for (var i = 0; i < fp.getPlanSize(); i = i + 1) {
var wp = fp.getWP(i);
var element = {
Header : "",
Leg : "",
DTK : "",
DIS : "",
ALT : "_____ft",
};
if (wp.wp_name != nil) {
element.Leg = substr(wp.wp_name, 0, 7);
} else {
element.Leg = "____";
}
if (i == 0) {
element.DIS = "";
element.DTK = "";
element.ALT = "_____ft";
} else if (i < current_wp) {
# Passed waypoints are blanked out on the display
element.DIS = "___nm";
element.DTK = "___°";
element.ALT = "_____ft";
} else {
if (wp.leg_distance != nil) element.DIS = sprintf("%.1fnm", wp.leg_distance);
if (wp.leg_bearing != nil) element.DTK = sprintf("%03d°", wp.leg_bearing);
if (wp.alt_cstr_type != nil) element.ALT = sprintf("%dft", wp.alt_cstr);
}
append(elements, element);
append(arrowElements, { Arrow : i});
}
me.flightplanList.setValues(elements);
me.currentLegIndicator.setValues(arrowElements);
if (current_wp == -1) {
me.flightplanList.setCRSR(0);
me.currentLegIndicator.setCRSR(0);
} else {
me.flightplanList.setCRSR(current_wp);
me.currentLegIndicator.setCRSR(current_wp);
}
me.flightplanList.displayGroup();
me.currentLegIndicator.displayGroup();
# Determine a suitable name to display, using the flightplan name if there is one,
# but falling back to the flightplan departure / destination airports, or failing
# that the IDs of the first and last waypoints.
if ((fp.id == nil) or (fp.id == "default-flightplan")) {
var from = "????";
var dest = "????";
if ((fp.getWP(0) != nil) and (fp.getWP(0).wp_name != nil)) {
from = fp.getWP(0).wp_name;
}
if ((fp.getWP(fp.getPlanSize() -1) != nil) and (fp.getWP(fp.getPlanSize() -1).wp_name != nil)) {
dest = fp.getWP(fp.getPlanSize() -1).wp_name;
}
if (fp.departure != nil) from = fp.departure.id;
if (fp.destination != nil) dest = fp.destination.id;
me.getElement("Name").setText(from ~ " / " ~ dest);
} else {
me.getElement("Name").setText(fp.id);
}
},
};

View file

@ -24,24 +24,44 @@ var ActiveFlightPlanNarrowController =
_crsrToggle : 0,
_recipient : nil,
_page : page,
_fp_current_wp : 0,
_fp_active : 0,
_current_flightplan : nil,
_fprecipient : nil,
transmitter : nil,
_waypointSubmenuVisible : 0,
};
obj._current_flightplan = obj.getNavData("Flightplan");
if (obj._current_flightplan != nil) {
obj._fp_current_wp = obj._current_flightplan.current;
obj._page.setFlightPlan(obj._current_flightplan, obj._fp_current_wp);
} else {
obj._page.setFlightPlan(nil, nil);
}
return obj;
},
# Input Handling
handleCRSR : func() {
me._crsrToggle = (! me._crsrToggle);
if (me._crsrToggle) {
me._page.flightplanList.showCRSR();
} else {
me._page.hideCRSR();
me._page.flightplanList.hideCRSR();
}
return emesary.Transmitter.ReceiptStatus_Finished;
},
handleFMSInner : func(value) {
if (me._crsrToggle == 1) {
# Scroll through whatever is the current list
# Enable the WaypointEntry window
me._page.mfd._WaypointEntry.ondisplay();
# Also directly pass in the message. This is because the WaypointEntry page
# is above this in the Emesary stack, and as it was not displayed, it won't
# have picked up the message to display either an entry box or the submenu.
me._page.mfd._WaypointEntry.getController().handleFMSInner(value);
return emesary.Transmitter.ReceiptStatus_Finished;
} else {
# Pass to the page group controller to display and scroll through the page group menu
@ -50,6 +70,7 @@ var ActiveFlightPlanNarrowController =
},
handleFMSOuter : func(value) {
if (me._crsrToggle == 1) {
me._page.flightplanList.incrLarge(value);
return emesary.Transmitter.ReceiptStatus_Finished;
} else {
# Pass to the page group controller to display and scroll through the page group menu
@ -64,12 +85,177 @@ var ActiveFlightPlanNarrowController =
}
},
handleRange : func(val)
{
# Pass any range entries to the NavMapController
me._page.Map.handleRange(val);
},
# Handle the user entry of a waypoint. We now need to insert it into the
# flightplan at the point after the selected waypoint, then update the
# flightplan. This should cause a cascade of Emesary updates, which will
# subsequently update this display (and any others).
handleWaypointEntry : func(data) {
assert(data.id != nil, "handleWaypointEntry called with invalid hash");
# Place this after the current index
var params = {
index : me._page.flightplanList.getCRSR() + 1,
wp : data
};
# Update the FMS with the new flightplan via Emesary
var notification = notifications.PFDEventNotification.new(
"MFD",
me.getDeviceID(),
notifications.PFDEventNotification.NavData,
{Id: "InsertWaypoint", Value: params});
var response = me._transmitter.NotifyAll(notification);
if (me._transmitter.IsFailed(response)) {
print("ActiveFlightPlanNarrowController.handleWaypointEntry() : Failed to set FMS Data " ~ params);
debug.dump(params);
} else {
# The flightplan has changed. For some reason this isn't triggering an
# update from the flightplan delegate, so we'll just trigger an update
# ourselves.
var notification = notifications.PFDEventNotification.new(
"MFD",
1,
notifications.PFDEventNotification.FMSData,
{"FMSFlightPlanEdited" : 1});
var response = me._transmitter.NotifyAll(notification);
if (me._transmitter.IsFailed(response)) {
print("ActiveFlightPlanNarrowController.handleWaypointEntry() : Failed to set FMS Data " ~ params);
debug.dump(params);
}
}
# Critically, only this page should handle the waypoint entry.
return emesary.Transmitter.ReceiptStatus_Finished;
},
# Handle update to the FMS information. Note that there is no guarantee
# that the entire set of FMS data will be available.
handleFMSData : func(data) {
var update_fp = 0;
var reload_fp = 0;
if (data["FMSLegID"] != nil) me._leg_id = data["FMSLegID"];
if ((data["FMSFlightPlanSequenced"] != nil) and (data["FMSFlightPlanSequenced"] != me._fp_current_wp)) {
me._fp_current_wp = data["FMSFlightPlanSequenced"];
update_fp = 1;
}
if (data["FMSFlightPlanEdited"] != nil) {
reload_fp = 1;
}
if ((data["FMSFlightPlanActive"] != nil) and (data["FMSFlightPlanActive"] != me._fp_active)) {
me._fp_active = data["FMSFlightPlanActive"];
if (me._fp_active) {
reload_fp = 1;
} else {
# No flightplan active, so we will display nothing.
me._current_flightplan = nil;
me._fp_current_wp = -1;
update_fp = 1;
}
}
if ((data["FMSFlightPlanCurrentWP"] != nil) and (data["FMSFlightPlanCurrentWP"] != me._fp_current_wp)) {
me._fp_current_wp = data["FMSFlightPlanCurrentWP"];
update_fp = 1;
}
if (reload_fp) {
# The flightplan has changed in some way, so reload it.
me._current_flightplan = me.getNavData("Flightplan");
if (me._current_flightplan != nil) {
me._fp_current_wp = me._current_flightplan.current;
update_fp = 1;
}
}
if (update_fp) {
#me._current_flightplan = me.getNavData("Flightplan");
me._page.setFlightPlan(me._current_flightplan, me._fp_current_wp);
}
return emesary.Transmitter.ReceiptStatus_OK;
},
# Reset controller if required when the page is displayed or hidden
ondisplay : func() {
me.RegisterWithEmesary();
me.FPRegisterWithEmesary();
},
offdisplay : func() {
me.DeRegisterWithEmesary();
me.FPDeRegisterWithEmesary();
},
FPRegisterWithEmesary : func(transmitter = nil){
if (transmitter == nil)
transmitter = emesary.GlobalTransmitter;
if (me._fprecipient == nil){
me._fprecipient = emesary.Recipient.new("ActiveFlightPlanNarrowController_" ~ me._page.device.designation);
var pfd_obj = me._page.device;
var controller = me;
me._fprecipient.Receive = func(notification)
{
if (notification.Device_Id == pfd_obj.device_id and
notification.NotificationType == notifications.PFDEventNotification.DefaultType and
notification.Event_Id == notifications.PFDEventNotification.FMSData and
notification.EventParameter != nil and
notification.EventParameter["Id"] == "SetWaypointEntry")
{
# Special case where THIS DEVICE has displayed the WaypointEntry page and
# we are now receiving the entered waypoint. In this case we need to
# determine where to enter it in the flightplan and update it.
return controller.handleWaypointEntry(notification.EventParameter.Value);
}
if (notification.NotificationType == notifications.PFDEventNotification.DefaultType and
notification.Event_Id == notifications.PFDEventNotification.FMSData and
notification.EventParameter != nil)
{
return controller.handleFMSData(notification.EventParameter);
}
return emesary.Transmitter.ReceiptStatus_NotProcessed;
};
}
transmitter.Register(me._fprecipient);
me.transmitter = transmitter;
},
FPDeRegisterWithEmesary : func(transmitter = nil){
# remove registration from transmitter; but keep the recipient once it is created.
if (me.transmitter != nil)
me.transmitter.DeRegister(me._fprecipient);
me.transmitter = nil;
},
getNavData : func(type, value=nil) {
# Use Emesary to get a piece from the NavData system, using the provided
# type and value;
var notification = notifications.PFDEventNotification.new(
"MFD",
me._page.mfd.getDeviceID(),
notifications.PFDEventNotification.NavData,
{Id: type, Value: value});
var response = me._transmitter.NotifyAll(notification);
if (! me._transmitter.IsFailed(response)) {
return notification.EventParameter.Value;
} else {
return nil;
}
},
};

View file

@ -117,19 +117,8 @@ var AirportInfo =
me.setTextElement("City", "CITY");
me.setTextElement("Region", "REGION");
me.setTextElement("Alt", sprintf("%ift", M2FT * apt_info.elevation));
if (apt_info.lat < 0.0) {
me.setTextElement("Lat", sprintf("S %.4f", -apt_info.lat));
} else {
me.setTextElement("Lat", sprintf("N %.4f", apt_info.lat));
}
if (apt_info.lon < 0.0) {
me.setTextElement("Lon", sprintf("W%3.4f", -apt_info.lon));
} else {
me.setTextElement("Lon", sprintf("E%3.4f", apt_info.lon));
}
me.setTextElementLat("Lat", apt_info.lat);
me.setTextElementLon("Lon", apt_info.lon);
me.setTextElement("Fuel", "AVGAS, AVTUR");
me.setTextElement("TZ", "UTC-6");

View file

@ -69,9 +69,8 @@ var DirectTo =
obj.WaypointSubmenuSelect = PFD.ScrollElement.new(obj.pageName, svg, "WaypointSubmenuSelect", DirectTo.SHORTCUTS);
obj.WaypointSubmenuScroll = PFD.GroupElement.new(obj.pageName, svg, [ "WaypointSubmenuScroll" ] , 4, "WaypointSubmenuScroll", 0, "WaypointSubmenuScrollTrough" , "WaypointSubmenuScrollThumb", 60);
# The Airport Chart
# The Airport Chart - only displayed on the MFD variant (where thre's if there's a Map SVG element present)
if (obj.elementExists("Map")) {
print("DirectoTo Map exists");
obj.DirectToChart = fg1000.NavMap.new(obj, obj.getElement("Map"), [860,440], "rect(-160px, 160px, 160px, -160px)", 0, 2, 1);
} else {
obj.DirectToChart = nil;

View file

@ -177,6 +177,8 @@ var DirectToController =
handleRange : func(val)
{
if (! me.dto_displayed) return emesary.Transmitter.ReceiptStatus_NotProcessed;
if (me.page.DirectToChart != nil) {
return me.page.DirectToChart.handleRange(val);
} else {
@ -336,7 +338,7 @@ var DirectToController =
# Some elements don't have names
var name = destination.id;
if (!defined("destination.name")) name = destination.name;
if (defined("destination.name")) name = destination.name;
var point = { lat: destination.lat, lon: destination.lon };
var (course, dist) = courseAndDistance(point);

View file

@ -17,15 +17,6 @@
# Navigation Map Controller
var NavigationMapController =
{
# TODO: Add STAMEN topo layer, which is visible on all levels as opposed to
# roads, railways, boundaries, cities which are only visible on declutter 0.
# Declutter levels.
DCLTR : [ "DCLTR", "DCLTR-1", "DCLTR-2", "DCLTR-3"],
# Airways levels.
AIRWAYS : [ "AIRWAYS", "AIRWY ON", "AIRWY LO", "AIRWY HI"],
new : func (page, svg)
{
var obj = { parents : [ NavigationMapController, MFDPageController.new(page) ] };

View file

@ -95,6 +95,7 @@ var PFDInstruments =
);
obj.setController(fg1000.PFDInstrumentsController.new(obj, svg));
obj.setWindDisplay(0);
obj.setCDISource("GPS");
obj.setBRG1("OFF");
@ -728,6 +729,8 @@ var PFDInstruments =
if (fp == nil) return;
var current_wp = fp.current;
for (var i = 0; i < fp.getPlanSize(); i = i + 1) {
var wp = fp.getWP(i);
@ -736,22 +739,30 @@ var PFDInstruments =
FlightPlanID : "",
FlightPlanType : "",
FlightPlanDTK : 0,
FlightPlanDIS : 0
FlightPlanDIS : 0,
};
if (wp.wp_name != nil) element.FlightPlanID = substr(wp.wp_name, 0, 7);
if (wp.wp_role != nil) element.FlightPlanType = substr(wp.wp_role, 0, 4);
if (wp.leg_distance != nil) element.FlightPlanDIS = sprintf("%.1fnm", wp.leg_distance);
if (wp.leg_bearing != nil) element.FlightPlanDTK = sprintf("%03d°", wp.leg_bearing);
if (i < current_wp) {
# Passed waypoints are blanked out on the display
element.FlightPlanDIS = "___nm";
element.FlightPlanDTK = "___°";
} else {
if (wp.leg_distance != nil) element.FlightPlanDIS = sprintf("%.1fnm", wp.leg_distance);
if (wp.leg_bearing != nil) element.FlightPlanDTK = sprintf("%03d°", wp.leg_bearing);
}
append(elements, element);
}
me.flightplanList.setValues(elements);
me.flightplanList.setCRSR(current_wp);
# Determine a suitable name to display, using the flightplan name if there is one,
# but falling back to the flightplan departure / destination airports, or failing
# that the IDs of the first and last waypoints.
if (fp.id == nil) {
if ((fp.id == nil) or (fp.id == "default-flightplan")) {
var from = "????";
var dest = "????";

View file

@ -131,6 +131,13 @@ var PFDInstrumentsController =
var incr_or_decr = (val > 0) ? me.page.insetMap.zoomIn() : me.page.insetMap.zoomOut();
},
handleFPL : func (value) {
# Display/hide the FPL display
me._fp_visible = (! me._fp_visible);
me.page.setFlightPlanVisible(me._fp_active and me._fp_visible);
return emesary.Transmitter.ReceiptStatus_Finished;
},
# Set the STD BARO to 29.92 in Hg
setStdBaro : func() {
var data = {};
@ -254,12 +261,17 @@ var PFDInstrumentsController =
if (data["FMSFlightPlanEdited"] != nil) {
# The flightplan has changed in some way, so reload it.
update_fp = 1;
me._current_flightplan = me.getNavData("Flightplan");
if (me._current_flightplan != nil) {
me._fp_current_wp = me._current_flightplan.current;
me.page.setFlightPlan(me._current_flightplan);
update_fp = 1;
}
}
if ((data["FMSFlightPlanActive"] != nil) and (data["FMSFlightPlanActive"] != me._fp_active)) {
me._fp_active = data["FMSFlightPlanActive"];
me.page.setFlightPlanVisible(me._fp_active);
me.page.setFlightPlanVisible(me._fp_active and me._fp_visible);
update_fp = 1;
}
@ -268,16 +280,7 @@ var PFDInstrumentsController =
update_fp = 1;
}
if (update_fp and me._fp_active) {
# For some reason the signals to indicate a FP change aren't firing, so reload the
# flightplan here
me._current_flightplan = me.getNavData("Flightplan");
if (me._current_flightplan != nil) {
me._fp_current_wp = me._current_flightplan.current;
me.page.setFlightPlan(me._current_flightplan);
update_fp = 1;
}
if (me._fp_visible and update_fp and me._fp_active) {
me.page.updateFlightPlan(me._fp_current_wp);
}

View file

@ -40,7 +40,7 @@ var PAGE_GROUPS = [
{ label: "FPLGroupLabel",
group: "FPLPageGroup",
pages: [ "ActiveFlightPlanWide", "FlightPlanCatalog", "StoredFlightPlan"],
pages: [ "ActiveFlightPlanNarrow", "FlightPlanCatalog", "StoredFlightPlan"],
},
{ label: "LstGroupLabel",

View file

@ -14,14 +14,11 @@
# You should have received a copy of the GNU General Public License
# along with FlightGear. If not, see <http://www.gnu.org/licenses/>.
#
# DirectTo page
#
# Technically this is supposed to be an overlay page, sitting on top of
# whatever page the user was on already. However, to simplify implementation,
# we will assume that the user was on the Map page, and simply display the
# NavigationMap page underneath.
# WaypointEntry page. This is an overlay, sitting on whatever page the user
# is on already. Hence it is not called in the normal way, but instead
# explicitly called by Flightplan pages to insert a waypoint.
var DirectTo =
var WaypointEntry =
{
SHORTCUTS : [ "FPL", "NRST", "RECENT", "USER", "AIRWAY" ],
@ -29,21 +26,23 @@ var DirectTo =
{
var obj = {
parents : [
DirectTo,
MFDPage.new(mfd, myCanvas, device, svg, "DirectTo", "DIRECT TO")
WaypointEntry,
MFDPage.new(mfd, myCanvas, device, svg, "WaypointEntry", "")
],
symbols : {},
};
obj.crsrIdx = 0;
# Dynamic text elements in the SVG file. In the SVG these have an "DirectTo" prefix.
# Dynamic text elements in the SVG file. In the SVG these have an "WaypointEntry" prefix.
textelements = [
"Name",
"City",
"Region",
"LocationBRG",
"LocationDIS",
"LocationLat",
"LocationLon",
];
obj.addTextElements(textelements);
@ -59,88 +58,62 @@ var DirectTo =
# .chars is the set of characters, used to scroll through using the small
# FMS knob.
obj.IDEntry = PFD.DataEntryElement.new(obj.pageName, svg, "ID", "", 4, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
obj.VNVAltEntry = PFD.DataEntryElement.new(obj.pageName, svg, "VNVAlt", "", 5, "0123456789");
obj.VNVOffsetEntry = PFD.DataEntryElement.new(obj.pageName, svg, "VNVOffset", "", 2, "0123456789");
obj.CourseEntry = PFD.DataEntryElement.new(obj.pageName, svg, "Course", "", 3, "0123456789");
obj.Activate = PFD.TextElement.new(obj.pageName, svg, "Activate", "ACTIVATE?");
# The Shortcut window. This allows the user to scroll through a set of lists
# of waypoints.
obj.WaypointSubmenuGroup = obj._SVGGroup.getElementById("DirectToWaypointSubmenuGroup");
assert(obj.WaypointSubmenuGroup != nil, "Unable to find DirectToWaypointSubmenuGroup");
obj.WaypointSubmenuGroup = obj._SVGGroup.getElementById("WaypointEntryWaypointSubmenuGroup");
assert(obj.WaypointSubmenuGroup != nil, "Unable to find WaypointEntryWaypointSubmenuGroup");
obj.WaypointSubmenuGroup.setVisible(0);
obj.WaypointSubmenuSelect = PFD.ScrollElement.new(obj.pageName, svg, "WaypointSubmenuSelect", DirectTo.SHORTCUTS);
obj.WaypointSubmenuSelect = PFD.ScrollElement.new(obj.pageName, svg, "WaypointSubmenuSelect", WaypointEntry.SHORTCUTS);
obj.WaypointSubmenuScroll = PFD.GroupElement.new(obj.pageName, svg, [ "WaypointSubmenuScroll" ] , 4, "WaypointSubmenuScroll", 0, "WaypointSubmenuScrollTrough" , "WaypointSubmenuScrollThumb", 60);
# The Airport Chart
# The Airport Chart - only displayed on the MFD variant (where thre's if there's a Map SVG element present)
if (obj.elementExists("Map")) {
obj.DirectToChart = fg1000.NavMap.new(obj, obj.getElement("Map"), [860,440], "rect(-160px, 160px, 160px, -160px)", 0, 2, 1);
obj.WaypointEntryChart = fg1000.NavMap.new(obj, obj.getElement("Map"), [860,440], "rect(-160px, 160px, 160px, -160px)", 0, 2, 1);
} else {
obj.WaypointEntryChart = nil;
}
obj.setController(fg1000.DirectToController.new(obj, svg));
obj.setController(fg1000.WaypointEntryController.new(obj, svg));
return obj;
},
displayDestination : func(destination) {
#me.IDEntry.clearElement();
if (destination != nil) {
# Display a given location
if (me.DirectToChart) {
me.DirectToChart.setVisible(1);
me.DirectToChart.getController().setPosition(destination.lat,destination.lon);
if (me.WaypointEntryChart != nil) {
me.WaypointEntryChart.setVisible(1);
me.WaypointEntryChart.getController().setPosition(destination.lat,destination.lon);
}
me.setTextElement("Name", string.uc(destination.name));
me.setTextElement("City", "CITY");
me.setTextElement("Region", "REGION");
me.setTextElement("LocationBRG", "" ~ sprintf("%03d°", destination.course));
me.setTextElement("LocationDIS", sprintf("%d", destination.range_nm) ~ "nm");
me.IDEntry.setValue(destination.id);
me.VNVAltEntry.setValue("00000");
me.VNVOffsetEntry.setValue("00");
me.CourseEntry.setValue("" ~ sprintf("%03d°", destination.course));
} else {
if (me.DirectToChart) me.DirectToChart.setVisible(0);
me.setTextElement("Name", "");
me.setTextElement("City", "");
me.setTextElement("Region", "");
me.setTextElement("LocationBRG", "_");
me.setTextElement("LocationDIS", "_");
me.IDEntry.setValue("____");
me.VNVAltEntry.setValue("00000");
me.VNVOffsetEntry.setValue("00");
me.CourseEntry.setValue(0);
me.setTextElement("LocationBRG", "" ~ sprintf("%03d°", destination.course));
me.setTextElement("LocationDIS", sprintf("%d", destination.range_nm) ~ "nm");
me.setTextElementLat("LocationLat", destination.lat);
me.setTextElementLon("LocationLon", destination.lon);
me.IDEntry.setValue(destination.id);
} else {
if (me.WaypointEntryChart != nil) me.WaypointEntryChart.setVisible(0);
me.setTextElement("Name", "___");
me.setTextElement("City", "____________");
me.setTextElement("Region", "____________");
me.setTextElement("LocationBRG", "___°");
me.setTextElement("LocationDIS", "__._nm");
me.setTextElement("LocationLat", "_ __°__.__'");
me.setTextElement("LocationLon", "____°__.__'");
me.IDEntry.setValue("####");
}
},
offdisplay : func() {
me._group.setVisible(0);
me.getElement("Group").setVisible(0);
me.getController().offdisplay();
me.mfd.NavigationMap.offdisplay(0);
},
ondisplay : func() {
me._group.setVisible(1);
# Display a false title, as underneath we're showing the navigation map.
me.mfd.setPageTitle("MAP - NAVIGATION MAP");
me.getElement("Map").setVisible(1);
me.getElement("Map-bg").setVisible(1);
if (me.DirectToChart) me.DirectToChart.setVisible(1);
me.getElement("Group").setVisible(1);
me.getController().ondisplay();
# The DirectTo pages displays over the NavigationMap. This is a hack
# as the page should just magically sit ontop of whatever page the user was
# on. However, we also need to disable the NavMap's own controller so there's
# no confusion.
me.mfd.NavigationMap.ondisplay(0);
},
# When the Direct To display is enabled, nothing is displayed on the softkeys.
topMenu : func(device, pg, menuitem) {
pg.clearMenu();
pg.resetMenuColors();
device.updateMenus();
},
};

View file

@ -0,0 +1,314 @@
# Copyright 2018 Stuart Buchanan
# This file is part of FlightGear.
#
# Foobar is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# FlightGear is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with FlightGear. If not, see <http://www.gnu.org/licenses/>.
#
# WaypointEntry Controller
var WaypointEntryController =
{
new : func (page, svg)
{
var obj = { parents : [ WaypointEntryController, MFDPageController.new(page)] };
obj.id = "";
obj.page = page;
obj._wpentry_displayed = 0;
obj._destination = nil;
obj._cursorElements = [
obj.page.IDEntry,
];
obj._activateIndex = size(obj._cursorElements) - 1;
obj._selectedElement = 0;
# Whether the WaypointSubmenuGroup is enabled
obj._waypointSubmenuVisible = 0;
return obj;
},
setCursorElement : func(value) {
for (var i = 0; i < size(me._cursorElements); i = i+1) {
me._cursorElements[i].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);
},
handleCRSR : func() {
if (! me._wpentry_displayed) return emesary.Transmitter.ReceiptStatus_NotProcessed;
# No effect, but shouldn't be passed to underlying page?
return emesary.Transmitter.ReceiptStatus_Finished;
},
updateWaypointSubmenu : func() {
var type = me.page.WaypointSubmenuSelect.getValue();
var items = [];
if (type == "FPL") {
# Get the contents of the flightplan and display the list of waypoints.
var fp = me.getNavData("Flightplan");
for (var i = 0; i < fp.getPlanSize(); i = i + 1) {
var wp = fp.getWP(i);
if (wp.wp_name != nil) append(items, wp.wp_name);
}
}
if (type == "NRST") {
# Get the nearest airports
var apts = me.getNavData("NearestAirports");
for (var i = 0; i < size(apts); i = i + 1) {
var apt = apts[i];
if (apt.id != nil) append(items, apt.id);
}
}
if (type == "RECENT") {
# Get the set of recent waypoints
items = me.getNavData("RecentWaypoints");
}
if (type == "USER") {
items = me.getNavData("UserWaypoints");
}
if (type == "AIRWAY") {
var airways = me.getNavData("AirwayWaypoints");
if (airways != nil) {
foreach (var wp; airways) {
if (wp.wp_name != nil) append(items, wp.wp_name);
}
}
}
if ((items != nil) and (size(items) > 0)) {
# At this point we have a vector of waypoint names. We need to convert
# this into a vector of { "WaypointSubmenuScroll" : [name] } hashes for consumption by the
# list of waypoints
var groupitems = [];
foreach (var item; items) {
append(groupitems, { "WaypointSubmenuScroll" : item } );
}
# Now display them!
me.page.WaypointSubmenuScroll.setValues(groupitems);
} else {
# Nothing to display
me.page.WaypointSubmenuScroll.setValues([]);
}
},
getNavData : func(type, value=nil) {
# Use Emesary to get a piece from the NavData system, using the provided
# type and value;
var notification = notifications.PFDEventNotification.new(
"MFD",
me.getDeviceID(),
notifications.PFDEventNotification.NavData,
{Id: type, Value: value});
var response = me._transmitter.NotifyAll(notification);
if (! me._transmitter.IsFailed(response)) {
return notification.EventParameter.Value;
} else {
return nil;
}
},
setFMSData : func(type, value=nil) {
# Use Emesary to set a piece of data in the NavData system, using the provided
# type and value;
var notification = notifications.PFDEventNotification.new(
"MFD",
me.getDeviceID(),
notifications.PFDEventNotification.FMSData,
{Id: type, Value: value});
var response = me._transmitter.NotifyAll(notification);
if (me._transmitter.IsFailed(response)) {
print("WaypointEntryController.setNavData() : Failed to set Nav Data " ~ value);
debug.dump(value);
}
},
handleRange : func(val)
{
if (! me._wpentry_displayed) return emesary.Transmitter.ReceiptStatus_NotProcessed;
if (me.page.WaypointEntryChart != nil) {
return me.page.WaypointEntryChart.handleRange(val);
} else {
return emesary.Transmitter.ReceiptStatus_NotProcessed;
}
},
handleFMSInner : func(value) {
if (! me._wpentry_displayed) return emesary.Transmitter.ReceiptStatus_NotProcessed;
if (me._waypointSubmenuVisible) {
# We're in the Waypoint Submenu, in which case the inner FMS knob
# selects between the different waypoint types.
me.page.WaypointSubmenuSelect.highlightElement();
me.page.WaypointSubmenuSelect.incrSmall(value);
# Now update the Scroll group with the new type of waypoints
me.updateWaypointSubmenu();
} else if ((me._selectedElement == 0) and (! me.page.IDEntry.isInEdit()) and (value == -1)) {
# The WaypointSubmenuGroup group is displayed if the small FMS knob is rotated
# anti-clockwise as an initial rotation where the ID Entry is not being editted.
me._cursorElements[0].unhighlightElement();
me.page.WaypointSubmenuGroup.setVisible(1);
me.page.WaypointSubmenuSelect.highlightElement();
me._waypointSubmenuVisible = 1;
me.updateWaypointSubmenu();
} else {
# We've already got something selected, and we're not in the
# WaypointSubmenuGroup, so increment it.
me._cursorElements[me._selectedElement].incrSmall(value);
}
return emesary.Transmitter.ReceiptStatus_Finished;
},
handleFMSOuter : func(value) {
if (! me._wpentry_displayed) return emesary.Transmitter.ReceiptStatus_NotProcessed;
if (me._waypointSubmenuVisible) {
# We're in the Waypoint Submenu, in which case the outer FMS knob
# selects between the different waypoints in the Waypoint Submenu.
me.page.WaypointSubmenuSelect.unhighlightElement();
me.page.WaypointSubmenuScroll.showCRSR();
me.page.WaypointSubmenuScroll.incrLarge(value);
} else if (me._cursorElements[me._selectedElement].isInEdit()) {
# If we're editing an element, then get on with it!
me._cursorElements[me._selectedElement].incrLarge(value);
} else {
me.nextCursorElement(value);
}
return emesary.Transmitter.ReceiptStatus_Finished;
},
handleEnter : func(value) {
if (! me._wpentry_displayed) return emesary.Transmitter.ReceiptStatus_NotProcessed;
if (me._waypointSubmenuVisible) {
# If we're in the Waypoint Submenu, then take whatever is highlighted
# in the scroll list, load it and hide the Waypoint submenu
var id = me.page.WaypointSubmenuScroll.getValue();
if (id != nil) me.loadDestination(id);
me.page.WaypointSubmenuGroup.setVisible(0);
me._waypointSubmenuVisible = 0;
} else if (me.page.IDEntry.isInEdit()) {
# If we're editing an element, complete the data entry, the load it.
me.page.IDEntry.enterElement();
me.loadDestination(me.page.IDEntry.getValue());
} else {
# Pass the entered waypoint to the surrounding page TODO
me.setFMSData("SetWaypointEntry", me._destination);
me._wpentry_displayed = 0;
me.page.offdisplay();
return emesary.Transmitter.ReceiptStatus_Finished;
}
return emesary.Transmitter.ReceiptStatus_Finished;
},
handleClear : func(value) {
if (! me._wpentry_displayed) return emesary.Transmitter.ReceiptStatus_NotProcessed;
if (me._waypointSubmenuVisible) {
# If we're in the Waypoint Submenu, then this clears it.
me.page.WaypointSubmenuGroup.setVisible(0);
me._waypointSubmenuVisible = 0;
} else if (me._cursorElements[me._selectedElement].isInEdit()) {
me._cursorElements[me._selectedElement].clearElement();
} else {
# Cancel the entire Waypoint Entry page.
me._wpentry_displayed = 0;
me.page.offdisplay();
}
return emesary.Transmitter.ReceiptStatus_Finished;
},
# Reset controller if required when the page is displayed or hidden
# Note that we explicitly do NOT RegisterWithEmesary/DeRegisterWithEmesary!
# This page should RegisterWithEmesary at start of day instead.
ondisplay : func() {
# On initial display we simply display a blank destination
me._wpentry_displayed = 1;
me.loadDestination(nil);
},
offdisplay : func() {
me._wpentry_displayed = 0;
},
loadDestination : func(id) {
if ((id == nil) or (id == "")) {
me._destination = nil;
} else {
# Use Emesary to get the destination
var notification = notifications.PFDEventNotification.new(
"MFD",
me.getDeviceID(),
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)) {
var destination = retval[0];
# set the course and distance to the destination if required
# Some elements don't have names
var name = destination.id;
if (defined("destination.name")) name = destination.name;
var point = { lat: destination.lat, lon: destination.lon };
var (course, dist) = courseAndDistance(point);
me._destination = {
id: destination.id,
name: name,
lat: destination.lat,
lon: destination.lon,
course : course,
range_nm : dist,
};
}
}
me.page.displayDestination(me._destination);
},
};

View file

@ -0,0 +1,44 @@
# Copyright 2018 Stuart Buchanan
# This file is part of FlightGear.
#
# Foobar is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# FlightGear is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with FlightGear. If not, see <http://www.gnu.org/licenses/>.
#
# WaypointEntry Options
var WaypointEntryOptions =
{
new : func() {
var obj = { parents : [WaypointEntryOptions] };
obj.Options= {};
obj.loadOptions();
return obj;
},
getOption : func(type) {
return me.Options[type];
},
setOption : func(type, name, value) {
me.Options[type][name] = value;
},
loadOptions : func() {
me.clearOptions();
me.Options.APS = {};
},
clearOptions : func() {
me.Options = {};
},
};

View file

@ -0,0 +1,82 @@
# Copyright 2018 Stuart Buchanan
# This file is part of FlightGear.
#
# Foobar is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# FlightGear is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with FlightGear. If not, see <http://www.gnu.org/licenses/>.
#
# WaypointEntry Styles
var WaypointEntryStyles =
{
new : func() {
var obj = { parents : [ WaypointEntryStyles ]};
obj.Styles = {};
obj.loadStyles();
return obj;
},
getStyle : func(type) {
return me.Styles[type];
},
setStyle : func(type, name, value) {
me.Styles[type][name] = value;
},
loadStyles : func() {
me. clearStyles();
me.Styles.DME = {};
me.Styles.DME.debug = 1; # HACK for benchmarking/debugging purposes
me.Styles.DME.animation_test = 0; # for prototyping animated symbols
me.Styles.DME.scale_factor = 0.4; # 40% (applied to whole group)
me.Styles.DME.line_width = 3.0;
me.Styles.DME.color_tuned = [0,1,0]; #rgb
me.Styles.DME.color_default = [1,1,0]; #rgb
me.Styles.APT = {};
me.Styles.APT.scale_factor = 0.4; # 40% (applied to whole group)
me.Styles.APT.line_width = 3.0;
me.Styles.APT.color_default = [0,0.6,0.85]; #rgb
me.Styles.APT.label_font_color = me.Styles.APT.color_default;
me.Styles.APT.label_font_size=28;
me.Styles.TFC = {};
me.Styles.TFC.scale_factor = 0.4; # 40% (applied to whole group)
me.Styles.WPT = {};
me.Styles.WPT.scale_factor = 0.5; # 50% (applied to whole group)
me.Styles.RTE = {};
me.Styles.RTE.line_width = 2;
me.Styles.FLT = {};
me.Styles.FLT.line_width = 3;
me.Styles.FIX = {};
me.Styles.FIX.color = [1,0,0];
me.Styles.FIX.scale_factor = 0.4; # 40%
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.APS = {};
me.Styles.APS.scale_factor = 0.25;
},
clearStyles : func() {
me.Styles = {};
},
};

View file

@ -42,8 +42,8 @@ var NavMap = {
obj.Styles = fg1000.NavigationMapStyles.new();
obj.Options = fg1000.NavigationMapOptions.new();
obj.Map = element.createChild("map");
obj.Map.setScreenRange(689/2.0);
obj._map = element.createChild("map");
obj._map.setScreenRange(689/2.0);
obj._rangeDisplay = obj._svg.getElementById(obj._pageName ~ "RangeDisplay");
if (obj._rangeDisplay == nil) die("Unable to find element " ~ obj._pageName ~ "RangeDisplay");
@ -53,7 +53,7 @@ var NavMap = {
# Initialize the controllers:
if (static) {
obj.Map.setController("Static position", "main");
obj._map.setController("Static position", "main");
} else {
var ctrl_ns = canvas.Map.Controller.get("Aircraft position");
var source = ctrl_ns.SOURCES["current-pos"];
@ -74,12 +74,12 @@ var NavMap = {
source.aircraft_heading = n.getBoolValue();
}, 1);
# Make it move with our aircraft:
obj.Map.setController("Aircraft position", "current-pos"); # from aircraftpos.controller
obj._map.setController("Aircraft position", "current-pos"); # from aircraftpos.controller
}
if (clip != "") {
obj.Map.set("clip-frame", canvas.Element.LOCAL);
obj.Map.set("clip", clip);
obj._map.set("clip-frame", canvas.Element.LOCAL);
obj._map.set("clip", clip);
}
if (zindex != 0) {
@ -94,7 +94,7 @@ var NavMap = {
if ((static == 0) or (layer.static == 1)) {
# Not all layers are displayed for all map types. Specifically,
# some layers are not displayed on static maps - e.g. DirectTo
obj.Map.addLayer(
obj._map.addLayer(
factory: layer.factory,
type_arg: layer_name,
priority: layer.priority,
@ -106,29 +106,24 @@ var NavMap = {
obj.setZoom(obj.current_zoom);
obj.setOrientation(0);
obj.Map.setVisible(0);
obj._map.setVisible(0);
return obj;
},
setController : func(type, controller ) {
me.Map.setController(type, controller);
me._map.setController(type, controller);
},
getController : func() {
return me.Map.getController();
return me._map.getController();
},
toggleLayerVisible : func(name) {
(var l = me.Map.getLayer(name)).setVisible(l.getVisible());
(var l = me._map.getLayer(name)).setVisible(l.getVisible());
},
setLayerVisible : func(name,n=1) {
me.Map.getLayer(name).setVisible(n);
},
setRange : func(range, label) {
me.Map.setRange(range);
me._rangeDisplay.setText(label);
me._map.getLayer(name).setVisible(n);
},
setOrientation : func(orientation) {
@ -137,7 +132,7 @@ var NavMap = {
},
setScreenRange : func(range) {
me.Map.setScreenRange(range);
me._map.setScreenRange(range);
},
zoomIn : func() {
@ -151,10 +146,8 @@ var NavMap = {
setZoom : func(zoom) {
if ((zoom < 0) or (zoom > (size(fg1000.RANGES) - 1))) return;
me.current_zoom = zoom;
# Ranges above represent vertical ranges, but the display is a rectangle, so
# we need to use the diagonal range of the 1024 x 689, which is 617px.
# 617px is 1.8 x 689/2, so we need to increase the range values by x1.8
me.setRange(fg1000.RANGES[zoom].range, fg1000.RANGES[zoom].label);
me._rangeDisplay.setText(fg1000.RANGES[zoom].label);
me._map.setRange(fg1000.RANGES[zoom].range);
me.updateVisibility();
},
@ -163,7 +156,7 @@ var NavMap = {
foreach (var layer_name; me._page.mfd.ConfigStore.getLayerNames()) {
var layer = me._page.mfd.ConfigStore.getLayer(layer_name);
if (me.Map.getLayer(layer_name) == nil) continue;
if (me._map.getLayer(layer_name) == nil) continue;
# Layers are only displayed if:
# 1) the user has enabled them.
@ -171,15 +164,15 @@ var NavMap = {
# (i.e. as the range gets larger, we remove layers). Note that for
# inset maps, the range that items are removed is lower.
# 3) They haven't been removed due to the declutter level.
var effective_zoom = math.clamp(me.current_zoom + me.vis_shift, 0, size(fg1000.RANGES));
var effective_zoom = math.clamp(me.current_zoom + me.vis_shift, 0, size(fg1000.RANGES) -1);
var effective_range = fg1000.RANGES[effective_zoom].range;
if (layer.enabled and
(effective_range <= layer.range) and
(me.declutter <= layer.declutter) )
{
me.Map.getLayer(layer_name).setVisible(1);
me._map.getLayer(layer_name).setVisible(1);
} else {
me.Map.getLayer(layer_name).setVisible(0);
me._map.getLayer(layer_name).setVisible(0);
}
}
},
@ -220,7 +213,7 @@ var NavMap = {
# Set the DTO line target
setDTOLineTarget : func(lat, lon) {
me.Map.getLayer("DTO").controller.setTarget(lat,lon);
me._map.getLayer("DTO").controller.setTarget(lat,lon);
},
enableDTO : func(enable) {
me._page.mfd.ConfigStore.setLayerEnabled("DTO", enable);
@ -235,16 +228,16 @@ var NavMap = {
},
getMap : func() {
return me.Map;
return me._map;
},
show : func() {
me.Map.show();
me._map.show();
},
hide : func() {
me.Map.hide();
me._map.hide();
},
setVisible : func(visible) {
me.Map.setVisible(visible);
me._map.setVisible(visible);
}
};

View file

@ -2,7 +2,7 @@
var GroupElement =
{
new : func (pageName, svg, elementNames, size, highlightElement, arrow=0, scrollTroughElement=nil, scrollThumbElement=nil, scrollHeight=0, style=nil)
new : func (pageName, svg, elementNames, displaysize, highlightElement, arrow=0, scrollTroughElement=nil, scrollThumbElement=nil, scrollHeight=0, style=nil)
{
var obj = {
parents : [ GroupElement ],
@ -18,7 +18,7 @@ new : func (pageName, svg, elementNames, size, highlightElement, arrow=0, scroll
# The size of the group. For each of the ._elementNames hash values there
# must be an SVG Element [pageName][elementName]{0...pageSize}
_size : size,
_size : displaysize,
# ElementName to be highlighted. Must be an hash value from ._elementNames
_highlightElement : highlightElement,
@ -66,7 +66,7 @@ new : func (pageName, svg, elementNames, size, highlightElement, arrow=0, scroll
if (style == nil) obj._style = PFD.DefaultStyle;
for (var i = 0; i < size; i = i + 1) {
for (var i = 0; i < displaysize; i = i + 1) {
if (obj._arrow == 1) {
append(obj._elements, PFD.HighlightElement.new(pageName, svg, highlightElement ~ i, i, obj._style));
} else {
@ -87,12 +87,12 @@ setValues : func (values_array) {
if (size(me._values) > me._size) {
# Number of elements exceeds our ability to display them, so enable
# the scroll bar.
me._scrollThumbElement.setVisible(1);
me._scrollTroughElement.setVisible(1);
if (me._scrollThumbElement != nil) me._scrollThumbElement.setVisible(1);
if (me._scrollTroughElement != nil) me._scrollTroughElement.setVisible(1);
} else {
# There is no scrolling to do, so hide the scrollbar.
me._scrollThumbElement.setVisible(0);
me._scrollTroughElement.setVisible(0);
if (me._scrollThumbElement != nil) me._scrollThumbElement.setVisible(0);
if (me._scrollTroughElement != nil) me._scrollTroughElement.setVisible(0);
}
me.displayGroup();
@ -203,6 +203,9 @@ setCRSR : func(index) {
me._crsrIndex = math.min(index, size(me._values) -1);
me._crsrIndex = math.max(0, me._crsrIndex);
},
getCRSR : func() {
return me._crsrIndex;
},
getCursorElementName : func() {
if (me._crsrEnabled == -1) return nil;
return me._elements[me._crsrIndex - me._pageIndex].name;
@ -232,7 +235,6 @@ incrSmall : func(value) {
var incr_or_decr = (value > 0) ? 1 : -1;
if (me._elements[me._crsrIndex - me._pageIndex].isInEdit()) {
# We're editing, so pass to the element.
#print("Moving cursor to next character entry");
me._elements[me._crsrIndex - me._pageIndex].incrSmall(val);
} else {
# Move to next selection element
@ -247,7 +249,6 @@ incrLarge : func(val) {
var incr_or_decr = (val > 0) ? 1 : -1;
if (me._elements[me._crsrIndex - me._pageIndex].isInEdit()) {
# We're editing, so pass to the element.
#print("Moving cursor to next character entry");
me._elements[me._crsrIndex - me._pageIndex].incrLarge(val);
} else {
# Move to next selection element