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