1 // kln89_page_*.[ch]xx - this file is one of the "pages" that
2 // are used in the KLN89 GPS unit simulation.
4 // Written by David Luff, started 2005.
6 // Copyright (C) 2005 - David C Luff - david.luff@nottingham.ac.uk
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.
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.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #include "kln89_page_fpl.hxx"
33 KLN89FplPage::KLN89FplPage(KLN89* parent)
53 KLN89FplPage::~KLN89FplPage() {
56 void KLN89FplPage::Update(double dt) {
59 // NOTE - we need to draw the active leg arrow outside of this block to avoid the _delFP check.
60 // TODO - we really ought to merge the page 0 and other pages drawing code with a couple of lines of extra logic.
61 if(_subPage == 0 && !_delFP) { // Note that in the _delFP case, the active flightplan gets a header, and hence the same geometry as the other fps, so we draw it there.
63 // NOTE THAT FOR THE ACTIVE FLIGHT PLAN, TOP POSITION IS STILL 4 in the underline position scheme, to make
64 // copy and paste easier!!!!
66 // ---------------------------------- Copy the active FlightPlan and insert approach header and fence if required ---------------
67 // For synatical convienience
68 //vector<GPSWaypoint*> waylist = _kln89->_flightPlans[_subPage]->waypoints;
69 // Copy every waypoint for now.
70 // This is inefficient, but allows us to insert dummy waypoints to represent the header and fence
71 // in our *local copy* of the flightplan, if an approach is loaded. There must be a better way to do this!!!!
72 //cout << "AA" << endl;
73 vector<GPSWaypoint> waylist;
74 for(unsigned int i=0; i<_kln89->_flightPlans[_subPage]->waypoints.size(); ++i) {
75 waylist.push_back(*_kln89->_flightPlans[_subPage]->waypoints[i]);
77 //cout << "BB" << endl;
80 if(_kln89->_approachLoaded) {
83 wp.type = GPS_WP_VIRT;
85 //cout << "CC" << endl;
86 for(unsigned int i=0; i<waylist.size(); ++i) {
87 // Insert the hdr immediately before the IAF
88 if(waylist[i].appType == GPS_IAF) {
89 waylist.insert(waylist.begin()+i, wp);
90 // Need to insert empty string into the params to keep them in sync
91 _params.insert(_params.begin()+i-1, "");
96 //cout << "DD" << endl;
98 wp.type = GPS_WP_VIRT;
99 wp.appType = GPS_FENCE;
100 for(unsigned int i=0; i<waylist.size(); ++i) {
101 // Insert the fence between the MAF and the MAP
102 if(waylist[i].appType == GPS_MAHP) {
103 waylist.insert(waylist.begin()+i, wp);
104 // Need to insert empty string into the params to keep them in sync
105 _params.insert(_params.begin()+i-1, "");
112 // Now make up a vector of waypoint numbers, since they aren't aligned with list position anymore
116 for(unsigned int i=0; i<waylist.size(); ++i) {
117 if(waylist[i].appType != GPS_HDR && waylist[i].appType != GPS_FENCE) {
118 numlist.push_back(num);
121 numlist.push_back(-1);
126 for(unsigned int i=0; i<waylist.size(); ++i) {
127 //cout << i + 1 - hfcount << ": ID= " << waylist[i].id;
128 if(waylist[i].appType == GPS_HDR) {
132 if(waylist[i].appType == GPS_FENCE) {
138 //----------------------------------------- end active FP copy ------------------------------------------------
140 // Recalculate which waypoint is displayed at the top of the list if required (generally if this page has lost focus).
141 int idx = _parent->GetActiveWaypointIndex();
143 if(waylist.size() <= 1) {
145 } else if(waylist.size() <= 4) {
148 // Make the active waypoint the second WP displayed
154 //cout << "HeaderPos = " << _hdrPos << ", fencePos = " << _fencePos << ", _fplPos = " << _fplPos << ", active waypoint index = " << _parent->GetActiveWaypointIndex() << '\n';
155 if(_hdrPos >= 0 && idx >= _hdrPos) {
157 if(_fencePos >= 0 && (idx + 1) >= _fencePos) {
161 _resetFplPos0 = false;
164 // Increment the active waypoint position if required due hdr and fence here not above so it gets called every frame
165 if(_hdrPos >= 0 && idx >= _hdrPos) {
167 if(_fencePos >= 0 && idx >= _fencePos) {
172 // Draw the leg arrow etc
173 int diff = idx - (int)_fplPos;
176 // No active waypoint
177 } else if(diff < 0) {
178 // Off screen to the top
179 } else if(diff > 2) {
184 // Only the head is blinked during waypoint alerting
185 if(!(_kln89->_waypointAlert && _kln89->_blink)) {
186 _kln89->DrawSpecialChar(4, 2, 0, 3-drawPos);
188 // If the active waypoint is immediately after an approach header then we need to do an extra-long tail leg
189 if(_hdrPos >= 0 && idx == _hdrPos + 1) {
190 if(drawPos > 0 && !_kln89->_dto) _kln89->DrawLongLegTail(3-drawPos);
192 if(drawPos > 0 && !_kln89->_dto) _kln89->DrawLegTail(3-drawPos);
195 //cout << "Top pos is " << _fplPos0 << ' ';
197 if(_kln89->_mode == KLN89_MODE_CRSR) {
199 _kln89->Underline(2, 13, 3, 3);
200 } else if(_uLinePos >= 4) {
203 _kln89->Underline(2, 5, 3 - (_uLinePos - 4), 4);
204 } else if(_wLinePos == 4) {
205 _kln89->Underline(2, 4, 3 - (_uLinePos - 4), 4);
207 _kln89->Underline(2, 4, 3 - (_uLinePos - 4), _wLinePos);
208 _kln89->Underline(2, 5 + _wLinePos, 3 - (_uLinePos - 4), 4 - _wLinePos);
210 if(!_kln89->_blink) {
211 //_kln89->DrawText(_entWp->id, 2, 4, 2 - (_uLinePos - 4), false, _wLinePos);
215 _kln89->Underline(2, 4, 3 - (_uLinePos - 4), 5);
219 // ----------------------------------
220 //cout << "A1" << endl;
222 // Sanity check the top position - remember that we can have an extra blank one at the bottom even if CRSR is off if crsr is switched on then off
223 if((int)_fplPos > ((int)waylist.size()) - 3) _fplPos = (((int)waylist.size()) - 3 < 0 ? 0 : waylist.size() - 3);
224 unsigned int last_pos;
225 if(waylist.empty()) {
228 last_pos = ((int)_fplPos == ((int)waylist.size()) - 3 ? waylist.size() : waylist.size() - 1);
230 //cout << "Initialising last_pos, last_pos = " << last_pos << '\n';
231 //cout << "B1" << endl;
232 if(waylist.size() < 4) last_pos = waylist.size();
234 // Don't draw the cyclic field header if the top waypoint is the approach header
235 // Not sure if this also applies to the fence - don't think so but TODO - check!
236 if(waylist[_fplPos].appType != GPS_HDR) {
237 _kln89->DrawChar('>', 2, 12, 3);
238 if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 3 && _kln89->_blink)) {
244 for(unsigned int i=0; i<4; ++i) {
245 //cout << "F1... " << i << endl;
246 // Don't draw the waypoint number for the header or fence
247 //cout << "_fplPos0 = " << _fplPos0 << ", waylist size is " << waylist.size() << '\n';
248 //cout << "F1, i = " << i << ", way id = " << waylist[_fplPos0+i].id << '\n';
249 if((waylist[_fplPos+i].appType == GPS_HDR || waylist[_fplPos+i].appType == GPS_FENCE)
250 && i != 3) { // By definition, the header and fence lines can't be displayed on the last line hence the unconditional !i==3 is safe.
254 int n = (i < 3 ? _fplPos + i + 1 : last_pos + 1);
255 if(_kln89->_approachLoaded) {
257 if(n > _fencePos) --n;
259 string s = GPSitoa(n);
260 // Don't draw the colon for waypoints that are part of the published approach
261 if(waylist[_fplPos+i].appType == GPS_APP_NONE) {
264 if(!(_delWp && _uLinePos == i+4)) _kln89->DrawText(s, 2, 4 - (s[s.size()-1] == ':' ? s.size() : s.size()+1), 3 - i);
266 //cout << "F1 done!\n";
268 if(_delWp && _uLinePos == i+4) {
269 if(!_kln89->_blink) {
270 _kln89->DrawText("Del", 2, 0, 3-i);
271 _kln89->DrawChar('?', 2, 10, 3-i);
272 _kln89->Underline(2, 0, 3-i, 11);
275 } else if(_kln89->_mode == KLN89_MODE_CRSR && _bEntWp && _uLinePos == i+4) {
276 if(!_kln89->_blink) {
277 if(_wLinePos >= _entWp->id.size()) {
278 _kln89->DrawText(_entWp->id, 2, 4, 3-i);
279 _kln89->DrawChar(' ', 2, 4+_wLinePos, 3-i, false, true);
281 _kln89->DrawText(_entWp->id.substr(0, _wLinePos), 2, 4, 3-i);
282 _kln89->DrawChar(_entWp->id[_wLinePos], 2, 4+_wLinePos, 3-i, false, true);
283 _kln89->DrawText(_entWp->id.substr(_wLinePos+1, _entWp->id.size()-_wLinePos-1), 2, 5+_wLinePos, 3-i);
288 //cout << "F2" << endl;
290 //cout << "F2a" << endl;
291 if(i == 3 || _fplPos + i == waylist.size()) {
292 //cout << "F2a1" << endl;
293 //cout << "_uLinePos = " << _uLinePos << ", i = " << i << ", waylist.size() = " << waylist.size() << endl;
294 if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == (i + 4) && _kln89->_blink)) {
295 //cout << "Drawing underline..." << endl;
296 _kln89->DrawText(last_pos < waylist.size() ? waylist[last_pos].GetAprId() : "_____", 2, 4, 3-i);
297 //cout << "2" << endl;
299 //cout << "3" << endl;
300 //cout << "last_pos = " << last_pos << endl;
301 if(last_pos > 0 && last_pos < waylist.size() && i > 0) {
302 //cout << "4" << endl;
304 if(_actFpMode == 0) {
305 string s = _params[last_pos - 1];
306 _kln89->DrawText(s, 2, 16-s.size(), 3-i);
307 } else if(_actFpMode == 3) {
308 string s = _params[last_pos - 1];
309 _kln89->DrawText(s, 2, 15-s.size(), 3-i);
310 _kln89->DrawSpecialChar(0, 2, 15, 3-i);
312 //cout << "5" << endl;
314 //cout << "6" << endl;
317 //cout << "F2a2" << endl;
318 if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == (i + 4) && _kln89->_blink)) {
319 if(waylist[_fplPos+i].appType == GPS_HDR) {
321 _kln89->DrawText("DELETE APPR?", 2, 1, 3-i);
322 } else if(_changeAppr) {
323 _kln89->DrawText("CHANGE APPR?", 2, 1, 3-i);
325 _kln89->DrawText(_kln89->_approachAbbrev, 2, 1, 3-i);
326 _kln89->DrawText(_kln89->_approachRwyStr, 2, 7, 3-i);
327 _kln89->DrawText(_kln89->_approachID, 2, 12, 3-i);
329 } else if(waylist[_fplPos+i].appType == GPS_FENCE) {
330 _kln89->DrawText("*NO WPT SEQ", 2, 0, 3-i);
332 _kln89->DrawText(waylist[_fplPos+i].GetAprId(), 2, 4, 3-i);
336 //cout << "F2b" << endl;
339 //cout << "i > 0 param draw...\n";
340 if(_actFpMode == 0) {
341 string s = _params[_fplPos + i - 1];
342 _kln89->DrawText(s, 2, 16-s.size(), 3-i);
343 } else if(_actFpMode == 3) {
344 string s = _params[_fplPos + i - 1];
345 _kln89->DrawText(s, 2, 15-s.size(), 3-i);
346 _kln89->DrawSpecialChar(0, 2, 15, 3-i);
349 //cout << "F2c" << endl;
351 //cout << "F3" << endl;
353 //cout << "GGGGGG" << endl;
354 } else { // Not active flightplan
355 //cout << "Top pos is " << _fplPos << ' ';
356 // For synatical convienience
357 //int nWp = (_subPage == 0 && !_delFP ? 4 : 3); // number of waypoints to display
358 vector<GPSWaypoint*> waylist = _kln89->_flightPlans[_subPage]->waypoints;
359 if(waylist.empty()) {
360 if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 1 && _kln89->_blink)) {
361 _kln89->DrawText(_delFP ? "Delete FPL?" : "Copy FPL 0?", 2, 0, 3);
364 if(!(_kln89->_mode == KLN89_MODE_CRSR && (_uLinePos == 1 || _uLinePos == 2) && _kln89->_blink)) {
365 _kln89->DrawText(_delFP ? "Delete FPL?" : "Use?", 2, 0, 3);
367 if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 2 && _kln89->_blink)) {
368 if(!_delFP) _kln89->DrawText("Inverted?", 2, 5, 3);
372 // ----------------------------------
373 if(_kln89->_mode == KLN89_MODE_CRSR) {
375 if(!_kln89->_blink) {
376 _kln89->Underline(2, 0, 3, (waylist.empty() || _delFP ? 11 : 4)); // This underline is blinked
379 } else if(_uLinePos == 2) {
380 // assert(!waylist.empty());
381 if(!_kln89->_blink) {
382 _kln89->Underline(2, 0, 3, 14); // This underline is blinked
385 } else if(_uLinePos == 3) {
386 _kln89->Underline(2, 13, 2, 3);
387 } else if(_uLinePos >= 4) {
390 _kln89->Underline(2, 5, 2 - (_uLinePos - 4), 4);
391 } else if(_wLinePos == 4) {
392 _kln89->Underline(2, 4, 2 - (_uLinePos - 4), 4);
394 _kln89->Underline(2, 4, 2 - (_uLinePos - 4), _wLinePos);
395 _kln89->Underline(2, 5 + _wLinePos, 2 - (_uLinePos - 4), 4 - _wLinePos);
397 if(!_kln89->_blink) {
398 //_kln89->DrawText(_entWp->id, 2, 4, 2 - (_uLinePos - 4), false, _wLinePos);
402 if(!_delWp) _kln89->Underline(2, 4, 2 - (_uLinePos - 4), 5);
406 // ----------------------------------
408 _kln89->DrawChar('>', 2, 12, 2);
409 if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 3 && _kln89->_blink)) DrawFpMode(2);
410 // Sanity check the top position - remember that we can have an extra blank one at the bottom even if CRSR is off if crsr is switched on then off
411 if((int)_fplPos > ((int)waylist.size()) - 2) _fplPos = (((int)waylist.size()) - 2 < 0 ? 0 : waylist.size() - 2);
412 unsigned int last_pos;
413 if(waylist.empty()) {
416 last_pos = ((int)_fplPos == ((int)waylist.size()) - 2 ? waylist.size() : waylist.size() - 1);
418 if(waylist.size() < 3) last_pos = waylist.size();
419 for(unsigned int i=0; i<3; ++i) {
420 string s = GPSitoa(i < 2 ? _fplPos + i + 1 : last_pos + 1);
422 if(!(_delWp && _uLinePos == i+4)) _kln89->DrawText(s, 2, 4 - s.size(), 2 - i);
424 if(_delWp && _uLinePos == i+4) {
425 if(!_kln89->_blink) {
426 _kln89->DrawText("Del", 2, 0, 2-i);
427 _kln89->DrawChar('?', 2, 10, 2-i);
428 _kln89->Underline(2, 0, 2-i, 11);
431 } else if(_kln89->_mode == KLN89_MODE_CRSR && _bEntWp && _uLinePos == i+4) {
432 if(!_kln89->_blink) {
433 if(_wLinePos >= _entWp->id.size()) {
434 _kln89->DrawText(_entWp->id, 2, 4, 2-i);
435 _kln89->DrawChar(' ', 2, 4+_wLinePos, 2-i, false, true);
437 _kln89->DrawText(_entWp->id.substr(0, _wLinePos), 2, 4, 2-i);
438 _kln89->DrawChar(_entWp->id[_wLinePos], 2, 4+_wLinePos, 2-i, false, true);
439 _kln89->DrawText(_entWp->id.substr(_wLinePos+1, _entWp->id.size()-_wLinePos-1), 2, 5+_wLinePos, 2-i);
445 if(i == 2 || _fplPos + i == waylist.size()) {
446 if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == (i + 4) && _kln89->_blink)) {
447 _kln89->DrawText(last_pos < waylist.size() ? waylist[last_pos]->id : "_____", 2, 4, 2-i);
449 if(last_pos > 0 && last_pos < waylist.size() && i > 0) {
452 string s = _params[last_pos - 1];
453 _kln89->DrawText(s, 2, 16-s.size(), 2-i);
458 if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == (i + 4) && _kln89->_blink)) {
459 _kln89->DrawText(waylist[_fplPos+i]->id, 2, 4, 2-i);
464 string s = _params[_fplPos + i - 1];
465 _kln89->DrawText(s, 2, 16-s.size(), 2-i);
473 KLN89Page::Update(dt);
476 void KLN89FplPage::DrawFpMode(int ypos) {
479 if(_actFpMode == 1) {
481 } else if(_actFpMode == 2) {
482 s = "UTC"; // TODO - alter depending on chosen timezone
483 } else if(_actFpMode == 3) {
484 s = (_kln89->_obsMode ? "OBS" : "Dtk");
491 _kln89->DrawText(s, 2, 13, ypos);
494 // Bit of an ipsy-dipsy function this one - calc the required parameters for the displayed flightplan.
495 void KLN89FplPage::Calc() {
497 GPSFlightPlan* fp = _kln89->_flightPlans[_subPage];
498 vector<GPSWaypoint*> wv = fp->waypoints;
500 // Active FP - parameters are only displayed for the active waypoint onwards for the active plan,
501 // and distance is cumulative from the user position.
502 if(0 == _actFpMode) {
504 double cum_tot = 0.0;
506 //cum_tot += _kln89->GetHorizontalSeparation(_kln89->_gpsLat, _kln89->_gpsLon, wv[0]->lat, wv[0]->lon) * SG_METER_TO_NM;
507 cum_tot += _kln89->GetGreatCircleDistance(_kln89->_gpsLat, _kln89->_gpsLon, wv[0]->lat, wv[0]->lon);
509 for(unsigned int i=1; i<wv.size(); ++i) {
510 //cum_tot += _kln89->GetHorizontalSeparation(wv[i-1]->lat, wv[i-1]->lon, wv[i]->lat, wv[i]->lon) * SG_METER_TO_NM; // TODO - add units switch!
511 cum_tot += _kln89->GetGreatCircleDistance(wv[i-1]->lat, wv[i-1]->lon, wv[i]->lat, wv[i]->lon); // TODO - add units switch!
512 int n = (int)(cum_tot + 0.5);
513 _params.push_back(GPSitoa(n));
515 } else if(1 == _actFpMode) {
516 } else if(2 == _actFpMode) {
519 for(int i=1; i<wv.size(); ++i) {
520 double dtk = _kln89->GetMagHeadingFromTo(wv[i-1]->lat, wv[i-1]->lon, wv[i]->lat, wv[i]->lon);
521 int n = (int)(dtk + 0.5);
522 _params.push_back(GPSitoa(n));
529 double cum_tot = 0.0;
530 for(int i=1; i<wv.size(); ++i) {
531 //cum_tot += _kln89->GetHorizontalSeparation(wv[i-1]->lat, wv[i-1]->lon, wv[i]->lat, wv[i]->lon) * SG_METER_TO_NM; // TODO - add units switch!
532 cum_tot += _kln89->GetGreatCircleDistance(wv[i-1]->lat, wv[i-1]->lon, wv[i]->lat, wv[i]->lon); // TODO - add units switch!
533 int n = (int)(cum_tot + 0.5);
534 _params.push_back(GPSitoa(n));
541 void KLN89FplPage::CrsrPressed() {
544 _kln89->_mode = KLN89_MODE_DISP;
549 if(_kln89->_mode == KLN89_MODE_DISP) {
552 for(unsigned int i = 0; i < _kln89->_flightPlans[_subPage]->waypoints.size(); ++i) {
553 if(_kln89->_flightPlans[_subPage]->waypoints[i] == _entWp) {
554 _kln89->_flightPlans[_subPage]->waypoints.erase(_kln89->_flightPlans[_subPage]->waypoints.begin() + i);
563 if(_kln89->_obsMode) {
566 if(_kln89->_flightPlans[_subPage]->IsEmpty()) {
569 _uLinePos = (_subPage == 0 ? 3 : 1);
575 void KLN89FplPage::ClrPressed() {
577 _kln89->_mode = KLN89_MODE_DISP;
579 } else if(_delAppr) {
580 _kln89->_mode = KLN89_MODE_DISP;
583 if(KLN89_MODE_CRSR == _kln89->_mode) {
584 // TODO - see if we need to delete a waypoint
587 _kln89->_mode = KLN89_MODE_DISP;
590 // First check that we're not trying to delete an approach waypoint. Note that we can delete the approach by deleting the header though.
591 // Check for approach waypoints or header/fences in flightplan 0
592 int n = _fplPos + _uLinePos - 4;
594 bool fencePos = false;
595 //cout << "_fplPos = " << _fplPos << ", _uLinePos = " << _uLinePos << ", n = " << n << ", _hdrPos = " << _hdrPos << ", _fencePos = " << _fencePos << '\n';
597 //cout << "HEADER POS\n";
601 //cout << "FENCE POS\n";
604 if(_hdrPos >= 0 && n > _hdrPos) --n;
605 if(_fencePos >= 0 && n >= _fencePos) --n; // This one needs to be >= since n is already decremented by 1 in the line above!
606 //cout << "New n = " << n << '\n';
610 } else if(fencePos) {
613 } else if(n >= _kln89->_flightPlans[_subPage]->waypoints.size()) {
614 // no-op - off the end of the list on the entry field
615 } else if(_kln89->_flightPlans[_subPage]->waypoints[n]->appType == GPS_APP_NONE) {
617 _kln89->_mode = KLN89_MODE_CRSR;
620 ShowScratchpadMessage("Invald", " Del ");
623 } else if(_uLinePos == 3) {
626 if(_actFpMode > 3) _actFpMode = 0;
629 if(_fpMode > 1) _fpMode = 0;
635 _kln89->_mode = KLN89_MODE_CRSR;
640 void KLN89FplPage::CleanUp() {
641 // TODO - possibly need to clean up _delWp here as well, since it goes off if dto and then ent are pressed.
644 for(unsigned int i = 0; i < _kln89->_flightPlans[_subPage]->waypoints.size(); ++i) {
645 if(_kln89->_flightPlans[_subPage]->waypoints[i] == _entWp) {
646 _kln89->_flightPlans[_subPage]->waypoints.erase(_kln89->_flightPlans[_subPage]->waypoints.begin() + i);
652 KLN89Page::CleanUp();
655 void KLN89FplPage::LooseFocus() {
657 _resetFplPos0 = true;
661 _scratchpadMsg = false;
664 void KLN89FplPage::EntPressed() {
666 _parent->ClearFlightPlan(_subPage);
669 int pos = _uLinePos - 4 + _fplPos;
670 // Sanity check - the calculated wp position should never be off the end of the waypoint list.
671 if(pos > _kln89->_flightPlans[_subPage]->waypoints.size() - 1) {
672 cout << "ERROR - _uLinePos too big in KLN89FplPage::EntPressed!\n";
675 _kln89->_flightPlans[_subPage]->waypoints.erase(_kln89->_flightPlans[_subPage]->waypoints.begin() + pos);
677 // Do we need to re-calc _fplPos here?
678 } else if(_bEntExp) {
681 _entWp = NULL; // DON'T delete it! - it's been pushed onto the waypoint list at this point.
683 _kln89->_cleanUpPage = -1;
685 // TODO - in actual fact the previously underlined waypoint stays in the same position and underlined
686 // in some or possibly all circumstances - need to check this out and match it, but not too important
690 // TODO - should be able to get rid of this switch I think and use the enum values.
691 switch(_entWp->type) {
693 _kln89->_activePage = _kln89->_pages[0];
694 _kln89->_curPage = 0;
695 ((KLN89Page*)_kln89->_pages[0])->SetEntInvert(true);
698 _kln89->_activePage = _kln89->_pages[1];
699 _kln89->_curPage = 1;
700 ((KLN89Page*)_kln89->_pages[1])->SetEntInvert(true);
703 _kln89->_activePage = _kln89->_pages[2];
704 _kln89->_curPage = 2;
705 ((KLN89Page*)_kln89->_pages[2])->SetEntInvert(true);
708 _kln89->_activePage = _kln89->_pages[3];
709 _kln89->_curPage = 3;
710 ((KLN89Page*)_kln89->_pages[3])->SetEntInvert(true);
713 _kln89->_activePage = _kln89->_pages[4];
714 _kln89->_curPage = 4;
715 ((KLN89Page*)_kln89->_pages[4])->SetEntInvert(true);
718 cout << "Error - unknown waypoint type found in KLN89::FplPage::EntPressed()\n";
720 _kln89->_activePage->SetId(_entWp->id);
721 _kln89->_entJump = 7;
722 _kln89->_cleanUpPage = 7;
723 _kln89->_entRestoreCrsr = true;
724 _kln89->_mode = KLN89_MODE_DISP;
727 } else if(_uLinePos == 1) {
728 if(_kln89->_flightPlans[_subPage]->IsEmpty()) {
730 for(unsigned int i=0; i<_kln89->_flightPlans[0]->waypoints.size(); ++i) {
731 GPSWaypoint* wp = new GPSWaypoint;
732 *wp = *(_kln89->_flightPlans[0]->waypoints[i]);
733 _kln89->_flightPlans[_subPage]->waypoints.push_back(wp);
737 _parent->ClearFlightPlan(0);
738 for(unsigned int i=0; i<_kln89->_flightPlans[_subPage]->waypoints.size(); ++i) {
739 GPSWaypoint* wp = new GPSWaypoint;
740 *wp = *(_kln89->_flightPlans[_subPage]->waypoints[i]);
741 _kln89->_flightPlans[0]->waypoints.push_back(wp);
743 _kln89->OrientateToActiveFlightPlan();
746 _parent->CrsrPressed();
747 } else if(_uLinePos == 2) {
748 if(_kln89->_flightPlans[_subPage]->IsEmpty()) {
752 _parent->ClearFlightPlan(0);
753 for(unsigned int i=0; i<_kln89->_flightPlans[_subPage]->waypoints.size(); ++i) {
754 GPSWaypoint* wp = new GPSWaypoint;
755 *wp = *(_kln89->_flightPlans[_subPage]->waypoints[i]);
756 // FIXME - very inefficient - use a reverse iterator on the source array and push_back instead!!!!!!!!
757 _kln89->_flightPlans[0]->waypoints.insert(_kln89->_flightPlans[0]->waypoints.begin(), wp);
759 _kln89->OrientateToActiveFlightPlan();
761 _parent->CrsrPressed();
766 void KLN89FplPage::Knob1Left1() {
774 if(_kln89->_mode == KLN89_MODE_CRSR) {
776 if(_wLinePos > 0) _wLinePos--;
778 // _uLinePos with empty/not-empty plan: 1 = Copy FPL 0? / Use?, 2 = unused if empty / Invert?, 3 = >Dis/Dtk field, 4+ = Waypoint 1+
781 } else if(_uLinePos == 1 || _uLinePos == 2) {
783 } else if(_uLinePos == 3) {
785 } else if(_uLinePos == 4) {
786 if(_kln89->_flightPlans[_subPage]->IsEmpty()) {
787 _uLinePos = (_subPage == 0 ? 0 : 1);
788 } else if(_fplPos == 0) {
789 _uLinePos = (_subPage == 0 ? 0 : 2);
793 } else if(_uLinePos == 5) {
799 if(_subPage == 0 && _uLinePos > 3) {
800 int ix = _fplPos + (_uLinePos - 4);
801 if(_fencePos >= 0 && ix >= _fencePos) ix--;
802 if(_hdrPos >= 0 && ix >= _hdrPos) ix--;
803 if(ix >= _kln89->_activeFP->waypoints.size()) {
806 _fp0SelWpId = _kln89->_activeFP->waypoints[ix]->id;
810 //cout << "Not page 0, or not in waypoints, clearing id!\n";
816 void KLN89FplPage::Knob1Right1() {
824 if(_kln89->_mode == KLN89_MODE_CRSR) {
826 if(_wLinePos < 4) _wLinePos++;
828 // _uLinePos with empty/not-empty plan:
829 // 1 = Copy FPL 0? / Use?, 2 = unused if empty / Invert?, 3 = >Dis/Dtk field, 4+ = Waypoint 1+
831 _uLinePos = (_subPage == 0 ? 4 : 1);
832 } else if(_uLinePos == 1) {
833 _uLinePos = (_kln89->_flightPlans[_subPage]->IsEmpty() ? 4 : 2);
834 } else if(_uLinePos == 2) {
836 } else if(_uLinePos == 3) {
837 if(!_kln89->_flightPlans[_subPage]->IsEmpty()) _uLinePos = 5;
838 } else if(_uLinePos == 4) {
840 } else if((_subPage == 0 && _uLinePos == 6) || (_subPage > 0 && _uLinePos == 5)) {
841 // Urrggh - complicated!
843 // 1: We're on the entry field at the end of the list, and can't move any more.
844 // 2: We're on the last or second-last field, and move to the last position
845 // 3: We're on a field before the second-last one, and don't move, but change the list-head position
846 // And 4: _subPage 0 can be complicated by the presence of header/fence lines in an approach.
849 if(_hdrPos >= 0) hfcount++;
850 if(_fencePos >= 0) hfcount++;
852 if(_kln89->_flightPlans[_subPage]->waypoints.size() == 1 || _fplPos == _kln89->_flightPlans[_subPage]->waypoints.size() + hfcount - 1) {
854 } else if(_fplPos >= _kln89->_flightPlans[_subPage]->waypoints.size() + hfcount - (_subPage == 0 ? 4 : 3)) {
859 } else if(_uLinePos == 5) {
860 // Must be _subPage 0
863 // Must be the last line - either _uLinePos 6 or 7 depending on _subPage
864 int thresh = (_subPage == 0 ? 3 : 2);
865 if(_kln89->_flightPlans[_subPage]->waypoints.size() == thresh || _fplPos == _kln89->_flightPlans[_subPage]->waypoints.size() - thresh) {
872 if(_subPage == 0 && _uLinePos > 3) {
873 int ix = _fplPos + (_uLinePos - 4);
874 if(_fencePos >= 0 && ix >= _fencePos) ix--;
875 if(_hdrPos >= 0 && ix >= _hdrPos) ix--;
876 if(ix >= _kln89->_activeFP->waypoints.size()) {
879 _fp0SelWpId = _kln89->_activeFP->waypoints[ix]->id;
883 //cout << "Not page 0, or not in waypoints, clearing id!\n";
889 void KLN89FplPage::Knob2Left1() {
896 if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) {
897 if(_kln89->_mode != KLN89_MODE_CRSR) _resetFplPos0 = true;
898 KLN89Page::Knob2Left1();
901 // Check for approach waypoints or header/fences in flightplan 0
902 int n = _fplPos + _uLinePos - 4;
904 bool fencePos = false;
906 //cout << "_fplPos = " << _fplPos << ", _uLinePos = " << _uLinePos << ", n = " << n << ", _hdrPos = " << _hdrPos << ", _fencePos = " << _fencePos << '\n';
908 //cout << "HEADER POS\n";
912 //cout << "FENCE POS\n";
915 if(_hdrPos >= 0 && n > _hdrPos) --n;
916 if(_fencePos >= 0 && n >= _fencePos) --n; // This one needs to be >= since n is already decremented by 1 in the line above!
917 //cout << "New n = " << n << '\n';
919 if(n < _kln89->_flightPlans[_subPage]->waypoints.size()) {
920 if(_kln89->_flightPlans[_subPage]->waypoints[n]->appType != GPS_APP_NONE) {
926 // TODO - not sure what we actually do in this condition
928 } else if(fencePos) {
931 ShowScratchpadMessage("Invald", " Add ");
933 if((_wLinePos + 1) > _entWpStr.size()) {
936 _entWpStr[_wLinePos] = _kln89->DecChar(_entWpStr[_wLinePos], (_wLinePos == 0 ? false : true));
939 _fp0SelWpId.clear(); // Waypoints don't become the DTO default whilst being entered.
942 const GPSWaypoint* wp = _kln89->FindFirstById(_entWpStr.substr(0, _wLinePos+1), multi, false);
947 _entWp = new GPSWaypoint;
948 if(_fplPos + (_uLinePos - 4) >= _kln89->_flightPlans[_subPage]->waypoints.size()) {
949 _kln89->_flightPlans[_subPage]->waypoints.push_back(_entWp);
951 _kln89->_flightPlans[_subPage]->waypoints.insert(_kln89->_flightPlans[_subPage]->waypoints.begin()+(_fplPos + (_uLinePos - 4)), _entWp);
962 void KLN89FplPage::Knob2Right1() {
969 if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) {
970 if(_kln89->_mode != KLN89_MODE_CRSR) _resetFplPos0 = true;
971 KLN89Page::Knob2Right1();
974 // Check for approach waypoints or header/fences in flightplan 0
975 int n = _fplPos + _uLinePos - 4;
977 bool fencePos = false;
979 //cout << "_fplPos = " << _fplPos << ", _uLinePos = " << _uLinePos << ", n = " << n << ", _hdrPos = " << _hdrPos << ", _fencePos = " << _fencePos << '\n';
981 //cout << "HEADER POS\n";
985 //cout << "FENCE POS\n";
988 if(_hdrPos >= 0 && n > _hdrPos) --n;
989 if(_fencePos >= 0 && n >= _fencePos) --n; // This one needs to be >= since n is already decremented by 1 in the line above!
990 //cout << "New n = " << n << '\n';
992 if(n < _kln89->_flightPlans[_subPage]->waypoints.size()) {
993 if(_kln89->_flightPlans[_subPage]->waypoints[n]->appType != GPS_APP_NONE) {
999 // TODO - not sure what we actually do in this condition
1001 } else if(fencePos) {
1004 ShowScratchpadMessage("Invald", " Add ");
1006 if((_wLinePos + 1) > _entWpStr.size()) {
1009 _entWpStr[_wLinePos] = _kln89->DecChar(_entWpStr[_wLinePos], (_wLinePos == 0 ? false : true));
1012 _fp0SelWpId.clear(); // Waypoints don't become the DTO default whilst being entered.
1015 const GPSWaypoint* wp = _kln89->FindFirstById(_entWpStr.substr(0, _wLinePos+1), multi, false);
1019 if(_entWp == NULL) {
1020 _entWp = new GPSWaypoint;
1021 if(_fplPos + (_uLinePos - 4) >= _kln89->_flightPlans[_subPage]->waypoints.size()) {
1022 _kln89->_flightPlans[_subPage]->waypoints.push_back(_entWp);
1024 _kln89->_flightPlans[_subPage]->waypoints.insert(_kln89->_flightPlans[_subPage]->waypoints.begin()+(_fplPos + (_uLinePos - 4)), _entWp);