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