]> git.mxchange.org Git - flightgear.git/blob - src/Instrumentation/KLN89/kln89_page_nav.cxx
Make traffic take-off roll look a little better.
[flightgear.git] / src / Instrumentation / KLN89 / kln89_page_nav.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 <cstdlib>
29
30 #include "kln89_page_nav.hxx"
31 #include <Main/fg_props.hxx>
32
33 using std::string;
34
35 KLN89NavPage::KLN89NavPage(KLN89* parent) 
36 : KLN89Page(parent) {
37         _nSubPages = 4;
38         _subPage = 0;
39         _name = "NAV";
40         _posFormat = 0;         // Check - should this default to ref from waypoint?
41         _vnv = 0;
42         _nav4DataSnippet = 0;
43         _cdiFormat = 0;
44         _menuActive = false;
45         _menuPos = 0;
46         _suspendAVS = false;
47         _scanWpSet = false;
48         _scanWpIndex = -1;
49 }
50
51 KLN89NavPage::~KLN89NavPage() {
52 }
53
54 void KLN89NavPage::Update(double dt) {
55         GPSFlightPlan* fp = _kln89->_activeFP;
56         GPSWaypoint* awp = _kln89->GetActiveWaypoint();
57         // Scan-pull out on nav4 page switches off the cursor
58         if(3 == _subPage && fgGetBool("/instrumentation/kln89/scan-pull")) { _kln89->_mode = KLN89_MODE_DISP; }
59         bool crsr = (_kln89->_mode == KLN89_MODE_CRSR);
60         bool blink = _kln89->_blink;
61         double lat = _kln89->_gpsLat * SG_RADIANS_TO_DEGREES;
62         double lon = _kln89->_gpsLon * SG_RADIANS_TO_DEGREES;
63         
64         if(_subPage != 3) { _scanWpSet = false; }
65         
66         if(0 == _subPage) {
67                 if(_kln89->_navFlagged) {
68                         _kln89->DrawText(">    F L A G", 2, 0, 2);
69                         _kln89->DrawText("DTK ---  TK ---", 2, 0, 1);
70                         _kln89->DrawText(">--- To    --:--", 2, 0, 0);
71                         _kln89->DrawSpecialChar(0, 2, 7, 1);
72                         _kln89->DrawSpecialChar(0, 2, 15, 1);
73                         _kln89->DrawSpecialChar(0, 2, 4, 0);
74                         _kln89->DrawSpecialChar(1, 2, 3, 2);
75                         _kln89->DrawSpecialChar(1, 2, 4, 2);
76                         _kln89->DrawSpecialChar(1, 2, 6, 2);
77                         _kln89->DrawSpecialChar(1, 2, 10, 2);
78                         _kln89->DrawSpecialChar(1, 2, 12, 2);
79                         _kln89->DrawSpecialChar(1, 2, 13, 2);
80                 } else {
81                         if(_kln89->_dto) {
82                                 _kln89->DrawDTO(2, 7, 3);
83                         } else {
84                                 if(!(_kln89->_waypointAlert && _kln89->_blink)) {
85                                         _kln89->DrawSpecialChar(3, 2, 8, 3);
86                                 }
87                         }
88                         _kln89->DrawText(awp->id, 2, 10, 3);
89                         if(!_kln89->_dto && !_kln89->_obsMode && !_kln89->_fromWaypoint.id.empty()) {
90                                 if(_kln89->_fromWaypoint.type != GPS_WP_VIRT) {         // Don't draw the virtual waypoint names
91                                         _kln89->DrawText(_kln89->_fromWaypoint.id, 2, 1, 3);
92                                 }
93                         }
94                         if(!(crsr && blink && _uLinePos == 1)) {
95                                 if(_cdiFormat == 0) {
96                                         _kln89->DrawCDI();
97                                 } else if(_cdiFormat == 1) {
98                                         _kln89->DrawText("Fly", 2, 2, 2);
99                                         double x = _kln89->CalcCrossTrackDeviation();
100                                         // TODO - check the R/L from sign of x below - I *think* it holds but not sure!
101                                         // Note also that we're setting Fly R or L based on the aircraft
102                                         // position only, not the heading.  Not sure if this is correct or not.
103                                         _kln89->DrawText(x < 0.0 ? "R" : "L", 2, 6, 2);
104                                         char buf[6];
105                                         int n;
106                                         x = fabs(x * (_kln89->_distUnits == GPS_DIST_UNITS_NM ? 1.0 : SG_NM_TO_METER * 0.001));
107                                         if(x < 1.0) {
108                                                 n = snprintf(buf, 6, "%0.2f", x);
109                                         } else if(x < 100.0) {
110                                                 n = snprintf(buf, 6, "%0.1f", x);
111                                         } else {
112                                                 n = snprintf(buf, 6, "%i", (int)(x+0.5));
113                                         }
114                                         _kln89->DrawText((string)buf, 2, 13-n, 2);
115                                         _kln89->DrawText(_kln89->_distUnits == GPS_DIST_UNITS_NM ? "nm" : "km", 2, 13, 2);
116                                 } else {
117                                         _kln89->DrawText("CDI Scale:", 2, 1, 2);
118                                         double d = _kln89->_cdiScales[_kln89->_currentCdiScaleIndex] * (_kln89->_distUnits == GPS_DIST_UNITS_NM ? 1.0 : SG_NM_TO_METER * 0.001);
119                                         char buf[5];
120                                         string s;
121                                         if(d >= 1.0) {
122                                                 snprintf(buf, 4, "%2.1f", d);
123                                                 s = buf;
124                                         } else {
125                                                 snprintf(buf, 5, "%2.2f", d);
126                                                 // trim the leading zero
127                                                 s = buf;
128                                                 s = s.substr(1, s.size() - 1);
129                                         }
130                                         _kln89->DrawText(s, 2, 11, 2);
131                                         _kln89->DrawText(_kln89->_distUnits == GPS_DIST_UNITS_NM ? "nm" : "km", 2, 14, 2);
132                                 }
133                         }
134                         _kln89->DrawChar('>', 2, 0, 2);
135                         _kln89->DrawChar('>', 2, 0, 0);
136                         if(crsr) {
137                                 if(_uLinePos == 1) _kln89->Underline(2, 1, 2, 15);
138                                 else if(_uLinePos == 2) _kln89->Underline(2, 1, 0, 9);
139                         }
140                         // Desired and actual magnetic track
141                         if(!_kln89->_obsMode) {
142                                 _kln89->DrawText("DTK", 2, 0, 1);
143                                 _kln89->DrawHeading((int)_kln89->_dtkMag, 2, 7, 1);
144                         }
145                         _kln89->DrawText("TK", 2, 9, 1);
146                         if(_kln89->_groundSpeed_ms > 3) {       // about 6 knots, don't know exactly what value to disable track
147                                 // The trouble with relying on FG gps's track value is we don't know when it's valid.
148                                 _kln89->DrawHeading((int)_kln89->_magTrackDeg, 2, 15, 1);
149                         } else {
150                                 _kln89->DrawText("---", 2, 12, 1);
151                                 _kln89->DrawSpecialChar(0, 2, 15, 1);
152                         }
153                         
154                         // Radial to/from active waypoint.
155                         // TODO - Not sure if this either is or should be true or mag!!!!!!!
156                         if(!(crsr && blink && _uLinePos == 2)) {
157                                 if(0 == _vnv) {
158                                         _kln89->DrawHeading((int)_kln89->GetHeadingToActiveWaypoint(), 2, 4, 0);
159                                         _kln89->DrawText("To", 2, 5, 0);
160                                 } else if(1 == _vnv) {
161                                         _kln89->DrawHeading((int)_kln89->GetHeadingFromActiveWaypoint(), 2, 4, 0);
162                                         _kln89->DrawText("Fr", 2, 5, 0);
163                                 } else {
164                                         _kln89->DrawText("Vnv Off", 2, 1, 0);
165                                 }
166                         }
167                         // It seems that the floating point groundspeed must be at least 30kt
168                         // for an ETA to be calculated.  Note that this means that (integer) 30kt
169                         // can appear in the frame 1 display both with and without an ETA displayed.
170                         // TODO - need to switch off track (and heading bug change) based on instantaneous speed as well
171                         // since the long gps lag filter means we can still be displaying when stopped on ground.
172                         if(_kln89->_groundSpeed_kts > 30.0) {
173                                 // Assuming eta display is always hh:mm
174                                 // Does it ever switch to seconds when close?
175                                 if(_kln89->_eta / 3600.0 > 100.0) {
176                                         // More that 100 hours ! - Doesn't fit.
177                                         _kln89->DrawText("--:--", 2, 11, 0);
178                                 } else {
179                                         _kln89->DrawTime(_kln89->_eta, 2, 15, 0);
180                                 }
181                         } else {
182                                 _kln89->DrawText("--:--", 2, 11, 0);
183                         }
184                 }
185         } else if(1 == _subPage) {
186                 // Present position
187                 _kln89->DrawChar('>', 2, 1, 3);
188                 if(!(crsr && blink && _uLinePos == 1)) _kln89->DrawText("PRESENT POSN", 2, 2, 3);
189                 if(crsr && _uLinePos == 1) _kln89->Underline(2, 2, 3, 12);
190                 if(0 == _posFormat) {
191                         // Lat/lon
192                         _kln89->DrawLatitude(lat, 2, 3, 1);
193                         _kln89->DrawLongitude(lon, 2, 3, 0);
194                 } else {
195                         // Ref from wp - defaults to nearest vor (and resets to default when page left and re-entered).
196                 }
197         } else if(2 == _subPage) {
198                 _kln89->DrawText("Time", 2, 0, 3);
199                 // TODO - hardwired to UTC at the moment
200                 _kln89->DrawText("UTC", 2, 6, 3);
201                 string th = fgGetString("/instrumentation/clock/indicated-hour");
202                 string tm = fgGetString("/instrumentation/clock/indicated-min");
203                 if(th.size() == 1) th = "0" + th;
204                 if(tm.size() == 1) tm = "0" + tm;
205                 _kln89->DrawText(th + tm, 2, 11, 3);
206                 _kln89->DrawText("Depart", 2, 0, 2);
207                 _kln89->DrawText(_kln89->_departureTimeString, 2, 11, 2);
208                 _kln89->DrawText("ETA", 2, 0, 1);
209                 if(_kln89->_departed) {
210                         /* Rules of ETA waypoint are:
211                          If the active waypoint is part of the active flightplan, then display
212                          the ETA to the final (destination) waypoint of the active flightplan.
213                          If the active waypoint is not part of the active flightplan, then
214                          display the ETA to the active waypoint. */
215                         // TODO - implement the above properly - we haven't below!
216                         string wid = "";
217                         if(fp->waypoints.size()) {
218                                 wid = fp->waypoints[fp->waypoints.size() - 1]->id;
219                         } else if(awp) {
220                                 wid = awp->id;
221                         }
222                         if(!wid.empty()) {
223                                 _kln89->DrawText(wid, 2, 4, 1);
224                                 double tsec = _kln89->GetTimeToWaypoint(wid);
225                                 if(tsec < 0.0) {
226                                         _kln89->DrawText("----", 2, 11, 1);
227                                 } else {
228                                         int etah = (int)tsec / 3600;
229                                         int etam = ((int)tsec - etah * 3600) / 60;
230                                         etah += atoi(fgGetString("/instrumentation/clock/indicated-hour"));
231                                         etam += atoi(fgGetString("/instrumentation/clock/indicated-min"));
232                                         while(etam > 59) {
233                                                 etam -= 60;
234                                                 etah += 1;
235                                         }
236                                         while(etah > 23) {
237                                                 etah -= 24;
238                                         }
239                                         char buf[6];
240                                         int n = snprintf(buf, 6, "%02i%02i", etah, etam);
241                                         _kln89->DrawText((string)buf, 2, 15-n, 1);
242                                 }
243                         } else {
244                                 _kln89->DrawText("----", 2, 11, 1);
245                         }
246                 } else {
247                         _kln89->DrawText("----", 2, 11, 1);
248                 }
249                 _kln89->DrawText("Flight", 2, 0, 0);
250                 if(_kln89->_departed) {
251                         int eh = (int)_kln89->_elapsedTime / 3600;
252                         int em = ((int)_kln89->_elapsedTime - eh * 3600) / 60;
253                         char buf[6];
254                         int n = snprintf(buf, 6, "%i:%02i", eh, em);
255                         _kln89->DrawText((string)buf, 2, 15-n, 0);
256                 } else {
257                         _kln89->DrawText("-:--", 2, 11, 0);
258                 }
259         } else {        // if(3 == _subPage)
260                 //
261                 // Switch the cursor off if scan-pull is out on this page.
262                 //
263                 if(fgGetBool("/instrumentation/kln89/scan-pull")) { _kln89->_mode = KLN89_MODE_DISP; } 
264                 
265                 //
266                 // Draw the moving map if valid.
267                 // We call the core KLN89 class to do this.
268                 //
269                 if(_kln89->_mapOrientation == 2 && _kln89->_groundSpeed_kts < 2) {
270                         // Don't draw it if in track up mode and groundspeed < 2kts, as per real-life unit.
271                 } else {
272                         _kln89->DrawMap(!_suspendAVS);
273                 }
274                 
275                 //
276                 // Now that the map has been drawn, add the annotation (scale, etc).
277                 //
278                 int scale = KLN89MapScales[_kln89->_mapScaleUnits][_kln89->_mapScaleIndex];
279                 string scle_str = GPSitoa(scale);
280                 if(crsr) {
281                         if(_menuActive) {
282                                 // Draw a background quad to encompass on/off for the first three at 'off' length
283                                 _kln89->DrawMapQuad(28, 9, 48, 36, true);
284                                 _kln89->DrawMapText("SUA:", 1, 27, true);
285                                 if(!(_menuPos == 0 && _kln89->_blink)) _kln89->DrawMapText((_kln89->_drawSUA ? "on" : "off"), 29, 27, true);
286                                 if(_menuPos == 0) _kln89->DrawLine(28, 27, 48, 27);
287                                 _kln89->DrawMapText("VOR:", 1, 18, true);
288                                 if(!(_menuPos == 1 && _kln89->_blink)) _kln89->DrawMapText((_kln89->_drawVOR ? "on" : "off"), 29, 18, true);
289                                 if(_menuPos == 1) _kln89->DrawLine(28, 18, 48, 18);
290                                 _kln89->DrawMapText("APT:", 1, 9, true);
291                                 if(!(_menuPos == 2 && _kln89->_blink)) _kln89->DrawMapText((_kln89->_drawApt ? "on" : "off"), 29, 9, true);
292                                 if(_menuPos == 2) _kln89->DrawLine(28, 9, 48, 9);
293                                 _kln89->DrawMapQuad(0, 0, 27, 8, true);
294                                 if(!(_menuPos == 3 && _kln89->_blink)) {
295                                         if(_kln89->_mapOrientation == 0) {
296                                                 _kln89->DrawMapText("N", 1, 0, true);
297                                                 _kln89->DrawMapUpArrow(7, 1);
298                                         } else if(_kln89->_mapOrientation == 1) {
299                                                 _kln89->DrawMapText("DTK", 1, 0, true);
300                                                 _kln89->DrawMapUpArrow(21, 1);
301                                         } else {
302                                                 // Don't bother with heading up for now!
303                                                 _kln89->DrawMapText("TK", 1, 0, true);
304                                                 _kln89->DrawMapUpArrow(14, 1);
305                                         }
306                                 }
307                                 if(_menuPos == 3) _kln89->DrawLine(0, 0, 27, 0);
308                         } else {
309                                 if(_uLinePos == 2) {
310                                         if(!_kln89->_blink) {
311                                                 _kln89->DrawMapText("Menu?", 1, 9, true);
312                                                 _kln89->DrawEnt();
313                                                 _kln89->DrawLine(0, 9, 34, 9);
314                                         } else {
315                                                 _kln89->DrawMapQuad(0, 9, 34, 17, true);
316                                         }
317                                 } else {
318                                         _kln89->DrawMapText("Menu?", 1, 9, true);
319                                 }
320                                 // right-justify the scale when _uLinePos == 3
321                                 if(!(_uLinePos == 3 && _kln89->_blink)) _kln89->DrawMapText(scle_str, (_uLinePos == 3 ? 29 - (scle_str.size() * 7) : 1), 0, true);
322                                 if(_uLinePos == 3) _kln89->DrawLine(0, 0, 27, 0);
323                         }
324                 } else {
325                         // Just draw the scale
326                         _kln89->DrawMapText(scle_str, 1, 0, true);
327                 }
328                 // If the scan-pull knob is out, draw one of the waypoints (if applicable).
329                 if(fgGetBool("/instrumentation/kln89/scan-pull")) {
330                         if(_kln89->_activeFP->waypoints.size()) {
331                                 //cout << "Need to draw a waypoint!\n";
332                                 _kln89->DrawLine(70, 0, 111, 0);
333                                 if(!_kln89->_blink) {
334                                         //_kln89->DrawMapQuad(45, 0, 97, 8, true);
335                                         if(!_scanWpSet) {
336                                                 _scanWpIndex = _kln89->GetActiveWaypointIndex();
337                                                 _scanWpSet = true;
338                                         }
339                                         _kln89->DrawMapText(_kln89->_activeFP->waypoints[_scanWpIndex]->id, 71, 0, true);
340                                 }               
341                         }
342                 }
343                 
344                 //
345                 // Do part of the field 1 update, since NAV 4 is a special case for the last line.
346                 //
347                 _kln89->DrawChar('>', 1, 0, 0);
348                 if(crsr && _uLinePos == 1) _kln89->Underline(1, 1, 0, 5);
349                 if(!(crsr && _uLinePos == 1 && _kln89->_blink)) {
350                         if(_kln89->_obsMode && _nav4DataSnippet == 0) _nav4DataSnippet = 1;
351                         double tsec;
352                         switch(_nav4DataSnippet) {
353                         case 0:
354                                 // DTK
355                                 _kln89->DrawLabel("DTK", -39, 6); 
356                                 // TODO - check we have an active FP / dtk and draw dashes if not.
357                                 char buf0[4];
358                                 snprintf(buf0, 4, "%03i", (int)(_kln89->_dtkMag));
359                                 _kln89->DrawText((string)buf0, 1, 3, 0);
360                                 break;
361                         case 1:
362                                 // groundspeed
363                                 _kln89->DrawSpeed(_kln89->_groundSpeed_kts, 1, 5, 0);
364                                 break;
365                         case 2:
366                                 // ETE
367                                 tsec = _kln89->GetETE();
368                                 if(tsec < 0.0) {
369                                         _kln89->DrawText("--:--", 1, 1, 0);
370                                 } else {
371                                         int eteh = (int)tsec / 3600;
372                                         int etem = ((int)tsec - eteh * 3600) / 60;
373                                         char buf[6];
374                                         int n = snprintf(buf, 6, "%02i:%02i", eteh, etem);
375                                         _kln89->DrawText((string)buf, 1, 6-n, 0);
376                                 }
377                                 break;
378                         case 3:
379                                 // Cross-track correction
380                                 double x = _kln89->CalcCrossTrackDeviation();
381                                 if(x < 0.0) {
382                                         _kln89->DrawSpecialChar(3, 1, 5, 0);
383                                 } else {
384                                         _kln89->DrawSpecialChar(7, 1, 5, 0);
385                                 }
386                                 char buf3[6];
387                                 int n;
388                                 x = fabs(x * (_kln89->_distUnits == GPS_DIST_UNITS_NM ? 1.0 : SG_NM_TO_METER * 0.001));
389                                 if(x < 1.0) {
390                                         n = snprintf(buf3, 6, "%0.2f", x);
391                                 } else if(x < 100.0) {
392                                         n = snprintf(buf3, 6, "%0.1f", x);
393                                 } else {
394                                         n = snprintf(buf3, 6, "%i", (int)(x+0.5));
395                                 }
396                                 _kln89->DrawText((string)buf3, 1, 5-n, 0);
397                                 break;
398                         }
399                 }
400         }
401         
402         KLN89Page::Update(dt);
403 }
404
405 // Returns the id string of the selected waypoint on NAV4 if valid, else returns an empty string.
406 string KLN89NavPage::GetNav4WpId() {
407         if(3 == _subPage) {
408                 if(fgGetBool("/instrumentation/kln89/scan-pull")) {
409                         if(_kln89->_activeFP->waypoints.size()) {
410                                 if(!_scanWpSet) {
411                                         return(_kln89->_activeWaypoint.id);
412                                 } else {
413                                         return(_kln89->_activeFP->waypoints[_scanWpIndex]->id);
414                                 }               
415                         }
416                 }
417         }
418         return("");
419 }
420
421 void KLN89NavPage::LooseFocus() {
422         _suspendAVS = false;
423         _scanWpSet = false;
424 }
425
426 void KLN89NavPage::CrsrPressed() {
427         if(_kln89->_mode == KLN89_MODE_DISP) {
428                 // Crsr just switched off
429                 _menuActive = false;
430         } else {
431                 // Crsr just switched on
432                 if(_subPage < 3) {
433                         _uLinePos = 1;
434                 } else {
435                         _uLinePos = 3;
436                 }
437         }
438 }
439
440 void KLN89NavPage::EntPressed() {
441         if(_kln89->_mode == KLN89_MODE_CRSR) {
442                 if(_subPage == 3 && _uLinePos == 2 && !_menuActive) {
443                         _menuActive = true;
444                         _menuPos = 0;
445                         _suspendAVS = false;
446                 }
447         }
448 }
449
450 void KLN89NavPage::ClrPressed() {
451         if(_kln89->_mode == KLN89_MODE_CRSR) {
452                 if(_subPage == 0) {
453                         if(_uLinePos == 1) {
454                                 _cdiFormat++;
455                                 if(_cdiFormat > 2) _cdiFormat = 0;
456                         } else if(_uLinePos == 2) {
457                                 _vnv++;
458                                 if(_vnv > 2) _vnv = 0;
459                         }
460                 }
461                 if(_subPage == 3) {
462                         if(_uLinePos > 1) {
463                                 _suspendAVS = !_suspendAVS;
464                                 _menuActive = false;
465                         } else if(_uLinePos == 1) {
466                                 _nav4DataSnippet++;
467                                 if(_nav4DataSnippet > 3) _nav4DataSnippet = 0;
468                         }
469                 }
470         } else {
471                 if(_subPage == 3) {
472                         _suspendAVS = !_suspendAVS;
473                 }
474         }
475 }
476
477 void KLN89NavPage::Knob1Left1() {
478         if(_kln89->_mode == KLN89_MODE_CRSR) {
479                 if(!(_subPage == 3 && _menuActive)) {
480                         if(_uLinePos > 0) _uLinePos--;
481                 } else {
482                         if(_menuPos > 0) _menuPos--;
483                 }
484         }
485 }
486
487 void KLN89NavPage::Knob1Right1() {
488         if(_kln89->_mode == KLN89_MODE_CRSR) {
489                 if(_subPage < 2) {
490                         if(_uLinePos < 2) _uLinePos++;
491                 } else if(_subPage == 2) {
492                         _uLinePos = 1;
493                 } else {
494                         // NAV 4 - this is complicated by whether the menu is displayed or not.
495                         if(_menuActive) {
496                                 if(_menuPos < 3) _menuPos++;
497                         } else {
498                                 if(_uLinePos < 3) _uLinePos++;
499                         }
500                 }
501         }
502 }
503
504 void KLN89NavPage::Knob2Left1() {
505         // If the inner-knob is out on the nav4 page, the only effect is to cycle the displayed waypoint.
506         if(3 == _subPage && fgGetBool("/instrumentation/kln89/scan-pull")) {
507                 if(_kln89->_activeFP->waypoints.size()) {       // TODO - find out what happens when scan-pull is on on nav4 without an active FP.
508                         // It's unlikely that we could get here without _scanWpSet, but theoretically possible, so we need to cover it.
509                         if(!_scanWpSet) {
510                                 _scanWpIndex = _kln89->GetActiveWaypointIndex();
511                                 _scanWpSet = true;
512                         } else {
513                                 if(0 == _scanWpIndex) {
514                                         _scanWpIndex = _kln89->_activeFP->waypoints.size() - 1;
515                                 } else {
516                                         _scanWpIndex--;
517                                 }
518                         }
519                 }
520                 return;
521         }
522         if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) {
523                 KLN89Page::Knob2Left1();
524                 return;
525         }
526         if(_subPage == 0) {
527                 if(_uLinePos == 1 && _cdiFormat == 2) {
528                         _kln89->CDIFSDIncrease();
529                 }
530         } else if(_subPage == 3) {
531                 if(_menuActive) {
532                         if(_menuPos == 0) {
533                                 _kln89->_drawSUA = !_kln89->_drawSUA;
534                         } else if(_menuPos == 1) {
535                                 _kln89->_drawVOR = !_kln89->_drawVOR;
536                         } else if(_menuPos == 2) {
537                                 _kln89->_drawApt = !_kln89->_drawApt;
538                         } else {
539                                 if(_kln89->_mapOrientation == 0) {
540                                         // Don't allow heading up for now
541                                         _kln89->_mapOrientation = 2;
542                                 } else {
543                                         _kln89->_mapOrientation--;
544                                 }
545                                 _kln89->UpdateMapHeading();
546                         }
547                 } else if(_uLinePos == 3) {
548                         // TODO - add AUTO
549                         if(_kln89->_mapScaleIndex == 0) {
550                                 _kln89->_mapScaleIndex = 20;
551                         } else {
552                                 _kln89->_mapScaleIndex--;
553                         }
554                 }
555         }
556 }
557
558 void KLN89NavPage::Knob2Right1() {
559         // If the inner-knob is out on the nav4 page, the only effect is to cycle the displayed waypoint.
560         if(3 == _subPage && fgGetBool("/instrumentation/kln89/scan-pull")) {
561                 if(_kln89->_activeFP->waypoints.size()) {       // TODO - find out what happens when scan-pull is on on nav4 without an active FP.
562                         // It's unlikely that we could get here without _scanWpSet, but theoretically possible, so we need to cover it.
563                         if(!_scanWpSet) {
564                                 _scanWpIndex = _kln89->GetActiveWaypointIndex();
565                                 _scanWpSet = true;
566                         } else {
567                                 _scanWpIndex++;
568                                 if(_scanWpIndex > static_cast<int>(_kln89->_activeFP->waypoints.size()) - 1) {
569                                         _scanWpIndex = 0;
570                                 }
571                         }
572                 }
573                 return;
574         }
575         if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) {
576                 KLN89Page::Knob2Right1();
577                 return;
578         }
579         if(_subPage == 0) {
580                 if(_uLinePos == 1 && _cdiFormat == 2) {
581                         _kln89->CDIFSDDecrease();
582                 }
583         } else if(_subPage == 3) {
584                 if(_menuActive) {
585                         if(_menuPos == 0) {
586                                 _kln89->_drawSUA = !_kln89->_drawSUA;
587                         } else if(_menuPos == 1) {
588                                 _kln89->_drawVOR = !_kln89->_drawVOR;
589                         } else if(_menuPos == 2) {
590                                 _kln89->_drawApt = !_kln89->_drawApt;
591                         } else {
592                                 if(_kln89->_mapOrientation >= 2) {
593                                         // Don't allow heading up for now
594                                         _kln89->_mapOrientation = 0;
595                                 } else {
596                                         _kln89->_mapOrientation++;
597                                 }
598                                 _kln89->UpdateMapHeading();
599                         }
600                 } else if(_uLinePos == 3) {
601                         // TODO - add AUTO
602                         if(_kln89->_mapScaleIndex == 20) {
603                                 _kln89->_mapScaleIndex = 0;
604                         } else {
605                                 _kln89->_mapScaleIndex++;
606                         }
607                 }
608         }
609 }