Showing 3 changed files with 105 additions and 0 deletions
+89
Nasal/MFD.pages.nas
... ...
@@ -97,6 +97,95 @@ displayClass.MFD = {
97 97
             me.device.knobs.FmsInner = me.device.knobs.NavigateMenu;
98 98
             me.device.knobs.FmsOuter = me.device.knobs.NavigateMenu;
99 99
         },
100
+        'FLIGHT PLAN CATALOG': func {
101
+            var obj_infos = [];
102
+            var departure = getprop('/sim/airport/closest-airport-id');
103
+            append(obj_infos, {text: departure ~ ' STORED FLIGHT PLANS', type: 'title'});
104
+            append(obj_infos, {type: 'separator'});
105
+            var idx = 0;
106
+            foreach (var file; directory(data.flightplans)) {
107
+                var stat = io.stat(data.flightplans ~ '/' ~ file);
108
+                if (stat[11] == 'reg' or stat[11] == 'lnk') {
109
+                    var xml = call(func (path) io.readxml(path), [ data.flightplans ~ '/' ~ file ], me, {}, var errors = []);
110
+                    if (size(errors))
111
+                        continue;
112
+                    if (xml.getNode('/PropertyList/flight-rules')        != nil
113
+                    and xml.getNode('/PropertyList/flight-type')         != nil
114
+                    and xml.getNode('/PropertyList/departure/airport')   != nil
115
+                    and xml.getNode('/PropertyList/destination/airport') != nil
116
+                    and xml.getNode('/PropertyList/departure').getValue('airport') == departure) {
117
+                        append(obj_infos, {
118
+                            text: sprintf('RWY %s to %s%s',
119
+                                xml.getNode('/PropertyList/departure').getValue('runway'),
120
+                                xml.getNode('/PropertyList/destination').getValue('airport'),
121
+                                xml.getNode('/PropertyList/destination').getValue('runway') != nil ?
122
+                                '-' ~ xml.getNode('/PropertyList/destination').getValue('runway') : ''),
123
+                            type: (idx ? 'editable' : 'selected') ~ '|end-of-line',
124
+                            scrollgroup: idx,
125
+                            _file: data.flightplans ~ '/' ~ file
126
+                        });
127
+                        var first_wp = last_wp = 0;
128
+                        forindex (var wp; xml.getNode('/PropertyList/route').getChildren('wp')) {
129
+                            var ident = xml.getNode('/PropertyList/route').getChild('wp', wp).getValue('ident');
130
+                            if (string.match(ident, 'DEP-[0-9]*')
131
+                            or string.match(ident, sprintf('%s', xml.getNode('/PropertyList/departure').getValue('runway')))
132
+                            or string.match(ident, sprintf('%s-[0-9]*', xml.getNode('/PropertyList/departure').getValue('runway')))) {
133
+                                continue;
134
+                            }
135
+                            if (!first_wp) {
136
+                                first_wp = wp;
137
+                                continue;
138
+                            }
139
+                            if (string.match(ident, 'APP-[0-9]*')
140
+                            or string.match(ident, sprintf('%s', xml.getNode('/PropertyList/destination').getValue('runway')))
141
+                            or string.match(ident, sprintf('%s', xml.getNode('/PropertyList/destination').getValue('airport')))
142
+                            or string.match(ident, sprintf('%s-[0-9]*', xml.getNode('/PropertyList/destination').getValue('runway')))) {
143
+                                last_wp = wp - 1;
144
+                                break;
145
+                            }
146
+                        }
147
+                        if (last_wp - first_wp > 2)
148
+                            append(obj_infos, {
149
+                                text: sprintf(' %s via %s and %s',
150
+                                    utf8.chstr(9658),
151
+                                    xml.getNode('/PropertyList/route').getChild('wp', first_wp + int((last_wp - first_wp)/3)).getValue('ident'),
152
+                                    xml.getNode('/PropertyList/route').getChild('wp', last_wp  - int((last_wp - first_wp)/3)).getValue('ident')),
153
+                                type: 'normal|end-of-line',
154
+                                scrollgroup: idx
155
+                            });
156
+                        else
157
+                            append(obj_infos, {
158
+                                text: sprintf(' %s direct', utf8.chstr(9658)),
159
+                                type: 'normal|end-of-line',
160
+                                scrollgroup: idx
161
+                            });
162
+                        idx += 1;
163
+                    }
164
+                }
165
+            }
166
+            if (!idx)
167
+                append(obj_infos, { text: 'no flightplan found', type: 'normal|end-of-line'});
168
+
169
+            var windowId = 'FLIGTH PLAN CATALOG';
170
+            me.device.windows.draw( windowId, obj_infos, {lines: 6, columns: 1, rows: 2} );
171
+            me.device.knobs.FmsInner = me.device.knobs.NavigateMenu;
172
+            me.device.knobs.FmsOuter = me.device.knobs.NavigateMenu;
173
+            me.device.buttons.CLR = func {
174
+                me.device.windows.del(windowId);
175
+                me.device.buttons.ENT = func;
176
+                me.device.buttons.CLR = func;
177
+                me.device.knobs.FmsInner = func;
178
+                me.device.knobs.FmsOuter = me.device.knobs.MFD_select_page_group;
179
+            }
180
+            me.device.buttons.ENT = func (a = 0) {
181
+                a or return;
182
+                var (id, selected) = split('-', me.device.windows.selected);
183
+                var file = me.device.windows.state[id].objects[selected]._file;
184
+                me.device.buttons.CLR();
185
+                data.flightplan = flightplan(file);
186
+                data.flightplan.activate();
187
+            }
188
+        },
100 189
     },
