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/compiler.h>
23 #include <simgear/structure/commands.hxx>
25 #include <Main/globals.hxx>
28 #include "ATCDialog.hxx"
31 #include "commlist.hxx"
32 #include "ATCutils.hxx"
33 #include <Airports/simple.hxx>
37 SG_USING_STD(ostringstream);
39 static void atcUppercase(string &s) {
40 for(unsigned int i=0; i<s.size(); ++i) {
45 FGATCDialog *current_atcdialog;
47 // For the command manager - maybe eventually this should go in the built in command list
48 static bool do_ATC_dialog(const SGPropertyNode* arg) {
49 globals->get_ATC_mgr()->doPopupDialog();
53 static bool do_ATC_freq_search(const SGPropertyNode* arg) {
54 current_atcdialog->FreqDialog();
58 ATCMenuEntry::ATCMenuEntry() {
65 ATCMenuEntry::~ATCMenuEntry() {
68 static char* t0 = "No communication currently available";
69 //static char* t1 = "Request departure clearance";
70 //static char* t2 = "Report Runway vacated";
71 static char** towerOptions = new char*[2];
73 // ----------------------- DCL ------------------------------------------
74 // For the ATC dialog - copied from the Autopilot new heading dialog code!
75 static puDialogBox* atcDialog;
76 static puFrame* atcDialogFrame;
77 static puText* atcDialogMessage;
78 //static puInput* atcDialogInput;
79 static puOneShot* atcDialogOkButton;
80 static puOneShot* atcDialogCancelButton;
81 static puButtonBox* atcDialogCommunicationOptions;
82 // ----------------------------------------------------------------------
84 //////////////////////////////////////////////////////
86 // STUFF FOR THE FREQUENCY SEARCH DIALOG
88 //////////////////////////////////////////////////////
90 static const int ATC_MAX_FREQ_DISPLAY = 20; // Maximum number of frequencies that can be displayed for any one airport
92 static puDialogBox* atcFreqDialog;
93 static puFrame* atcFreqDialogFrame;
94 static puText* atcFreqDialogMessage;
95 static puInput* atcFreqDialogInput;
96 static puOneShot* atcFreqDialogOkButton;
97 static puOneShot* atcFreqDialogCancelButton;
99 static puDialogBox* atcFreqDisplay;
100 static puFrame* atcFreqDisplayFrame;
101 static puText* atcFreqDisplayMessage;
102 static puOneShot* atcFreqDisplayOkButton;
103 static puText* atcFreqDisplayText[ATC_MAX_FREQ_DISPLAY];
105 static void FreqDialogCancel(puObject*) {
106 FG_POP_PUI_DIALOG(atcFreqDialog);
109 static void FreqDialogOK(puObject*) {
110 string tmp = atcFreqDialogInput->getStringValue();
111 FG_POP_PUI_DIALOG(atcFreqDialog);
112 current_atcdialog->FreqDisplay(tmp);
115 static void FreqDisplayOK(puObject*) {
116 FG_POP_PUI_DIALOG(atcFreqDisplay);
119 ////////////// end freq search statics ///////////////
121 // ------------------------ AK ------------------------------------------
122 static puDialogBox *ATCMenuBox = 0;
123 static puFrame *ATCMenuFrame = 0;
124 static puText *ATCMenuBoxMessage = 0;
125 static puButtonBox *ATCOptionsList = 0;
126 // ----------------------------------------------------------------------
129 static void AKATCDialogOK(puObject *)
131 switch(ATCOptionsList->getValue()) {
133 //cout << "Option 0 chosen\n";
134 fgSetBool("/sim/atc/opt0",true);
137 //cout << "Option 1 chosen\n";
138 fgSetBool("/sim/atc/opt1",true);
141 //cout << "Option 2 chosen\n";
142 fgSetBool("/sim/atc/opt2",true);
145 //cout << "Option 2 chosen\n";
146 fgSetBool("/sim/atc/opt3",true);
151 FG_POP_PUI_DIALOG( ATCMenuBox );
155 static void AKATCDialogCancel(puObject *)
157 FG_POP_PUI_DIALOG( ATCMenuBox );
161 static void ATCDialogCancel(puObject *)
163 //ATCDialogInput->rejectInput();
164 FG_POP_PUI_DIALOG( atcDialog );
168 static void ATCDialogOK (puObject *me)
170 // Note that currently the dialog is hardwired to comm1 only here.
171 switch(globals->get_ATC_mgr()->GetComm1ATCType()) {
178 FGTower* twr = (FGTower*)globals->get_ATC_mgr()->GetComm1ATCPointer();
179 switch(atcDialogCommunicationOptions->getValue()) {
181 //cout << "Option 0 chosen\n";
182 twr->RequestLandingClearance("charlie foxtrot sierra");
185 //cout << "Option 1 chosen\n";
186 twr->RequestDepartureClearance("charlie foxtrot sierra");
189 //cout << "Option 2 chosen\n";
190 twr->ReportRunwayVacated("charlie foxtrot sierra");
207 //if(error) mkDialog(s.c_str());
211 static void ATCDialog(puObject *cb)
213 FG_PUSH_PUI_DIALOG(atcDialog);
219 char defaultATCLabel[] = "Enter desired option to communicate with ATC:";
222 // Option lists hardwired per ATC type
223 towerOptions[0] = new char[strlen(t0)+1];
224 strcpy(towerOptions[0], t0);
225 //towerOptions[1] = new char[strlen(t1)+1];
226 //strcpy(towerOptions[1], t1);
227 //towerOptions[2] = new char[strlen(t2)+1];
228 //strcpy(towerOptions[2], t2);
229 towerOptions[1] = NULL;
231 atcDialog = new puDialogBox (150, 50);
233 atcDialogFrame = new puFrame (0, 0, 500, 250);
235 atcDialogMessage = new puText (250, 220);
236 atcDialogMessage -> setDefaultValue (defaultATCLabel);
237 atcDialogMessage -> getDefaultValue (&s);
238 atcDialogMessage -> setLabel (s);
239 atcDialogMessage -> setLabelPlace (PUPLACE_TOP_CENTERED);
241 atcDialogCommunicationOptions = new puButtonBox (50, 50, 450, 210, NULL, true);
243 atcDialogOkButton = new puOneShot (50, 10, 110, 50);
244 atcDialogOkButton -> setLegend (gui_msg_OK);
245 atcDialogOkButton -> makeReturnDefault (TRUE);
246 atcDialogOkButton -> setCallback (ATCDialogOK);
248 atcDialogCancelButton = new puOneShot (140, 10, 210, 50);
249 atcDialogCancelButton -> setLegend (gui_msg_CANCEL);
250 atcDialogCancelButton -> setCallback (ATCDialogCancel);
253 FG_FINALIZE_PUI_DIALOG(atcDialog);
255 // Add ATC-dialog to the command list
256 globals->get_commands()->addCommand("ATC-dialog", do_ATC_dialog);
259 ///////////////////////////////////////////////////////////////////////
261 // ATCDoDialog is in a state of flux at the moment
262 // Stations other than approach are handled by DCL's simple code
263 // Approach is handled by AK's fancy dynamic-list code
264 // Hopefully all interactive stations should go to AK's code eventually
266 ///////////////////////////////////////////////////////////////////////
267 void ATCDoDialog(atc_type type) {
270 atcDialogCommunicationOptions->newList(NULL);
271 atcDialogMessage->setLabel("Not tuned in to any ATC service.");
274 atcDialogCommunicationOptions->newList(NULL);
275 atcDialogMessage->setLabel("Tuned in to ATIS: no communication possible.");
278 atcDialogCommunicationOptions->newList(towerOptions);
279 atcDialogMessage->setLabel("Tuned in to Tower - select communication to transmit:");
282 atcDialogCommunicationOptions->newList(NULL);
283 atcDialogMessage->setLabel("Tuned in to Ground - select communication to transmit:");
286 current_atcdialog->DoDialog();
289 atcDialogCommunicationOptions->newList(NULL);
290 atcDialogMessage->setLabel("Tuned in to unknown ATC service - enter transmission:");
294 // Third - display the dialog without pausing sim.
295 if(type != APPROACH) {
300 FGATCDialog::FGATCDialog() {
303 FGATCDialog::~FGATCDialog() {
304 if(atcFreqDialog) puDeleteObject(atcFreqDialog);
305 if(atcFreqDisplay) puDeleteObject(atcFreqDisplay);
306 if(ATCMenuBox) puDeleteObject(ATCMenuBox);
309 void FGATCDialog::Init() {
310 // Add ATC-freq-search to the command list
311 globals->get_commands()->addCommand("ATC-freq-search", do_ATC_freq_search);
318 // Init the freq-search dialog
321 x = (fgGetInt("/sim/startup/xsize") / 2) - (w / 2);
324 atcFreqDialog = new puDialogBox (x, y);
326 atcFreqDialogFrame = new puFrame (0, 0, w, h);
327 atcFreqDialogMessage = new puText (40, (h - 30));
328 atcFreqDialogMessage->setDefaultValue ("Enter airport identifier:");
329 atcFreqDialogMessage->getDefaultValue (&s);
330 atcFreqDialogMessage->setLabel(s);
332 atcFreqDialogInput = new puInput (50, (h - 75), 150, (h - 45));
334 atcFreqDialogOkButton = new puOneShot (50, 10, 110, 50);
335 atcFreqDialogOkButton -> setLegend (gui_msg_OK);
336 atcFreqDialogOkButton -> makeReturnDefault (TRUE);
337 atcFreqDialogOkButton -> setCallback (FreqDialogOK);
339 atcFreqDialogCancelButton = new puOneShot (140, 10, 210, 50);
340 atcFreqDialogCancelButton -> setLegend (gui_msg_CANCEL);
341 atcFreqDialogCancelButton -> setCallback (FreqDialogCancel);
343 atcFreqDialogInput->acceptInput();
346 FG_FINALIZE_PUI_DIALOG(atcFreqDialog);
348 // Init the freq-display dialog
351 x = (fgGetInt("/sim/startup/xsize") / 2) - (w / 2);
353 atcFreqDisplay = new puDialogBox (x, y);
355 atcFreqDisplayFrame = new puFrame (0, 0, w, h);
357 atcFreqDisplayMessage = new puText (40, (h - 30));
358 atcFreqDisplayMessage -> setDefaultValue ("No freqencies found");
359 atcFreqDisplayMessage -> getDefaultValue (&s);
360 atcFreqDisplayMessage -> setLabel (s);
362 for(int i=0; i<ATC_MAX_FREQ_DISPLAY; ++i) {
363 atcFreqDisplayText[i] = new puText(40, h - 65 - (30 * i));
364 atcFreqDisplayText[i]->setDefaultValue("");
365 atcFreqDisplayText[i]-> getDefaultValue (&s);
366 atcFreqDisplayText[i]-> setLabel (s);
367 atcFreqDisplayText[i]->hide();
370 atcFreqDisplayOkButton = new puOneShot (50, 10, 110, 50);
371 atcFreqDisplayOkButton -> setLegend (gui_msg_OK);
372 atcFreqDisplayOkButton -> makeReturnDefault (TRUE);
373 atcFreqDisplayOkButton -> setCallback (FreqDisplayOK);
375 FG_FINALIZE_PUI_DIALOG(atcFreqDisplay);
377 // Init AK's interactive ATC menus
380 x = (fgGetInt("/sim/startup/xsize") / 2) - (w / 2);
381 //y = (fgGetInt("/sim/startup/ysize") / 2) - (h / 2);
383 ATCMenuBox = new puDialogBox (x, y);
385 ATCMenuFrame = new puFrame (0,0,w,h);
386 ATCMenuBoxMessage = new puText (w / 2, h - 30);
387 ATCMenuBoxMessage -> setLabel( "No transmission available" );
388 ATCMenuBoxMessage -> setLabelPlace(PUPLACE_TOP_CENTERED);
389 ATCOptionsList = new puButtonBox (50, 60, 450, 50, NULL, true);
390 ATCOptionsList -> hide();
391 atcDialogOkButton = new puOneShot ((w/2)-85, 10, (w/2)-25, 50);
392 atcDialogOkButton -> setLegend (gui_msg_OK);
393 atcDialogOkButton -> makeReturnDefault (TRUE);
394 atcDialogOkButton -> setCallback (AKATCDialogOK);
396 atcDialogCancelButton = new puOneShot ((w/2)+25, 10, (w/2)+85, 50);
397 atcDialogCancelButton -> setLegend (gui_msg_CANCEL);
398 atcDialogCancelButton -> setCallback (AKATCDialogCancel);
400 FG_FINALIZE_PUI_DIALOG(ATCMenuBox);
405 void FGATCDialog::add_entry(string station, string transmission, string menutext ) {
409 a.stationid = station;
410 a.transmission = transmission;
411 a.menuentry = menutext;
413 atcmentrylist_station[station.c_str()].push_back(a);
418 // query the database whether the transmission is already registered;
419 bool FGATCDialog::trans_reg( const string &station, const string &trans ) {
421 atcmentry_list_type atcmlist = atcmentrylist_station[station];
422 atcmentry_list_iterator current = atcmlist.begin();
423 atcmentry_list_iterator last = atcmlist.end();
425 for ( ; current != last ; ++current ) {
426 if ( current->transmission == trans ) return true;
432 // ===================================================
433 // === Update ATC menue and look for keys pressed ===
434 // ===================================================
435 void FGATCDialog::DoDialog() {
437 static string mentry[10];
438 static string mtrans[10];
441 FGATC* atcptr = globals->get_ATC_mgr()->GetComm1ATCPointer(); // Hardwired to comm1 at the moment
445 atcmentry_list_type atcmlist = atcmentrylist_station[atcptr->get_ident()];
446 //atcmentry_list_type atcmlist = atcmentrylist_station["EGNX"];
447 atcmentry_list_iterator current = atcmlist.begin();
448 atcmentry_list_iterator last = atcmlist.end();
450 // Set all opt flags to false before displaying box
451 fgSetBool("/sim/atc/opt0",false);
452 fgSetBool("/sim/atc/opt1",false);
453 fgSetBool("/sim/atc/opt2",false);
454 fgSetBool("/sim/atc/opt3",false);
455 fgSetBool("/sim/atc/opt4",false);
456 fgSetBool("/sim/atc/opt5",false);
457 fgSetBool("/sim/atc/opt6",false);
458 fgSetBool("/sim/atc/opt7",false);
459 fgSetBool("/sim/atc/opt8",false);
460 fgSetBool("/sim/atc/opt9",false);
463 int k = atcmlist.size();
464 int h = 110 + k * 25;
465 //cout << "k = " << k << '\n';
467 ATCMenuFrame->setSize(w, h);
470 // loop over all entries in atcmentrylist
471 char** optList = new char*[k+1];
473 for ( ; current != last ; ++current ) {
475 sprintf( buf, "%i", kk+1 );
478 mentry[kk] = dum + ". " + current->menuentry;
479 optList[kk] = new char[strlen(mentry[kk].c_str()) + 1];
480 strcpy(optList[kk], mentry[kk].c_str());
481 //cout << "optList[" << kk << "] = " << optList[kk] << endl;
482 mtrans[kk] = current->transmission;
486 ATCOptionsList->newList(optList);
487 ATCOptionsList->setSize(w-100, h-100);
488 ATCOptionsList->reveal();
489 ATCMenuBoxMessage -> setLabel( "ATC Menu" );
490 ATCMenuBoxMessage -> setPosition(w / 2, h - 30);
492 ATCOptionsList->hide();
493 ATCMenuBoxMessage -> setLabel( "No transmission available" );
494 ATCMenuBoxMessage -> setPosition(w / 2, h - 20);
497 FG_PUSH_PUI_DIALOG( ATCMenuBox );
500 if ( atckey != -1 && TransDisplayed && mtrans[atckey-1].c_str() != "" ) {
501 cout << mtrans[atckey-1].c_str() << endl;
502 TPar = current_transmissionlist->extract_transpar( mtrans[atckey-1].c_str() );
503 current_atcmentrylist->reset = true;
504 current_transparlist->add_entry( TPar );
506 // transpar_list_type test = current_transparlist;
507 // transpar_list_iterator current = test.begin();
508 //for ( ; current != test.end(); ++current ) {
509 // current->tpar.intention;
513 if ( current_atcmentrylist->freq != (int)(comm1_freq*100.0 + 0.5) ) {
514 current_atcmentrylist->reset = true;
517 // reset (delete) ATCmenue list if reset is true
518 if ( current_atcmentrylist->reset == true ) {
519 delete ( current_atcmentrylist );
520 current_atcmentrylist = new FGatcmentryList;
521 current_atcmentrylist->init( (int)(comm1_freq*100.0 + 0.5) );
522 if ( TransDisplayed ) {
523 FG_POP_PUI_DIALOG( ATCMenuBox );
524 TransDisplayed = false;
533 void FGATCDialog::FreqDialog() {
535 // Find the ATC stations within a reasonable range (about 40 miles?)
536 //comm_list_type atc_stations;
537 //comm_list_iterator atc_stat_itr;
539 //double lon = fgGetDouble("/position/longitude-deg");
540 //double lat = fgGetDouble("/position/latitude-deg");
541 //double elev = fgGetDouble("/position/altitude-ft");
544 // search stations in range
545 int num_stat = current_commlist->FindByPos(lon, lat, elev, 40.0, &atc_stations);
548 // Make up a message saying no things in range
552 // TODO - it would be nice to display a drop-down list of airports within the general vicinity of the user
553 // in addition to the general input box (started above).
555 atcFreqDialogInput->setValue("");
556 atcFreqDialogInput->acceptInput();
557 FG_PUSH_PUI_DIALOG(atcFreqDialog);
560 void FGATCDialog::FreqDisplay(string ident) {
567 int n = 0; // Number of ATC frequencies at this airport
568 string freqs[ATC_MAX_FREQ_DISPLAY];
572 if ( dclFindAirportID( ident, &a ) ) {
573 comm_list_type stations;
574 int found = current_commlist->FindByPos(a.longitude, a.latitude, a.elevation, 20.0, &stations);
577 comm_list_iterator itr = stations.begin();
578 while(itr != stations.end()) {
579 if((*itr).ident == ident) {
580 if((*itr).type != INVALID) {
582 freqs[n] = ostr.str();
583 freqs[n].append(" - ");
584 sprintf(buf, "%.2f", ((*itr).freq / 100.0)); // Convert from KHz to MHz
586 if(buf[5] == '3') buf[5] = '2';
587 if(buf[5] == '8') buf[5] = '7';
597 label = "No frequencies found for airport ";
600 label = "Frequencies for airport ";
607 label += " not found in database.";
610 int hsize = 105 + (n * 30);
612 atcFreqDisplayFrame->setSize(400, hsize);
614 atcFreqDisplayMessage -> setPosition (40, (hsize - 30));
615 atcFreqDisplayMessage -> setValue (label.c_str());
616 atcFreqDisplayMessage -> getValue (&s);
617 atcFreqDisplayMessage -> setLabel (s);
619 for(int i=0; i<n; ++i) {
620 atcFreqDisplayText[i] -> setPosition(40, hsize - 65 - (30 * i));
621 atcFreqDisplayText[i] -> setValue(freqs[i].c_str());
622 atcFreqDisplayText[i] -> getValue (&s);
623 atcFreqDisplayText[i] -> setLabel (s);
624 atcFreqDisplayText[i] -> reveal();
626 for(int j=n; j<ATC_MAX_FREQ_DISPLAY; ++j) {
627 atcFreqDisplayText[j] -> hide();
630 FG_PUSH_PUI_DIALOG(atcFreqDisplay);