1 // ATCDialog.cxx - Functions and classes to handle the pop-up ATC dialog
3 // Written by Alexander Kappes and David Luff, started February 2003.
5 // Copyright (C) 2003 Alexander Kappes and David Luff
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include <simgear/structure/commands.hxx>
23 #include <Main/globals.hxx>
26 #include "ATCDialog.hxx"
29 #include "commlist.hxx"
30 #include "ATCutils.hxx"
31 #include <Airports/simple.hxx>
33 FGATCDialog *current_atcdialog;
35 // For the command manager - maybe eventually this should go in the built in command list
36 static bool do_ATC_dialog(const SGPropertyNode* arg) {
37 globals->get_ATC_mgr()->doPopupDialog();
41 static bool do_ATC_freq_search(const SGPropertyNode* arg) {
42 current_atcdialog->FreqDialog();
46 ATCMenuEntry::ATCMenuEntry() {
53 ATCMenuEntry::~ATCMenuEntry() {
56 static char* t0 = "No communication currently available";
57 //static char* t1 = "Request departure clearance";
58 //static char* t2 = "Report Runway vacated";
59 static char** towerOptions = new char*[2];
61 // ----------------------- DCL ------------------------------------------
62 // For the ATC dialog - copied from the Autopilot new heading dialog code!
63 static puDialogBox* atcDialog;
64 static puFrame* atcDialogFrame;
65 static puText* atcDialogMessage;
66 //static puInput* atcDialogInput;
67 static puOneShot* atcDialogOkButton;
68 static puOneShot* atcDialogCancelButton;
69 static puButtonBox* atcDialogCommunicationOptions;
70 // ----------------------------------------------------------------------
72 // ------------------------ AK ------------------------------------------
73 static puDialogBox *ATCMenuBox = 0;
74 static puFrame *ATCMenuFrame = 0;
75 static puText *ATCMenuBoxMessage = 0;
76 static puButtonBox *ATCOptionsList = 0;
77 // ----------------------------------------------------------------------
80 static void AKATCDialogOK(puObject *)
82 switch(ATCOptionsList->getValue()) {
84 //cout << "Option 0 chosen\n";
85 fgSetBool("/sim/atc/opt0",true);
88 //cout << "Option 1 chosen\n";
89 fgSetBool("/sim/atc/opt1",true);
92 //cout << "Option 2 chosen\n";
93 fgSetBool("/sim/atc/opt2",true);
96 //cout << "Option 2 chosen\n";
97 fgSetBool("/sim/atc/opt3",true);
102 FG_POP_PUI_DIALOG( ATCMenuBox );
106 static void AKATCDialogCancel(puObject *)
108 FG_POP_PUI_DIALOG( ATCMenuBox );
112 static void ATCDialogCancel(puObject *)
114 //ATCDialogInput->rejectInput();
115 FG_POP_PUI_DIALOG( atcDialog );
119 static void ATCDialogOK (puObject *me)
121 // Note that currently the dialog is hardwired to comm1 only here.
122 switch(globals->get_ATC_mgr()->GetComm1ATCType()) {
129 FGTower* twr = (FGTower*)globals->get_ATC_mgr()->GetComm1ATCPointer();
130 switch(atcDialogCommunicationOptions->getValue()) {
132 //cout << "Option 0 chosen\n";
133 twr->RequestLandingClearance("charlie foxtrot sierra");
136 //cout << "Option 1 chosen\n";
137 twr->RequestDepartureClearance("charlie foxtrot sierra");
140 //cout << "Option 2 chosen\n";
141 twr->ReportRunwayVacated("charlie foxtrot sierra");
158 //if(error) mkDialog(s.c_str());
162 static void ATCDialog(puObject *cb)
164 //ApHeadingDialogInput -> setValue ( heading );
165 //ApHeadingDialogInput -> acceptInput();
166 FG_PUSH_PUI_DIALOG(atcDialog);
172 char defaultATCLabel[] = "Enter desired option to communicate with ATC:";
175 // Option lists hardwired per ATC type
176 towerOptions[0] = new char[strlen(t0)+1];
177 strcpy(towerOptions[0], t0);
178 //towerOptions[1] = new char[strlen(t1)+1];
179 //strcpy(towerOptions[1], t1);
180 //towerOptions[2] = new char[strlen(t2)+1];
181 //strcpy(towerOptions[2], t2);
182 towerOptions[1] = NULL;
184 atcDialog = new puDialogBox (150, 50);
186 atcDialogFrame = new puFrame (0, 0, 500, 250);
188 atcDialogMessage = new puText (250, 220);
189 atcDialogMessage -> setDefaultValue (defaultATCLabel);
190 atcDialogMessage -> getDefaultValue (&s);
191 atcDialogMessage -> setLabel (s);
192 atcDialogMessage -> setLabelPlace (PUPLACE_TOP_CENTERED);
194 atcDialogCommunicationOptions = new puButtonBox (50, 50, 450, 210, NULL, true);
196 atcDialogOkButton = new puOneShot (50, 10, 110, 50);
197 atcDialogOkButton -> setLegend (gui_msg_OK);
198 atcDialogOkButton -> makeReturnDefault (TRUE);
199 atcDialogOkButton -> setCallback (ATCDialogOK);
201 atcDialogCancelButton = new puOneShot (140, 10, 210, 50);
202 atcDialogCancelButton -> setLegend (gui_msg_CANCEL);
203 atcDialogCancelButton -> setCallback (ATCDialogCancel);
206 FG_FINALIZE_PUI_DIALOG(atcDialog);
208 // Add ATC-dialog to the command list
209 globals->get_commands()->addCommand("ATC-dialog", do_ATC_dialog);
212 ///////////////////////////////////////////////////////////////////////
214 // ATCDoDialog is in a state of flux at the moment
215 // Stations other than approach are handled by DCL's simple code
216 // Approach is handled by AK's fancy dynamic-list code
217 // Hopefully all interactive stations should go to AK's code eventually
219 ///////////////////////////////////////////////////////////////////////
220 void ATCDoDialog(atc_type type) {
223 atcDialogCommunicationOptions->newList(NULL);
224 atcDialogMessage->setLabel("Not tuned in to any ATC service.");
227 atcDialogCommunicationOptions->newList(NULL);
228 atcDialogMessage->setLabel("Tuned in to ATIS: no communication possible.");
231 atcDialogCommunicationOptions->newList(towerOptions);
232 atcDialogMessage->setLabel("Tuned in to Tower - select communication to transmit:");
235 atcDialogCommunicationOptions->newList(NULL);
236 atcDialogMessage->setLabel("Tuned in to Ground - select communication to transmit:");
239 current_atcdialog->DoDialog();
242 atcDialogCommunicationOptions->newList(NULL);
243 atcDialogMessage->setLabel("Tuned in to unknown ATC service - enter transmission:");
247 // Third - display the dialog without pausing sim.
248 if(type != APPROACH) {
253 void FGATCDialog::Init() {
254 // Add ATC-freq-search to the command list
255 globals->get_commands()->addCommand("ATC-freq-search", do_ATC_freq_search);
260 void FGATCDialog::add_entry(string station, string transmission, string menutext ) {
264 a.stationid = station;
265 a.transmission = transmission;
266 a.menuentry = menutext;
268 atcmentrylist_station[station.c_str()].push_back(a);
273 // query the database whether the transmission is already registered;
274 bool FGATCDialog::trans_reg( const string &station, const string &trans ) {
276 atcmentry_list_type atcmlist = atcmentrylist_station[station];
277 atcmentry_list_iterator current = atcmlist.begin();
278 atcmentry_list_iterator last = atcmlist.end();
280 for ( ; current != last ; ++current ) {
281 if ( current->transmission == trans ) return true;
287 // ===================================================
288 // === Update ATC menue and look for keys pressed ===
289 // ===================================================
290 void FGATCDialog::DoDialog() {
292 static string mentry[10];
293 static string mtrans[10];
296 FGATC* atcptr = globals->get_ATC_mgr()->GetComm1ATCPointer(); // Hardwired to comm1 at the moment
300 atcmentry_list_type atcmlist = atcmentrylist_station[atcptr->get_ident()];
301 //atcmentry_list_type atcmlist = atcmentrylist_station["EGNX"];
302 atcmentry_list_iterator current = atcmlist.begin();
303 atcmentry_list_iterator last = atcmlist.end();
305 // Set all opt flags to false before displaying box
306 fgSetBool("/sim/atc/opt0",false);
307 fgSetBool("/sim/atc/opt1",false);
308 fgSetBool("/sim/atc/opt2",false);
309 fgSetBool("/sim/atc/opt3",false);
310 fgSetBool("/sim/atc/opt4",false);
311 fgSetBool("/sim/atc/opt5",false);
312 fgSetBool("/sim/atc/opt6",false);
313 fgSetBool("/sim/atc/opt7",false);
314 fgSetBool("/sim/atc/opt8",false);
315 fgSetBool("/sim/atc/opt9",false);
321 if ( atcmlist.size() != 0 ){
322 int k=atcmlist.size();
324 //cout << "k = " << k << endl;
325 int y = (fgGetInt("/sim/startup/ysize") - 200 - 20 - k*20);
326 ATCMenuBox = new puDialogBox (100, y);
327 ATCMenuFrame = new puFrame (0,0,xsize,yc+40);
328 // loop over all entries in atcmentrylist
329 ATCOptionsList = new puButtonBox (50, 50, 450, 50+(k*25), NULL, true);
330 char** optList = new char*[k+1];
332 for ( ; current != last ; ++current ) {
334 sprintf( buf, "%i", kk+1 );
337 mentry[kk] = dum + ". " + current->menuentry;
338 optList[kk] = new char[strlen(mentry[kk].c_str()) + 1];
339 strcpy(optList[kk], mentry[kk].c_str());
340 //cout << "optList[" << kk << "] = " << optList[kk] << endl;
341 mtrans[kk] = current->transmission;
342 //ATCMenuBoxMessage = new puText (10, yc);
343 //ATCMenuBoxMessage -> setLabel( mentry[kk].c_str() );
349 ATCOptionsList->newList(optList);
351 int y = (fgGetInt("/sim/startup/ysize") - 100 - 20 );
352 ATCMenuBox = new puDialogBox (10, y);
353 ATCMenuFrame = new puFrame (0,0,xsize,yc+40);
354 ATCMenuBoxMessage = new puText (10, yc-10);
355 ATCMenuBoxMessage -> setLabel( "No transmission available" );
358 ATCMenuBoxMessage = new puText (10, yc+10);
359 ATCMenuBoxMessage -> setLabel( "ATC Menu" );
360 atcDialogOkButton = new puOneShot ((xsize/2)-85, 10, (xsize/2)-25, 50);
361 atcDialogOkButton -> setLegend (gui_msg_OK);
362 atcDialogOkButton -> makeReturnDefault (TRUE);
363 atcDialogOkButton -> setCallback (AKATCDialogOK);
365 atcDialogCancelButton = new puOneShot ((xsize/2)+25, 10, (xsize/2)+85, 50);
366 atcDialogCancelButton -> setLegend (gui_msg_CANCEL);
367 atcDialogCancelButton -> setCallback (AKATCDialogCancel);
368 FG_FINALIZE_PUI_DIALOG( ATCMenuBox );
369 FG_PUSH_PUI_DIALOG( ATCMenuBox );
373 if ( atckey != -1 && TransDisplayed && mtrans[atckey-1].c_str() != "" ) {
374 cout << mtrans[atckey-1].c_str() << endl;
375 TPar = current_transmissionlist->extract_transpar( mtrans[atckey-1].c_str() );
376 current_atcmentrylist->reset = true;
377 current_transparlist->add_entry( TPar );
379 // transpar_list_type test = current_transparlist;
380 // transpar_list_iterator current = test.begin();
381 //for ( ; current != test.end(); ++current ) {
382 // current->tpar.intention;
386 if ( current_atcmentrylist->freq != (int)(comm1_freq*100.0 + 0.5) ) {
387 current_atcmentrylist->reset = true;
390 // reset (delete) ATCmenue list if reset is true
391 if ( current_atcmentrylist->reset == true ) {
392 delete ( current_atcmentrylist );
393 current_atcmentrylist = new FGatcmentryList;
394 current_atcmentrylist->init( (int)(comm1_freq*100.0 + 0.5) );
395 if ( TransDisplayed ) {
396 FG_POP_PUI_DIALOG( ATCMenuBox );
397 TransDisplayed = false;
404 //////////////////////////////////////////////////////
406 // STUFF FOR THE FREQUENCY SEARCH DIALOG
408 //////////////////////////////////////////////////////
410 static puDialogBox* atcFreqDialog;
411 static puFrame* atcFreqDialogFrame;
412 static puText* atcFreqDialogMessage;
413 static puInput* atcFreqDialogInput;
414 static puOneShot* atcFreqDialogOkButton;
415 static puOneShot* atcFreqDialogCancelButton;
416 //static puButtonBox* atcFreqDialogCommunicationOptions;
418 static puText* atcFreqDisplayText[20];
420 static void FreqDialogCancel(puObject*) {
421 FG_POP_PUI_DIALOG(atcFreqDialog);
422 delete atcFreqDialog;
425 static void FreqDialogOK(puObject*) {
426 string tmp = atcFreqDialogInput->getStringValue();
427 FG_POP_PUI_DIALOG(atcFreqDialog);
428 delete atcFreqDialog;
429 current_atcdialog->FreqDisplay(tmp);
432 static void FreqDisplayOK(puObject*) {
433 FG_POP_PUI_DIALOG(atcFreqDialog);
434 delete atcFreqDialog;
437 void FGATCDialog::FreqDialog() {
439 // Find the ATC stations within a reasonable range (about 40 miles?)
440 //comm_list_type atc_stations;
441 //comm_list_iterator atc_stat_itr;
443 //double lon = fgGetDouble("/position/longitude-deg");
444 //double lat = fgGetDouble("/position/latitude-deg");
445 //double elev = fgGetDouble("/position/altitude-ft");
448 // search stations in range
449 int num_stat = current_commlist->FindByPos(lon, lat, elev, 40.0, &atc_stations);
452 // Make up a message saying no things in range
456 //char defaultATCLabel[] = "Enter desired option to communicate with ATC:";
460 atcFreqDialog = new puDialogBox (150, 50);
462 atcFreqDialogFrame = new puFrame (0, 0, 300, hsize);
464 atcFreqDialogMessage = new puText (40, (hsize - 30));
465 atcFreqDialogMessage -> setDefaultValue ("Enter airport identifier:");
466 atcFreqDialogMessage -> getDefaultValue (&s);
467 atcFreqDialogMessage -> setLabel (s);
468 //atcFreqDialogMessage -> setLabelPlace (PUPLACE_TOP_CENTERED);
469 //atcFreqDialogMessage -> setLabelPlace (0);
471 atcFreqDialogInput = new puInput (50, (hsize - 75), 150, (hsize - 45));
472 atcFreqDialogInput->acceptInput();
474 atcFreqDialogOkButton = new puOneShot (50, 10, 110, 50);
475 atcFreqDialogOkButton -> setLegend (gui_msg_OK);
476 atcFreqDialogOkButton -> makeReturnDefault (TRUE);
477 atcFreqDialogOkButton -> setCallback (FreqDialogOK);
479 atcFreqDialogCancelButton = new puOneShot (140, 10, 210, 50);
480 atcFreqDialogCancelButton -> setLegend (gui_msg_CANCEL);
481 atcFreqDialogCancelButton -> setCallback (FreqDialogCancel);
484 FG_FINALIZE_PUI_DIALOG(atcFreqDialog);
486 FG_PUSH_PUI_DIALOG(atcFreqDialog);
490 static void atcUppercase(string &s)
492 for(unsigned int i=0; i<s.size(); ++i) {
493 s[i] = toupper(s[i]);
497 void FGATCDialog::FreqDisplay(string ident) {
499 // Find the ATC stations within a reasonable range (about 40 miles?)
500 //comm_list_type atc_stations;
501 //comm_list_iterator atc_stat_itr;
503 //double lon = fgGetDouble("/position/longitude-deg");
504 //double lat = fgGetDouble("/position/latitude-deg");
505 //double elev = fgGetDouble("/position/altitude-ft");
508 // search stations in range
509 int num_stat = current_commlist->FindByPos(lon, lat, elev, 40.0, &atc_stations);
512 // Make up a message saying no things in range
518 //char defaultATCLabel[] = "Enter desired option to communicate with ATC:";
519 string label = "Frequencies for airport ";
524 int n = 0; // Number of ATC frequencies at this airport
529 if ( dclFindAirportID( ident, &a ) ) {
530 comm_list_type stations;
531 int found = current_commlist->FindByPos(a.longitude, a.latitude, a.elevation, 20.0, &stations);
533 comm_list_iterator itr = stations.begin();
534 while(itr != stations.end()) {
535 if((*itr).ident == ident) {
536 switch((*itr).type) {
538 freqs[n] = "ATIS - ";
539 sprintf(buf, "%.2f", ((*itr).freq / 100.0)); // Convert from KHz to MHz
541 if(buf[5] == '3') buf[5] = '2';
542 if(buf[5] == '8') buf[5] = '7';
548 freqs[n] = "TOWER - ";
549 sprintf(buf, "%.2f", ((*itr).freq / 100.0)); // Convert from KHz to MHz
551 if(buf[5] == '3') buf[5] = '2';
552 if(buf[5] == '8') buf[5] = '7';
558 freqs[n] = "GROUND - ";
559 sprintf(buf, "%.2f", ((*itr).freq / 100.0)); // Convert from KHz to MHz
561 if(buf[5] == '3') buf[5] = '2';
562 if(buf[5] == '8') buf[5] = '7';
565 //cout << "GROUND\n";
568 freqs[n] = "APPROACH - ";
569 sprintf(buf, "%.2f", ((*itr).freq / 100.0)); // Convert from KHz to MHz
571 if(buf[5] == '3') buf[5] = '2';
572 if(buf[5] == '8') buf[5] = '7';
575 //cout << "APPROACH\n";
578 freqs[n] = "DEPARTURE - ";
579 sprintf(buf, "%.2f", ((*itr).freq / 100.0)); // Convert from KHz to MHz
581 if(buf[5] == '3') buf[5] = '2';
582 if(buf[5] == '8') buf[5] = '7';
585 //cout << "DEPARTURE\n";
587 case ENROUTE: // not really associated with an airport possibly.
588 freqs[n] = "ENROUTE - ";
589 sprintf(buf, "%.2f", ((*itr).freq / 100.0)); // Convert from KHz to MHz
591 if(buf[5] == '3') buf[5] = '2';
592 if(buf[5] == '8') buf[5] = '7';
595 //cout << "ENROUTE\n";
597 case INVALID: // need to include this to stop the compiler complaining.
607 label += " not found in database.";
612 label = "No frequencies found for airport ";
616 int hsize = (n < 0 ? 100 : 105 + (n * 30));
617 atcFreqDialog = new puDialogBox (250, 50);
619 atcFreqDialogFrame = new puFrame (0, 0, 400, hsize);
621 atcFreqDialogMessage = new puText (40, (hsize - 30));
622 atcFreqDialogMessage -> setDefaultValue (label.c_str());
623 atcFreqDialogMessage -> getDefaultValue (&s);
624 atcFreqDialogMessage -> setLabel (s);
626 for(int i=0; i<n; ++i) {
627 atcFreqDisplayText[i] = new puText(40, hsize - 65 - (30 * i));
628 atcFreqDisplayText[i]->setDefaultValue(freqs[i].c_str());
629 atcFreqDisplayText[i]-> getDefaultValue (&s);
630 atcFreqDisplayText[i]-> setLabel (s);
633 atcFreqDialogOkButton = new puOneShot (50, 10, 110, 50);
634 atcFreqDialogOkButton -> setLegend (gui_msg_OK);
635 atcFreqDialogOkButton -> makeReturnDefault (TRUE);
636 atcFreqDialogOkButton -> setCallback (FreqDisplayOK);
638 atcFreqDialogCancelButton = new puOneShot (140, 10, 210, 50);
639 atcFreqDialogCancelButton -> setLegend (gui_msg_CANCEL);
640 atcFreqDialogCancelButton -> setCallback (FreqDialogCancel);
643 FG_FINALIZE_PUI_DIALOG(atcFreqDialog);
645 FG_PUSH_PUI_DIALOG(atcFreqDialog);