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