101 190
     NRST : {
102 191
         'NEAREST AIRPORTS': func {
+9
README.md
... ...
@@ -93,6 +93,7 @@ Please report bug at <zkv1000@seb.lautre.net>.
93 93
   * use of [maketimer()](http://wiki.flightgear.org/Nasal_library#maketimer.28.29) instead of [settimer()](http://wiki.flightgear.org/Nasal_library#settimer.28.29) when possible
94 94
 * ![][80%]
95 95
   * Setting pages (MFD): pages/sub-pages selection via FMS knob ![][done], pages content implementation ![][ongoing]
96
+  * Flight plans catalog (display on map doesn't work each time...)
96 97
 * ![][70%]
97 98
 * ![][60%]
98 99
   * NOT TESTED: add the posssibility to only use Nasal part of the instrument. This in case of a cockpit which already includes needed objects and animations for screens, knobs and buttons in its config files
... ...
@@ -234,6 +235,14 @@ You can specify the stall AoA in order to display it in the dedicated display.
234 235
 * If `<stall-aoa>` is not specified or equals to `0` (zero) the AOA display won't be accessible.
235 236
 * The `<approach-aoa>` is optionnal, if present a blue marker is visible on AOA display (not in real GarminP1000)
236 237
 
238
+### Flight plans catalog
239
+You can specify a directory where to find the flightplans you save. Defaults to `$FG_HOME/Export`
240
+
241
+        <flightplans type="string">/absolute/path/to/your/flightplans/location</flightplans>
242
+
243
+Only the flightplans set for a departure from your position will be shown, no matter of the name of the file (even extension), each will be parsed to find the ones corresponding to your departure location.
244
+The list will show only 6 flightplans, but it's scrollable so you can handle much more.
245
+
237 246
 ## 3D models
238 247
 In the definition of your flightdeck (here are the values for the installation in the Lancair 235 in which I develop the device)
239 248
 put it everywhere you want to. Note that the path `Aircraft/Instruments-3d/zkv1000` is dependant on the path where the zkv1000 is installed, this can be somewhere like `Aircraft/My-Nice-Aircraft/arbitrary/dirs/zkv1000-or-not`as mentionned earlier in this section.
+7
zkv1000.nas
... ...
@@ -37,6 +37,7 @@ var data = { # set of data common to all devices
37 37
     lat : 0,
38 38
     lon : 0,
39 39
     aoa : 0,
40
+    fpSize : 0,
40 41
     tcas: [],
41 42
     settings: {
42 43
         units: {
... ...
@@ -86,6 +87,10 @@ var init_props = func {
86 87
     zkv.getNode('lightmap',1).setIntValue(0);
87 88
     if (zkv.getNode('size-factor').getValue() == nil)
88 89
         zkv.getNode('size-factor',1).setDoubleValue(1.0);
90
+    if (zkv.getValue('flightplans') != nil and io.stat(zkv.getValue('flightplans')) == "dir")
91
+        data.flightplans = zkv.getValue('flightplans');
92
+    else
93
+        data.flightplans = getprop('/sim/fg-home') ~ '/Export';
89 94
 
90 95
     radios = zkv.getNode('radios', 1);
91 96
     radios.getNode('nav1-selected',1).setIntValue(0);
... ...
@@ -151,6 +156,8 @@ var init_props = func {
151 156
     afcs.getNode('pit-active-mode-blink',1).setBoolValue(0);
152 157
     afcs.getNode('route',1);
153 158
 
159
+    data.flightplans = getprop('/sim/fg-home') ~ '/Export';
160
+
154 161
     misc = zkv.getNode('misc',1);
155 162
     misc.getNode('alt-setting-inhg',1).setDoubleValue(getprop('/instrumentation/altimeter/setting-inhg'));
156 163