]> git.mxchange.org Git - flightgear.git/blob - src/Instrumentation/KLN89/kln89_page_fpl.cxx
Support for multiple data dirs.
[flightgear.git] / src / Instrumentation / KLN89 / kln89_page_fpl.cxx
1 // kln89_page_*.[ch]xx - this file is one of the "pages" that
2 //                       are used in the KLN89 GPS unit simulation. 
3 //
4 // Written by David Luff, started 2005.
5 //
6 // Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 //
22 // $Id$
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #include "kln89_page_fpl.hxx"
29
30 #include <algorithm>
31 #include <iostream>
32
33 using namespace std;
34
35 KLN89FplPage::KLN89FplPage(KLN89* parent)
36 : KLN89Page(parent) {
37     _nSubPages = 26;
38     _subPage = 0;
39     _name = "FPL";
40     _fpMode = 0;
41     _actFpMode = 0;
42     _wLinePos = 0;
43     _bEntWp = false;
44     _bEntExp = false;
45     _entWp = NULL;
46     _fplPos = 0;
47     _resetFplPos0 = true;
48     _delFP = false;
49     _delWp = false;
50     _delAppr = false;
51     _changeAppr = false;
52     _fp0SelWpId = "";
53 }
54
55 KLN89FplPage::~KLN89FplPage() {
56 }
57
58 void KLN89FplPage::Update(double dt) {
59     Calc();
60     
61     // NOTE - we need to draw the active leg arrow outside of this block to avoid the _delFP check.
62     // TODO - we really ought to merge the page 0 and other pages drawing code with a couple of lines of extra logic.
63     if(_subPage == 0 && !_delFP) {  // Note that in the _delFP case, the active flightplan gets a header, and hence the same geometry as the other fps, so we draw it there.
64         // active FlightPlan
65         // NOTE THAT FOR THE ACTIVE FLIGHT PLAN, TOP POSITION IS STILL 4 in the underline position scheme, to make 
66         // copy and paste easier!!!!
67
68         // ---------------------------------- Copy the active FlightPlan and insert approach header and fence if required ---------------
69         // For synatical convienience
70         //vector<GPSWaypoint*> waylist = _kln89->_flightPlans[_subPage]->waypoints;
71         // Copy every waypoint for now.
72         // This is inefficient, but allows us to insert dummy waypoints to represent the header and fence 
73         // in our *local copy* of the flightplan, if an approach is loaded.  There must be a better way to do this!!!!
74         vector<GPSWaypoint> waylist;
75         for(unsigned int i=0; i<_kln89->_flightPlans[_subPage]->waypoints.size(); ++i) {
76             waylist.push_back(*_kln89->_flightPlans[_subPage]->waypoints[i]);
77         }
78         _hdrPos = -1;
79         _fencePos = -1;
80         if(_kln89->_approachLoaded) {
81             GPSWaypoint wp;
82             wp.id = "HHHH";
83             wp.type = GPS_WP_VIRT;
84             wp.appType = GPS_HDR;
85             for(unsigned int i=0; i<waylist.size(); ++i) {
86                 // Insert the hdr immediately before the IAF
87                 if(waylist[i].appType == GPS_IAF) {
88                     waylist.insert(waylist.begin()+i, wp);
89                     // Need to insert empty string into the params to keep them in sync
90                     // Guard against empty params list.
91                     // This shouldn't happen, but currently it can until ETE and UTC params are implemeted
92                     // (and better the ugly params list ripped out and replaced with something more maintainable!).
93                     if(!_params.empty()) {
94                         _params.insert(_params.begin()+i-1, "");
95                     }
96                     _hdrPos = i;
97                     break;
98                 }
99             }
100             wp.id = "FFFF";
101             wp.type = GPS_WP_VIRT;
102             wp.appType = GPS_FENCE;
103             for(unsigned int i=0; i<waylist.size(); ++i) {
104                 // Insert the fence between the MAF and the MAP
105                 if(waylist[i].appType == GPS_MAHP) {
106                     waylist.insert(waylist.begin()+i, wp);
107                     // Need to insert empty string into the params to keep them in sync
108                     // Guard against empty params list. See comments a few lines above.
109                     if(!_params.empty()) {
110                         _params.insert(_params.begin()+i-1, "");
111                     }
112                     _fencePos = i;
113                     break;
114                 }
115             }
116         }
117         /*
118         // Now make up a vector of waypoint numbers, since they aren't aligned with list position anymore
119         int num = 0;
120         vector<int> numlist;
121         numlist.clear();
122         for(unsigned int i=0; i<waylist.size(); ++i) {
123             if(waylist[i].appType != GPS_HDR && waylist[i].appType != GPS_FENCE) {
124                 numlist.push_back(num);
125                 num++;
126             } else {
127                 numlist.push_back(-1);
128             }
129         }
130         */
131         int hfcount = 0;
132         for(unsigned int i=0; i<waylist.size(); ++i) {
133             //cout << i + 1 - hfcount << ":  ID= " << waylist[i].id;
134             if(waylist[i].appType == GPS_HDR) {
135                 hfcount++;
136                 //cout << " HDR!";
137             }
138             if(waylist[i].appType == GPS_FENCE) {
139                 hfcount++;
140                 //cout << " FENCE!";
141             }
142             //cout << '\n';
143         }
144         //----------------------------------------- end active FP copy ------------------------------------------------
145         
146         // Recalculate which waypoint is displayed at the top of the list if required (generally if this page has lost focus).
147         int idx = _kln89->GetActiveWaypointIndex();
148         if(_resetFplPos0) {
149             if(waylist.size() <= 1) {
150                 _fplPos = 0;
151             } else if(waylist.size() <= 4) {
152                 _fplPos = 1;
153             } else {
154                 // Make the active waypoint the second WP displayed
155                 _fplPos = idx;
156                 if(_fplPos != 0) {
157                     _fplPos--;
158                 }
159             }
160             //cout << "HeaderPos = " << _hdrPos << ", fencePos = " << _fencePos << ", _fplPos = " << _fplPos << ", active waypoint index = " << _parent->GetActiveWaypointIndex() << '\n';
161             if(_hdrPos >= 0 && idx >= _hdrPos) {
162                 _fplPos++;
163                 if(_fencePos >= 0 && (idx + 1) >= _fencePos) {
164                     _fplPos++;
165                 }
166             }
167             _resetFplPos0 = false;
168         }
169         
170         // Increment the active waypoint position if required due hdr and fence here not above so it gets called every frame
171         if(_hdrPos >= 0 && idx >= _hdrPos) {
172             idx++;
173             if(_fencePos >= 0 && idx >= _fencePos) {
174                 idx++;
175             }
176         }
177         
178         // Draw the leg arrow etc
179         int diff = idx - (int)_fplPos;
180         int drawPos = -1;
181         if(idx < 0) {
182             // No active waypoint
183         } else if(diff < 0) {
184             // Off screen to the top
185         } else if(diff > 2) {
186             // TODO !
187         } else {
188             drawPos = diff;
189         }
190         // Only the head is blinked during waypoint alerting
191         if(!(_kln89->_waypointAlert && _kln89->_blink)) {
192             _kln89->DrawSpecialChar(4, 2, 0, 3-drawPos);
193         }
194         // If the active waypoint is immediately after an approach header then we need to do an extra-long tail leg
195         if(_hdrPos >= 0 && idx == _hdrPos + 1) {
196             if(drawPos > 0 && !_kln89->_dto) _kln89->DrawLongLegTail(3-drawPos);
197         } else {
198             if(drawPos > 0 && !_kln89->_dto) _kln89->DrawLegTail(3-drawPos);
199         }
200         
201         //cout << "Top pos is " << _fplPos0 << ' ';
202         
203         if(_kln89->_mode == KLN89_MODE_CRSR) {
204             if(_uLinePos == 3) {
205                 _kln89->Underline(2, 13, 3, 3);
206             } else if(_uLinePos >= 4) {
207                 if(_bEntWp) {
208                     if(_wLinePos == 0) {
209                         _kln89->Underline(2, 5, 3 - (_uLinePos - 4), 4);
210                     } else if(_wLinePos == 4) {
211                         _kln89->Underline(2, 4, 3 - (_uLinePos - 4), 4);
212                     } else {
213                         _kln89->Underline(2, 4, 3 - (_uLinePos - 4), _wLinePos);
214                         _kln89->Underline(2, 5 + _wLinePos, 3 - (_uLinePos - 4), 4 - _wLinePos);
215                     }
216                     if(!_kln89->_blink) {
217                         //_kln89->DrawText(_entWp->id, 2, 4, 2 - (_uLinePos - 4), false, _wLinePos);
218                         _kln89->DrawEnt();
219                     }
220                 } else {
221                     _kln89->Underline(2, 4, 3 - (_uLinePos - 4), 5);
222                 }
223             }
224         }
225         // ----------------------------------
226             
227         // Sanity check the top position - remember that we can have an extra blank one at the bottom even if CRSR is off if crsr is switched on then off
228         if((int)_fplPos > ((int)waylist.size()) - 3) _fplPos = (((int)waylist.size()) - 3 < 0 ? 0 : waylist.size() - 3);
229         unsigned int last_pos;
230         if(waylist.empty()) {
231             last_pos = 0;
232         } else {
233             last_pos = ((int)_fplPos == ((int)waylist.size()) - 3 ? waylist.size() : waylist.size() - 1);
234         }
235         //cout << "Initialising last_pos, last_pos = " << last_pos << '\n';
236         if(waylist.size() < 4) last_pos = waylist.size();
237         
238         // Don't draw the cyclic field header if the top waypoint is the approach header
239         // Not sure if this also applies to the fence - don't think so but TODO - check!
240         if(!waylist.empty() && _fplPos < waylist.size()) {
241             if(waylist[_fplPos].appType != GPS_HDR) {
242                 _kln89->DrawChar('>', 2, 12, 3);
243                 if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 3 && _kln89->_blink)) {
244                     DrawFpMode(3);
245                 }
246             }
247         }
248         
249         //
250         // NOTE: this is the drawing routine for the ACTIVE flightplan, due to the number
251         // of differences there is a seperate routine for the stored flightplans.
252         //
253         // There are 4 rows to display flightplan data on the KLN89.  Draw each row.
254         for(unsigned int i=0; i<4; ++i) {
255             // Sanity check - we should no longer tickle this.
256             if((_fplPos+i) > waylist.size()) {
257                 break;
258             }
259
260             // Draw the number and (optional) colon for each row.
261             bool drawNum = true;
262             int n = (i < 3 ? _fplPos + i + 1 : last_pos + 1);
263             if(_kln89->_approachLoaded) {
264                 if(n > _hdrPos) --n;
265                 if(n > _fencePos) --n;
266             }
267             string s = GPSitoa(n);
268             if(_fplPos+i < waylist.size()) {
269                 // Don't draw the waypoint number for the header or fence
270                 if((waylist[_fplPos+i].appType == GPS_HDR || waylist[_fplPos+i].appType == GPS_FENCE) 
271                     && i != 3) {    // By definition, the header and fence lines can't be displayed on the last line hence the unconditional !i==3 is safe.
272                     drawNum = false;
273                 } else {
274                     // Don't draw the colon for waypoints that are part of the published approach
275                     if(waylist[_fplPos+i].appType == GPS_APP_NONE) {
276                         s += ':';
277                     }
278                 }
279             } else {
280                 // We must be drawing the next entry field at the end of the list - this has a colon
281                 s += ':';
282             }
283             if(drawNum) {
284                 if(!(_delWp && _uLinePos == i+4)) _kln89->DrawText(s, 2, 4 - (s[s.size()-1] == ':' ? s.size() : s.size()+1), 3 - i);
285             }
286             // Done drawing numbers and colons.
287                 
288             bool drawID = true;
289             if(_delWp && _uLinePos == i+4) {
290                 if(!_kln89->_blink) {
291                     _kln89->DrawText("Del", 2, 0, 3-i);
292                     _kln89->DrawChar('?', 2, 10, 3-i);
293                     _kln89->Underline(2, 0, 3-i, 11);
294                     _kln89->DrawEnt();
295                 }
296             } else if(_kln89->_mode == KLN89_MODE_CRSR && _bEntWp && _uLinePos == i+4) {
297                 if(!_kln89->_blink) {
298                     if(_wLinePos >= _entWpStr.size()) {
299                         _kln89->DrawText(_entWpStr, 2, 4, 3-i);
300                         _kln89->DrawChar(' ', 2, 4+_wLinePos, 3-i, false, true);
301                     } else {
302                         _kln89->DrawText(_entWpStr.substr(0, _wLinePos), 2, 4, 3-i);
303                         _kln89->DrawChar(_entWpStr[_wLinePos], 2, 4+_wLinePos, 3-i, false, true);
304                         _kln89->DrawText(_entWpStr.substr(_wLinePos+1, _entWpStr.size()-_wLinePos-1), 2, 5+_wLinePos, 3-i);
305                     }
306                 }
307                 // Draw the param - this is "----" during waypoint entry (not for the first row though or we draw through the label!)
308                 if(i != 0) {
309                     _kln89->DrawText("----", 2, 12, 3-i);
310                 }
311                 
312                 drawID = false;
313             }
314             if(drawID) {
315                 if(i == 3 || _fplPos + i == waylist.size()) {
316                     //cout << "_uLinePos = " << _uLinePos << ", i = " << i << ", waylist.size() = " << waylist.size() << endl;
317                     if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == (i + 4) && _kln89->_blink)) {
318                         // Draw the underline symbol at the end of the flightplan
319                         _kln89->DrawText(last_pos < waylist.size() ? waylist[last_pos].GetAprId() : "_____", 2, 4, 3-i);
320                     }
321                     //cout << "last_pos = " << last_pos << endl;
322                     if(last_pos > 0 && last_pos < waylist.size() && i > 0) {
323                         // Draw the param
324                         if(_actFpMode == 0) {   // DIS
325                             if(_kln89->_mode == KLN89_MODE_CRSR && _bEntWp && _uLinePos < i+4) {
326                                 // This means that we are beyond the waypoint being entered.  In DIS mode
327                                 // this means that we dash out the field.
328                                 _kln89->DrawText("----", 2, 12, 3-i);
329                             } else {
330                                 string s = _params[last_pos - 1];
331                                 _kln89->DrawText(s, 2, 16-s.size(), 3-i);
332                             }
333                         } else if(_actFpMode == 3) {    // DTK
334                             string s = _params[last_pos - 1];
335                             _kln89->DrawText(s, 2, 15-s.size(), 3-i);
336                             _kln89->DrawSpecialChar(0, 2, 15, 3-i);
337                         }
338                     }
339                     break;
340                 } else {
341                     if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == (i + 4) && _kln89->_blink)) {
342                         if(waylist[_fplPos+i].appType == GPS_HDR) {
343                             if(_delAppr) {
344                                 _kln89->DrawText("DELETE APPR?", 2, 1, 3-i);
345                             } else if(_changeAppr) {
346                                 _kln89->DrawText("CHANGE APPR?", 2, 1, 3-i);
347                             } else {
348                                 _kln89->DrawText(_kln89->_approachAbbrev, 2, 1, 3-i);
349                                 _kln89->DrawText(_kln89->_approachRwyStr, 2, 7, 3-i);
350                                 _kln89->DrawText(_kln89->_approachID, 2, 12, 3-i);
351                             }
352                         } else if(waylist[_fplPos+i].appType == GPS_FENCE) {
353                             _kln89->DrawText("*NO WPT SEQ", 2, 0, 3-i);
354                         } else {
355                             _kln89->DrawText(waylist[_fplPos+i].GetAprId(), 2, 4, 3-i);
356                         }
357                     }
358                 }
359                 if(i > 0) {
360                     // Draw the param
361                     //cout << "i > 0 param draw...\n";
362                     if(_actFpMode == 0) {   // DIS
363                         if(_kln89->_mode == KLN89_MODE_CRSR && _bEntWp && _uLinePos < i+4) {
364                             // This means that we are beyond the waypoint being entered.  In DIS mode
365                             // this means that we dash out the field.
366                             _kln89->DrawText("----", 2, 12, 3-i);
367                         } else {
368                             string s = _params[_fplPos + i - 1];
369                             _kln89->DrawText(s, 2, 16-s.size(), 3-i);
370                         }
371                     } else if(_actFpMode == 3) {    // DTK
372                         // TODO - figure out properly what to do in DTK mode when beyond a waypoint being entered.
373                         // I *think* it is OK to do the same as here, but maybe not for the waypoint immediately
374                         // beyond the one being entered - need to check.
375                         string s = _params[_fplPos + i - 1];
376                         _kln89->DrawText(s, 2, 15-s.size(), 3-i);
377                         _kln89->DrawSpecialChar(0, 2, 15, 3-i);
378                     }
379                 }
380             }
381         }
382     } else {  // Not active flightplan
383         //cout << "Top pos is " << _fplPos << ' ';
384         // For synatical convienience
385         //int nWp = (_subPage == 0 && !_delFP ? 4 : 3); // number of waypoints to display
386         vector<GPSWaypoint*> waylist = _kln89->_flightPlans[_subPage]->waypoints;
387         if(waylist.empty()) {
388             if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 1 && _kln89->_blink)) {
389                 _kln89->DrawText(_delFP ? "Delete FPL?" : "Copy FPL 0?", 2, 0, 3);
390             }
391         } else {
392             if(!(_kln89->_mode == KLN89_MODE_CRSR && (_uLinePos == 1 || _uLinePos == 2) && _kln89->_blink)) {
393                 _kln89->DrawText(_delFP ? "Delete FPL?" : "Use?", 2, 0, 3);
394             }
395             if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 2 && _kln89->_blink)) {
396                 if(!_delFP) _kln89->DrawText("Inverted?", 2, 5, 3);
397             }
398         }
399         
400         // ----------------------------------
401         if(_kln89->_mode == KLN89_MODE_CRSR) {
402             if(_uLinePos == 1) {
403                 if(!_kln89->_blink) {
404                     _kln89->Underline(2, 0, 3, (waylist.empty() || _delFP ? 11 : 4));   // This underline is blinked
405                     _kln89->DrawEnt();
406                 }
407             } else if(_uLinePos == 2) {
408                 // assert(!waylist.empty());
409                 if(!_kln89->_blink) {
410                     _kln89->Underline(2, 0, 3, 14); // This underline is blinked
411                     _kln89->DrawEnt();
412                 }
413             } else if(_uLinePos == 3) {
414                 _kln89->Underline(2, 13, 2, 3);
415             } else if(_uLinePos >= 4) {
416                 if(_bEntWp) {
417                     if(_wLinePos == 0) {
418                         _kln89->Underline(2, 5, 2 - (_uLinePos - 4), 4);
419                     } else if(_wLinePos == 4) {
420                         _kln89->Underline(2, 4, 2 - (_uLinePos - 4), 4);
421                     } else {
422                         _kln89->Underline(2, 4, 2 - (_uLinePos - 4), _wLinePos);
423                         _kln89->Underline(2, 5 + _wLinePos, 2 - (_uLinePos - 4), 4 - _wLinePos);
424                     }
425                     if(!_kln89->_blink) {
426                         //_kln89->DrawText(_entWp->id, 2, 4, 2 - (_uLinePos - 4), false, _wLinePos);
427                         _kln89->DrawEnt();
428                     }
429                 } else {
430                     if(!_delWp) _kln89->Underline(2, 4, 2 - (_uLinePos - 4), 5);
431                 }
432             }
433         }
434         // ----------------------------------
435             
436         _kln89->DrawChar('>', 2, 12, 2);
437         if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 3 && _kln89->_blink)) DrawFpMode(2);
438         // Sanity check the top position - remember that we can have an extra blank one at the bottom even if CRSR is off if crsr is switched on then off
439         if((int)_fplPos > ((int)waylist.size()) - 2) _fplPos = (((int)waylist.size()) - 2 < 0 ? 0 : waylist.size() - 2);
440         unsigned int last_pos;
441         if(waylist.empty()) {
442             last_pos = 0;
443         } else {
444             last_pos = ((int)_fplPos == ((int)waylist.size()) - 2 ? waylist.size() : waylist.size() - 1);
445         }
446         if(waylist.size() < 3) last_pos = waylist.size();
447         for(unsigned int i=0; i<3; ++i) {
448             string s = GPSitoa(i < 2 ? _fplPos + i + 1 : last_pos + 1);
449             s += ':';
450             if(!(_delWp && _uLinePos == i+4)) _kln89->DrawText(s, 2, 4 - s.size(), 2 - i);
451             bool drawID = true;
452             if(_delWp && _uLinePos == i+4) {
453                 if(!_kln89->_blink) {
454                     _kln89->DrawText("Del", 2, 0, 2-i);
455                     _kln89->DrawChar('?', 2, 10, 2-i);
456                     _kln89->Underline(2, 0, 2-i, 11);
457                     _kln89->DrawEnt();
458                 }
459             } else if(_kln89->_mode == KLN89_MODE_CRSR && _bEntWp && _uLinePos == i+4) {
460                 // This means that we are drawing a waypoint currently being entered
461                 if(!_kln89->_blink) {
462                     if(_wLinePos >= _entWpStr.size()) {
463                         _kln89->DrawText(_entWpStr, 2, 4, 2-i);
464                         _kln89->DrawChar(' ', 2, 4+_wLinePos, 2-i, false, true);
465                     } else {
466                         _kln89->DrawText(_entWpStr.substr(0, _wLinePos), 2, 4, 2-i);
467                         _kln89->DrawChar(_entWpStr[_wLinePos], 2, 4+_wLinePos, 2-i, false, true);
468                         _kln89->DrawText(_entWpStr.substr(_wLinePos+1, _entWpStr.size()-_wLinePos-1), 2, 5+_wLinePos, 2-i);
469                     }
470                 }
471                 // Draw the param - this is "----" during waypoint entry (not for the first row though or we draw through the label!)
472                 if(i != 0) {
473                     _kln89->DrawText("----", 2, 12, 2-i);
474                 }
475                 
476                 drawID = false;
477             }
478             if(drawID) {
479                 if(i == 2 || _fplPos + i == waylist.size()) {
480                     if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == (i + 4) && _kln89->_blink)) {
481                         _kln89->DrawText(last_pos < waylist.size() ? waylist[last_pos]->id : "_____", 2, 4, 2-i);
482                     }
483                     if(last_pos > 0 && last_pos < waylist.size() && i > 0) {
484                         // Draw the param
485                         // TODO - we should also handle DTK mode params here.
486                         if(_fpMode == 0) {  // DIS
487                             if(_kln89->_mode == KLN89_MODE_CRSR && _bEntWp && _uLinePos < i+4) {
488                                 // This means that we are beyond the waypoint being entered.  In DIS mode
489                                 // this means that we dash out the field.
490                                 _kln89->DrawText("----", 2, 12, 2-i);
491                             } else {
492                                 string s = _params[last_pos - 1];
493                                 _kln89->DrawText(s, 2, 16-s.size(), 2-i);
494                             }
495                         }
496                     }
497                     break;
498                 } else {
499                     if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == (i + 4) && _kln89->_blink)) {
500                         _kln89->DrawText(waylist[_fplPos+i]->id, 2, 4, 2-i);
501                     }
502                     if(i > 0) {
503                         // Draw the param
504                         // TODO - we should also handle DTK mode params here.
505                         if(_fpMode == 0) {  // DIS
506                             if(_kln89->_mode == KLN89_MODE_CRSR && _bEntWp && _uLinePos < i+4) {
507                                 // This means that we are beyond the waypoint being entered.  In DIS mode
508                                 // this means that we dash out the field.
509                                 _kln89->DrawText("----", 2, 12, 2-i);
510                             } else {
511                                 string s = _params[_fplPos + i - 1];
512                                 _kln89->DrawText(s, 2, 16-s.size(), 2-i);
513                             }
514                         }
515                     }
516                 }
517             }
518         }
519     }
520     
521     KLN89Page::Update(dt);
522 }
523
524 void KLN89FplPage::DrawFpMode(int ypos) {
525     string s = "Dis";
526     if(0 == _subPage) {
527         if(_actFpMode == 1) {
528             s = "ETE";
529         } else if(_actFpMode == 2) {
530             s = "UTC";  // TODO - alter depending on chosen timezone
531         } else if(_actFpMode == 3) {
532             s = (_kln89->_obsMode ? "OBS" : "Dtk");
533         }
534     } else {
535         if(_fpMode == 1) {
536             s = "Dtk";
537         }
538     }
539     _kln89->DrawText(s, 2, 13, ypos);
540 }
541
542 // Calculate the displayable parameters for the currently displayed flightplan.
543 // These are Distance, ETE, ETA (UTC) and DTK for the active flight plan, and Distance and DTK for the stored flightplans.
544 // These are then converted into strings and pushed onto a string list (_params) which matches the flightplan,
545 // which is a really really really ugly and potentially bug-prone and hard to maintain way of doing this.
546 // TODO: When the unit is fully working rip out _params and replace with a better solution.
547 void KLN89FplPage::Calc() {
548     _params.clear();
549     GPSFlightPlan* fp = _kln89->_flightPlans[_subPage];
550     vector<GPSWaypoint*> wv = fp->waypoints;
551     // Some parameters are calculated differently for the active and the stored flightplans, so
552     // do the two cases seperately.
553     if(0 == _subPage) {
554         // Active FP - parameters are only displayed for the active waypoint onwards for the active plan,
555         // and distance is cumulative from the user position.
556         if(0 == _actFpMode) {
557             // Dis
558             double cum_tot = 0.0;
559             if(wv.size() > 0) {
560                 cum_tot += _kln89->GetGreatCircleDistance(_kln89->_gpsLat, _kln89->_gpsLon, wv[0]->lat, wv[0]->lon);
561             }
562             for(unsigned int i=1; i<wv.size(); ++i) {
563                 cum_tot += _kln89->GetGreatCircleDistance(wv[i-1]->lat, wv[i-1]->lon, wv[i]->lat, wv[i]->lon);  // TODO - add units switch!
564                 int n = (int)(cum_tot + 0.5);
565                 _params.push_back(GPSitoa(n));
566             }
567         } else if(1 == _actFpMode) {
568             // TODO
569         } else if(2 == _actFpMode) {
570             // TODO
571         } else {
572             // Dtk
573             for(unsigned int i=1; i<wv.size(); ++i) {
574                 double dtk = _kln89->GetMagHeadingFromTo(wv[i-1]->lat, wv[i-1]->lon, wv[i]->lat, wv[i]->lon);
575                 int n = (int)(dtk + 0.5);
576                 _params.push_back(GPSitoa(n));
577             }
578             
579         }
580     } else {
581         // other FPs
582         if(0 == _fpMode) {
583             double cum_tot = 0.0;
584             for(unsigned int i=1; i<wv.size(); ++i) {
585                 cum_tot += _kln89->GetGreatCircleDistance(wv[i-1]->lat, wv[i-1]->lon, wv[i]->lat, wv[i]->lon);  // TODO - add units switch!
586                 int n = (int)(cum_tot + 0.5);
587                 _params.push_back(GPSitoa(n));
588             }
589         } else {
590             // Dtk
591             for(unsigned int i=1; i<wv.size(); ++i) {
592                 double dtk = _kln89->GetMagHeadingFromTo(wv[i-1]->lat, wv[i-1]->lon, wv[i]->lat, wv[i]->lon);
593                 int n = (int)(dtk + 0.5);
594                 _params.push_back(GPSitoa(n));
595             }
596         }
597     }
598 }
599
600 void KLN89FplPage::CrsrPressed() {
601     if(_delFP || _delAppr) {
602         _delFP = _delAppr = false;
603         _kln89->_mode = KLN89_MODE_DISP;
604         return;
605     }
606
607     _wLinePos = 0;
608     if(_kln89->_mode == KLN89_MODE_DISP) {
609         _fp0SelWpId.clear();
610         if(_bEntWp) {
611             for(unsigned int i = 0; i < _kln89->_flightPlans[_subPage]->waypoints.size(); ++i) {
612                 if(_kln89->_flightPlans[_subPage]->waypoints[i] == _entWp) {
613                     _kln89->_flightPlans[_subPage]->waypoints.erase(_kln89->_flightPlans[_subPage]->waypoints.begin() + i);
614                 }
615             }
616             delete _entWp;
617             _entWp = NULL;
618             _bEntWp = false;
619             _entWpStr.clear();
620         }
621     } else {
622         if(_kln89->_obsMode) {
623             _uLinePos = 0;
624         } else {
625             if(_kln89->_flightPlans[_subPage]->IsEmpty()) {
626                 _uLinePos = 4;
627             } else {
628                 _uLinePos = (_subPage == 0 ? 3 : 1);
629             }
630         }
631     }
632 }
633
634 void KLN89FplPage::ClrPressed() {
635     if(_delFP || _delAppr) {
636         _delFP = _delAppr = false;
637         _kln89->_mode = KLN89_MODE_DISP;
638     } else {
639         if(KLN89_MODE_CRSR == _kln89->_mode) {
640             // TODO - see if we need to delete a waypoint
641             if(_uLinePos >= 4) {
642                 if(_delWp) {
643                     // If we are already displaying a clear waypoint dialog in response to the CLR button,
644                     // then a further press of the CLR button cancels the dialog.
645                     _kln89->_mode = KLN89_MODE_DISP;
646                     _delWp = false;
647                 } else if(_bEntWp) {
648                     // If we are currently entering a waypoint, then CLR deletes it unconditionally
649                     // without a confirmation dialog and cancels waypoint entry.
650                     int pos = _uLinePos - 4 + _fplPos;
651                     // Sanity check - the calculated wp position should never be off the end of the waypoint list.
652                     if(pos > static_cast<int>(_kln89->_flightPlans[_subPage]->waypoints.size()) - 1) {
653                         SG_LOG(SG_GENERAL, SG_ALERT, "ERROR - _uLinePos too big in KLN89FplPage::ClrPressed!\n");
654                         return;
655                     }
656                     _kln89->_flightPlans[_subPage]->waypoints.erase(_kln89->_flightPlans[_subPage]->waypoints.begin() + pos);
657                     _bEntWp = false;
658                     _entWp = NULL;
659                     _entWpStr.clear();
660                     _wLinePos = 0;
661                     // We can also get here from the waypoint review page, so clear _bEntExp as well
662                     _bEntExp = false;
663                     // Do we need to re-calc _fplPos here?                    
664                 } else {
665                     // First check that we're not trying to delete an approach waypoint.  Note that we can delete the approach by deleting the header though.
666                     // Check for approach waypoints or header/fences in flightplan 0
667                     int n = _fplPos + _uLinePos - 4;
668                     bool hdrPos = false;
669                     bool fencePos = false;
670                     //cout << "_fplPos = " << _fplPos << ", _uLinePos = " << _uLinePos << ", n = " << n << ", _hdrPos = " << _hdrPos << ", _fencePos = " << _fencePos << '\n';
671                     if(n == _hdrPos) {
672                         //cout << "HEADER POS\n";
673                         hdrPos = true;
674                     }
675                     if(n == _fencePos) {
676                         //cout << "FENCE POS\n";
677                         fencePos = true;
678                     }
679                     if(_hdrPos >= 0 && n > _hdrPos) --n;
680                     if(_fencePos >= 0 && n >= _fencePos) --n;   // This one needs to be >= since n is already decremented by 1 in the line above!
681                     //cout << "New n = " << n << '\n';
682                     if(hdrPos) {
683                         //cout << "HDRP\n";
684                         _delAppr = true;
685                     } else if(fencePos) {
686                         //cout << "FENP\n";
687                         // no-op
688                     } else if(n >= static_cast<int>(_kln89->_flightPlans[_subPage]->waypoints.size())) {
689                         // no-op - off the end of the list on the entry field
690                     } else if(_kln89->_flightPlans[_subPage]->waypoints[n]->appType == GPS_APP_NONE) {
691                         //cout << "DELFP\n";
692                         _kln89->_mode = KLN89_MODE_CRSR;
693                         _delWp = true;
694                     } else {
695                         ShowScratchpadMessage("Invald", " Del  ");
696                     }
697                 }
698             } else if(_uLinePos == 3) {
699                 if(_subPage == 0) {
700                     _actFpMode++;
701                     if(_actFpMode > 3) _actFpMode = 0;
702                 } else {
703                     _fpMode++;
704                     if(_fpMode > 1) _fpMode = 0;
705                 }
706             }
707         } else {
708             _delFP = true;
709             _uLinePos = 1;
710             _kln89->_mode = KLN89_MODE_CRSR;
711         }
712     }
713 }
714
715 void KLN89FplPage::CleanUp() {
716     // TODO - possibly need to clean up _delWp here as well, since it goes off if dto and then ent are pressed.
717     
718     _bEntWp = false;
719     for(unsigned int i = 0; i < _kln89->_flightPlans[_subPage]->waypoints.size(); ++i) {
720         if(_kln89->_flightPlans[_subPage]->waypoints[i] == _entWp) {
721             _kln89->_flightPlans[_subPage]->waypoints.erase(_kln89->_flightPlans[_subPage]->waypoints.begin() + i);
722         }
723     }
724     delete _entWp;
725     _entWp = NULL;
726     _entWpStr.clear();
727     KLN89Page::CleanUp();
728 }
729
730 void KLN89FplPage::LooseFocus() {
731     _fplPos = 0;
732     _resetFplPos0 = true;
733     _wLinePos = 0;
734     _uLinePos = 0;
735     _fp0SelWpId.clear();
736     _scratchpadMsg = false;
737 }
738
739 void KLN89FplPage::EntPressed() {
740     if(_delFP) {
741         _kln89->ClearFlightPlan(_subPage);
742         CrsrPressed();
743     } else if(_delWp) {
744         int pos = _uLinePos - 4 + _fplPos;
745         // Sanity check - the calculated wp position should never be off the end of the waypoint list.
746         if(pos > static_cast<int>(_kln89->_flightPlans[_subPage]->waypoints.size()) - 1) {
747             SG_LOG(SG_GENERAL, SG_ALERT, "ERROR - _uLinePos too big in KLN89FplPage::EntPressed!\n");
748             return;
749         }
750         _kln89->_flightPlans[_subPage]->waypoints.erase(_kln89->_flightPlans[_subPage]->waypoints.begin() + pos);
751         _delWp = false;
752         // Do we need to re-calc _fplPos here?
753     } else if(_bEntExp) {
754         // We get here if we have just approved a waypoint review for addition with the ENT button
755         _bEntWp = false;
756         _bEntExp = false;
757         _entWp = NULL;  // DON'T delete it! - it's been pushed onto the waypoint list at this point.
758         _entWpStr.clear();
759         _kln89->_cleanUpPage = -1;
760         _wLinePos = 0;
761         // The cursor should be moved either to the next waypoint in the list, or to the empty position at
762         // the end of the list if the waypoint just entered was the last one in the list.  Unfortunately
763         // that means that we have to deal with the horrible _uLinePos / _fplPos interaction yet again :-(
764         if(_uLinePos == 4) {
765             // We can't handle this case by calling K1R1, since we want to jump the field type
766             _uLinePos = 5;
767         } else {
768             // Just call Knob1Right1 and let that handle the horrible logic :-)
769             Knob1Right1();
770         }
771     } else if(_bEntWp) {
772         if(_entWp != NULL) {
773             // TODO - should be able to get rid of this switch I think and use the enum values.
774             switch(_entWp->type) {
775             case GPS_WP_APT:
776                 _kln89->_activePage = _kln89->_pages[0];
777                 _kln89->_curPage = 0;
778                 ((KLN89Page*)_kln89->_pages[0])->SetEntInvert(true);
779                 break;
780             case GPS_WP_VOR:
781                 _kln89->_activePage = _kln89->_pages[1];
782                 _kln89->_curPage = 1;
783                 ((KLN89Page*)_kln89->_pages[1])->SetEntInvert(true);
784                 break;
785             case GPS_WP_NDB:
786                 _kln89->_activePage = _kln89->_pages[2];
787                 _kln89->_curPage = 2;
788                 ((KLN89Page*)_kln89->_pages[2])->SetEntInvert(true);
789                 break;
790             case GPS_WP_INT:
791                 _kln89->_activePage = _kln89->_pages[3];
792                 _kln89->_curPage = 3;
793                 ((KLN89Page*)_kln89->_pages[3])->SetEntInvert(true);
794                 break;
795             case GPS_WP_USR:
796                 _kln89->_activePage = _kln89->_pages[4];
797                 _kln89->_curPage = 4;
798                 ((KLN89Page*)_kln89->_pages[4])->SetEntInvert(true);
799                 break;
800             default:
801                 SG_LOG(SG_GENERAL, SG_ALERT, "Error - unknown waypoint type found in KLN89::FplPage::EntPressed()\n");
802             }
803             _kln89->_activePage->SetId(_entWp->id);
804             _kln89->_entJump = _kln89->_clrJump = 7;
805             _kln89->_cleanUpPage = 7;
806             _kln89->_jumpRestoreCrsr = true;
807             _kln89->_mode = KLN89_MODE_DISP;
808         }
809         _bEntExp = true;
810     } else if(_uLinePos == 1) {
811         if(_kln89->_flightPlans[_subPage]->IsEmpty()) {
812             // Copy fpl 0
813             for(unsigned int i=0; i<_kln89->_flightPlans[0]->waypoints.size(); ++i) {
814                 GPSWaypoint* wp = new GPSWaypoint;
815                 *wp = *(_kln89->_flightPlans[0]->waypoints[i]);
816                 _kln89->_flightPlans[_subPage]->waypoints.push_back(wp);
817             }
818         } else {
819             // Use
820             _kln89->ClearFlightPlan(0);
821             for(unsigned int i=0; i<_kln89->_flightPlans[_subPage]->waypoints.size(); ++i) {
822                 GPSWaypoint* wp = new GPSWaypoint;
823                 *wp = *(_kln89->_flightPlans[_subPage]->waypoints[i]);
824                 _kln89->_flightPlans[0]->waypoints.push_back(wp);
825             }
826             _kln89->OrientateToActiveFlightPlan();
827             _subPage = 0;
828         }
829         _kln89->CrsrPressed();
830     } else if(_uLinePos == 2) {
831         if(_kln89->_flightPlans[_subPage]->IsEmpty()) {
832             // ERROR !!!
833         } else {
834             // Use Invert
835             _kln89->ClearFlightPlan(0);
836             for(unsigned int i=0; i<_kln89->_flightPlans[_subPage]->waypoints.size(); ++i) {
837                 GPSWaypoint* wp = new GPSWaypoint;
838                 *wp = *(_kln89->_flightPlans[_subPage]->waypoints[i]);
839                 // FIXME - very inefficient - use a reverse iterator on the source array and push_back instead!!!!!!!!
840                 _kln89->_flightPlans[0]->waypoints.insert(_kln89->_flightPlans[0]->waypoints.begin(), wp);
841             }
842             _kln89->OrientateToActiveFlightPlan();
843         }
844         _kln89->CrsrPressed();
845         _subPage = 0;
846     }
847 }
848
849 void KLN89FplPage::Knob1Left1() {
850     if(_delFP) {
851         _delFP = false;
852         return;
853     }
854     _delWp = false;
855     _changeAppr = false;
856
857     if(_kln89->_mode == KLN89_MODE_CRSR) {
858         if(_bEntWp) {
859             if(_wLinePos > 0) _wLinePos--;
860         } else {
861             // _uLinePos with empty/not-empty plan: 1 = Copy FPL 0? / Use?, 2 = unused if empty / Invert?, 3 = >Dis/Dtk field, 4+ = Waypoint 1+
862             if(_uLinePos == 0) {
863                 // No-op
864             } else if(_uLinePos == 1 || _uLinePos == 2) {
865                 _uLinePos--;
866             } else if(_uLinePos == 3) {
867                 _uLinePos = 4;
868             } else if(_uLinePos == 4) {
869                 if(_kln89->_flightPlans[_subPage]->IsEmpty()) {
870                     _uLinePos = (_subPage == 0 ? 0 : 1);
871                 } else if(_fplPos == 0) {
872                     _uLinePos = (_subPage == 0 ? 0 : 2);
873                 } else {
874                     _fplPos--;
875                 }
876             } else if(_uLinePos == 5) {
877                 _uLinePos = 3;
878             } else {
879                 _uLinePos--;
880             }
881
882             if(_subPage == 0 && _uLinePos > 3) {
883                 int ix = _fplPos + (_uLinePos - 4);
884                 if(_fencePos >= 0 && ix >= _fencePos) ix--;
885                 if(_hdrPos >= 0 && ix >= _hdrPos) ix--;
886                 if(ix >= static_cast<int>(_kln89->_activeFP->waypoints.size())) {
887                     _fp0SelWpId.clear();
888                 } else {
889                     _fp0SelWpId = _kln89->_activeFP->waypoints[ix]->id;
890                 }
891             } else {
892                 _fp0SelWpId.clear();
893                 //cout << "Not page 0, or not in waypoints, clearing id!\n";
894             }
895         }
896     }
897 }
898
899 void KLN89FplPage::Knob1Right1() {
900     if(_delFP) {
901         _delFP = false;
902         return;
903     }
904     _delWp = false;
905     _changeAppr = false;
906     
907     if(_kln89->_mode == KLN89_MODE_CRSR) {
908         if(_bEntWp) {
909             if(_wLinePos < 4) _wLinePos++;
910         } else {
911             // _uLinePos with empty/not-empty plan: 
912             // 1 = Copy FPL 0? / Use?, 2 = unused if empty / Invert?, 3 = >Dis/Dtk field, 4+ = Waypoint 1+
913             if(_uLinePos == 0) {
914                 _uLinePos = (_subPage == 0 ? 4 : 1);
915             } else if(_uLinePos == 1) {
916                 _uLinePos = (_kln89->_flightPlans[_subPage]->IsEmpty() ? 4 : 2);
917             } else if(_uLinePos == 2) {
918                 _uLinePos = 4;
919             } else if(_uLinePos == 3) {
920                 if(!_kln89->_flightPlans[_subPage]->IsEmpty()) _uLinePos = 5;
921             } else if(_uLinePos == 4) {
922                 _uLinePos = 3;
923             } else if((_subPage == 0 && _uLinePos == 6) || (_subPage > 0 && _uLinePos == 5)) {
924                 // Urrggh - complicated!
925                 // 3 possibilities:
926                 // 1: We're on the entry field at the end of the list, and can't move any more.
927                 // 2: We're on the last or second-last field, and move to the last position
928                 // 3: We're on a field before the second-last one, and don't move, but change the list-head position
929                 // And 4: _subPage 0 can be complicated by the presence of header/fence lines in an approach.
930                 int hfcount = 0;
931                 if(_subPage == 0) {
932                     if(_hdrPos >= 0) hfcount++;
933                     if(_fencePos >= 0) hfcount++;
934                 }
935                 if(_kln89->_flightPlans[_subPage]->waypoints.size() == 1 || _fplPos == _kln89->_flightPlans[_subPage]->waypoints.size() + hfcount - 1) {
936                     // 1: Don't move
937                 } else if((int)_fplPos >= static_cast<int>(_kln89->_flightPlans[_subPage]->waypoints.size()) + hfcount - (_subPage == 0 ? 4 : 3)) {
938                     _uLinePos++;
939                 } else {
940                     _fplPos++;
941                 }
942             } else if(_uLinePos == 5) {
943                 // Must be _subPage 0
944                 _uLinePos++;
945             } else {
946                 // Must be the last line - either _uLinePos 6 or 7 depending on _subPage
947                 const unsigned thresh = (_subPage == 0 ? 3 : 2);
948                 if(_kln89->_flightPlans[_subPage]->waypoints.size() == thresh || _fplPos == _kln89->_flightPlans[_subPage]->waypoints.size() - thresh) {
949                     // Don't move
950                 } else {
951                     _fplPos++;
952                 }
953             }
954             
955             if(_subPage == 0 && _uLinePos > 3) {
956                 int ix = _fplPos + (_uLinePos - 4);
957                 if(_fencePos >= 0 && ix >= _fencePos) ix--;
958                 if(_hdrPos >= 0 && ix >= _hdrPos) ix--;
959                 if(ix >= static_cast<int>(_kln89->_activeFP->waypoints.size())) {
960                     _fp0SelWpId.clear();
961                 } else {
962                     _fp0SelWpId = _kln89->_activeFP->waypoints[ix]->id;
963                 }
964             } else {
965                 _fp0SelWpId.clear();
966                 //cout << "Not page 0, or not in waypoints, clearing id!\n";
967             }
968         }
969     }
970 }
971
972 void KLN89FplPage::Knob2Left1() {
973     if(_delFP) {
974         _delFP = false;
975         return;
976     }
977     _delWp = false;
978
979     if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) {
980         if(_kln89->_mode != KLN89_MODE_CRSR) _resetFplPos0 = true;
981         KLN89Page::Knob2Left1();
982     } else {
983         if(_uLinePos > 3) {
984             // Check for approach waypoints or header/fences in flightplan 0
985             int n = _fplPos + _uLinePos - 4;
986             bool hdrPos = false;
987             bool fencePos = false;
988             bool appWp = false;
989             //cout << "_fplPos = " << _fplPos << ", _uLinePos = " << _uLinePos << ", n = " << n << ", _hdrPos = " << _hdrPos << ", _fencePos = " << _fencePos << '\n';
990             if(n == _hdrPos) {
991                 //cout << "HEADER POS\n";
992                 hdrPos = true;
993             }
994             if(n == _fencePos) {
995                 //cout << "FENCE POS\n";
996                 fencePos = true;
997             }
998             if(_hdrPos >= 0 && n > _hdrPos) --n;
999             if(_fencePos >= 0 && n >= _fencePos) --n;   // This one needs to be >= since n is already decremented by 1 in the line above!
1000             //cout << "New n = " << n << '\n';
1001             
1002             if(n < static_cast<int>(_kln89->_flightPlans[_subPage]->waypoints.size())) {
1003                 if(_kln89->_flightPlans[_subPage]->waypoints[n]->appType != GPS_APP_NONE) {
1004                     appWp = true;
1005                 }
1006             }
1007             
1008             if(hdrPos) {
1009                 // TODO - not sure what we actually do in this condition
1010                 _changeAppr = true;
1011             } else if(fencePos) {
1012                 // no-op?
1013             } else if(appWp) {
1014                 ShowScratchpadMessage("Invald", " Add  ");
1015             } else {
1016                 if(!_entWpStr.size()) {
1017                     _entWpStr += _kln89->DecChar(_kln89->_defaultFirstChar, false, true);
1018                 } else if((_wLinePos + 1) > _entWpStr.size()) {
1019                     // I don't think we can ever reach this state since I think it only ever applies to the
1020                     // first char and gets caught by the line above, but it can stay for now just in case.
1021                     _entWpStr += '9';
1022                 } else {
1023                     _entWpStr[_wLinePos] = _kln89->DecChar(_entWpStr[_wLinePos], (_wLinePos == 0 ? false : true));
1024                 }
1025                 _bEntWp = true;
1026                 _fp0SelWpId.clear();    // Waypoints don't become the DTO default whilst being entered.
1027                 
1028                 GPSWaypoint* wp = _kln89->FindFirstById(_entWpStr.substr(0, _wLinePos+1));
1029                 if(NULL == wp) {
1030                     // No ID matches the partial ID entered so _entWpStr must be shortened to the cursor
1031                     // position if it was longer due to a match on the previous character.
1032                     if(_entWpStr.size() > _wLinePos+1) {
1033                         _entWpStr = _entWpStr.substr(0, _wLinePos+1);
1034                     }
1035                 } else {
1036                     // There is a matching full ID to the entered partial ID, so copy the full ID
1037                     // into _entWpStr
1038                     _entWpStr = wp->id;
1039                     if(_entWp) {
1040                         *_entWp = *wp; // copy
1041                         delete wp;
1042                     } else {
1043                         _entWp = wp;
1044                         if(_fplPos + (_uLinePos - 4) >= _kln89->_flightPlans[_subPage]->waypoints.size()) {
1045                             _kln89->_flightPlans[_subPage]->waypoints.push_back(_entWp);
1046                         } else {
1047                             _kln89->_flightPlans[_subPage]->waypoints.insert(_kln89->_flightPlans[_subPage]->waypoints.begin()+(_fplPos + (_uLinePos - 4)), _entWp);
1048                         }
1049                     }
1050                 }
1051             }
1052         }
1053     }
1054 }
1055
1056 void KLN89FplPage::Knob2Right1() {
1057     if(_delFP) {
1058         _delFP = false;
1059         return;
1060     }
1061     _delWp = false;
1062
1063     if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) {
1064         if(_kln89->_mode != KLN89_MODE_CRSR) _resetFplPos0 = true;
1065         KLN89Page::Knob2Right1();
1066     } else {
1067         if(_uLinePos > 3) {
1068             // Check for approach waypoints or header/fences in flightplan 0
1069             int n = _fplPos + _uLinePos - 4;
1070             bool hdrPos = false;
1071             bool fencePos = false;
1072             bool appWp = false;
1073             //cout << "_fplPos = " << _fplPos << ", _uLinePos = " << _uLinePos << ", n = " << n << ", _hdrPos = " << _hdrPos << ", _fencePos = " << _fencePos << '\n';
1074             if(n == _hdrPos) {
1075                 //cout << "HEADER POS\n";
1076                 hdrPos = true;
1077             }
1078             if(n == _fencePos) {
1079                 //cout << "FENCE POS\n";
1080                 fencePos = true;
1081             }
1082             if(_hdrPos >= 0 && n > _hdrPos) --n;
1083             if(_fencePos >= 0 && n >= _fencePos) --n;   // This one needs to be >= since n is already decremented by 1 in the line above!
1084             //cout << "New n = " << n << '\n';
1085             
1086             if(n < static_cast<int>(_kln89->_flightPlans[_subPage]->waypoints.size())) {
1087                 if(_kln89->_flightPlans[_subPage]->waypoints[n]->appType != GPS_APP_NONE) {
1088                     appWp = true;
1089                 }
1090             }
1091             
1092             if(hdrPos) {
1093                 // TODO - not sure what we actually do in this condition
1094                 _changeAppr = true;
1095             } else if(fencePos) {
1096                 // no-op?
1097             } else if(appWp) {
1098                 ShowScratchpadMessage("Invald", " Add  ");
1099             } else {
1100                 if(!_entWpStr.size()) {
1101                     _entWpStr += _kln89->_defaultFirstChar;
1102                 } else if((_wLinePos + 1) > _entWpStr.size()) {
1103                     // I don't think we can ever reach this state since I think it only ever applies to the
1104                     // first char and gets caught by the line above, but it can stay for now just in case.
1105                     _entWpStr += 'A';
1106                 } else {
1107                     _entWpStr[_wLinePos] = _kln89->IncChar(_entWpStr[_wLinePos], (_wLinePos == 0 ? false : true));
1108                 }
1109                 _bEntWp = true;
1110                 _fp0SelWpId.clear();    // Waypoints don't become the DTO default whilst being entered.
1111                 
1112                 GPSWaypoint* wp = _kln89->FindFirstById(_entWpStr.substr(0, _wLinePos+1));
1113                 if(NULL == wp) {
1114                     // No ID matches the partial ID entered so _entWpStr must be shortened to the cursor
1115                     // position if it was longer due to a match on the previous character.
1116                     if(_entWpStr.size() > _wLinePos+1) {
1117                         _entWpStr = _entWpStr.substr(0, _wLinePos+1);
1118                     }
1119                 } else {
1120                     // There is a matching full ID to the entered partial ID, so copy the full ID
1121                     // into _entWpStr
1122                     _entWpStr = wp->id;
1123                     if(_entWp) {
1124                         *_entWp = *wp; // copy
1125                         delete wp;
1126                     } else {
1127                         _entWp = wp;
1128                         if(_fplPos + (_uLinePos - 4) >= _kln89->_flightPlans[_subPage]->waypoints.size()) {
1129                             _kln89->_flightPlans[_subPage]->waypoints.push_back(_entWp);
1130                         } else {
1131                             _kln89->_flightPlans[_subPage]->waypoints.insert(_kln89->_flightPlans[_subPage]->waypoints.begin()+(_fplPos + (_uLinePos - 4)), _entWp);
1132                         }
1133                     }
1134                 }
1135             }
1136         }
1137     }
1138 }