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 FGATCDialog *current_atcdialog;
41 // For the command manager - maybe eventually this should go in the built in command list
42 static bool do_ATC_dialog(const SGPropertyNode* arg) {
43 globals->get_ATC_mgr()->doPopupDialog();
47 static bool do_ATC_freq_search(const SGPropertyNode* arg) {
48 current_atcdialog->FreqDialog();
52 ATCMenuEntry::ATCMenuEntry() {
59 ATCMenuEntry::~ATCMenuEntry() {
62 static char* t0 = "No communication currently available";
63 //static char* t1 = "Request departure clearance";
64 //static char* t2 = "Report Runway vacated";
65 static char** towerOptions = new char*[2];
67 // ----------------------- DCL ------------------------------------------
68 // For the ATC dialog - copied from the Autopilot new heading dialog code!
69 static puDialogBox* atcDialog;
70 static puFrame* atcDialogFrame;
71 static puText* atcDialogMessage;
72 //static puInput* atcDialogInput;
73 static puOneShot* atcDialogOkButton;
74 static puOneShot* atcDialogCancelButton;
75 static puButtonBox* atcDialogCommunicationOptions;
76 // ----------------------------------------------------------------------
78 // ------------------------ AK ------------------------------------------
79 static puDialogBox *ATCMenuBox = 0;
80 static puFrame *ATCMenuFrame = 0;
81 static puText *ATCMenuBoxMessage = 0;
82 static puButtonBox *ATCOptionsList = 0;
83 // ----------------------------------------------------------------------
86 static void AKATCDialogOK(puObject *)
88 switch(ATCOptionsList->getValue()) {
90 //cout << "Option 0 chosen\n";
91 fgSetBool("/sim/atc/opt0",true);
94 //cout << "Option 1 chosen\n";
95 fgSetBool("/sim/atc/opt1",true);
98 //cout << "Option 2 chosen\n";
99 fgSetBool("/sim/atc/opt2",true);
102 //cout << "Option 2 chosen\n";
103 fgSetBool("/sim/atc/opt3",true);
108 FG_POP_PUI_DIALOG( ATCMenuBox );
112 static void AKATCDialogCancel(puObject *)
114 FG_POP_PUI_DIALOG( ATCMenuBox );
118 static void ATCDialogCancel(puObject *)
120 //ATCDialogInput->rejectInput();
121 FG_POP_PUI_DIALOG( atcDialog );
125 static void ATCDialogOK (puObject *me)
127 // Note that currently the dialog is hardwired to comm1 only here.
128 switch(globals->get_ATC_mgr()->GetComm1ATCType()) {
135 FGTower* twr = (FGTower*)globals->get_ATC_mgr()->GetComm1ATCPointer();
136 switch(atcDialogCommunicationOptions->getValue()) {
138 //cout << "Option 0 chosen\n";
139 twr->RequestLandingClearance("charlie foxtrot sierra");
142 //cout << "Option 1 chosen\n";
143 twr->RequestDepartureClearance("charlie foxtrot sierra");
146 //cout << "Option 2 chosen\n";
147 twr->ReportRunwayVacated("charlie foxtrot sierra");
164 //if(error) mkDialog(s.c_str());
168 static void ATCDialog(puObject *cb)
170 //ApHeadingDialogInput -> setValue ( heading );
171 //ApHeadingDialogInput -> acceptInput();
172 FG_PUSH_PUI_DIALOG(atcDialog);
178 char defaultATCLabel[] = "Enter desired option to communicate with ATC:";
181 // Option lists hardwired per ATC type
182 towerOptions[0] = new char[strlen(t0)+1];
183 strcpy(towerOptions[0], t0);
184 //towerOptions[1] = new char[strlen(t1)+1];
185 //strcpy(towerOptions[1], t1);
186 //towerOptions[2] = new char[strlen(t2)+1];
187 //strcpy(towerOptions[2], t2);
188 towerOptions[1] = NULL;
190 atcDialog = new puDialogBox (150, 50);
192 atcDialogFrame = new puFrame (0, 0, 500, 250);
194 atcDialogMessage = new puText (250, 220);
195 atcDialogMessage -> setDefaultValue (defaultATCLabel);
196 atcDialogMessage -> getDefaultValue (&s);
197 atcDialogMessage -> setLabel (s);
198 atcDialogMessage -> setLabelPlace (PUPLACE_TOP_CENTERED);
200 atcDialogCommunicationOptions = new puButtonBox (50, 50, 450, 210, NULL, true);
202 atcDialogOkButton = new puOneShot (50, 10, 110, 50);
203 atcDialogOkButton -> setLegend (gui_msg_OK);
204 atcDialogOkButton -> makeReturnDefault (TRUE);
205 atcDialogOkButton -> setCallback (ATCDialogOK);
207 atcDialogCancelButton = new puOneShot (140, 10, 210, 50);
208 atcDialogCancelButton -> setLegend (gui_msg_CANCEL);
209 atcDialogCancelButton -> setCallback (ATCDialogCancel);
212 FG_FINALIZE_PUI_DIALOG(atcDialog);
214 // Add ATC-dialog to the command list
215 globals->get_commands()->addCommand("ATC-dialog", do_ATC_dialog);
218 ///////////////////////////////////////////////////////////////////////
220 // ATCDoDialog is in a state of flux at the moment
221 // Stations other than approach are handled by DCL's simple code
222 // Approach is handled by AK's fancy dynamic-list code
223 // Hopefully all interactive stations should go to AK's code eventually
225 ///////////////////////////////////////////////////////////////////////
226 void ATCDoDialog(atc_type type) {
229 atcDialogCommunicationOptions->newList(NULL);
230 atcDialogMessage->setLabel("Not tuned in to any ATC service.");
233 atcDialogCommunicationOptions->newList(NULL);
234 atcDialogMessage->setLabel("Tuned in to ATIS: no communication possible.");
237 atcDialogCommunicationOptions->newList(towerOptions);
238 atcDialogMessage->setLabel("Tuned in to Tower - select communication to transmit:");
241 atcDialogCommunicationOptions->newList(NULL);
242 atcDialogMessage->setLabel("Tuned in to Ground - select communication to transmit:");
245 current_atcdialog->DoDialog();
248 atcDialogCommunicationOptions->newList(NULL);
249 atcDialogMessage->setLabel("Tuned in to unknown ATC service - enter transmission:");
253 // Third - display the dialog without pausing sim.
254 if(type != APPROACH) {
259 void FGATCDialog::Init() {
260 // Add ATC-freq-search to the command list
261 globals->get_commands()->addCommand("ATC-freq-search", do_ATC_freq_search);
266 void FGATCDialog::add_entry(string station, string transmission, string menutext ) {
270 a.stationid = station;
271 a.transmission = transmission;
272 a.menuentry = menutext;
274 atcmentrylist_station[station.c_str()].push_back(a);
279 // query the database whether the transmission is already registered;
280 bool FGATCDialog::trans_reg( const string &station, const string &trans ) {
282 atcmentry_list_type atcmlist = atcmentrylist_station[station];
283 atcmentry_list_iterator current = atcmlist.begin();
284 atcmentry_list_iterator last = atcmlist.end();
286 for ( ; current != last ; ++current ) {
287 if ( current->transmission == trans ) return true;
293 // ===================================================
294 // === Update ATC menue and look for keys pressed ===
295 // ===================================================
296 void FGATCDialog::DoDialog() {
298 static string mentry[10];
299 static string mtrans[10];
302 FGATC* atcptr = globals->get_ATC_mgr()->GetComm1ATCPointer(); // Hardwired to comm1 at the moment
306 atcmentry_list_type atcmlist = atcmentrylist_station[atcptr->get_ident()];
307 //atcmentry_list_type atcmlist = atcmentrylist_station["EGNX"];
308 atcmentry_list_iterator current = atcmlist.begin();
309 atcmentry_list_iterator last = atcmlist.end();
311 // Set all opt flags to false before displaying box
312 fgSetBool("/sim/atc/opt0",false);
313 fgSetBool("/sim/atc/opt1",false);
314 fgSetBool("/sim/atc/opt2",false);
315 fgSetBool("/sim/atc/opt3",false);
316 fgSetBool("/sim/atc/opt4",false);
317 fgSetBool("/sim/atc/opt5",false);
318 fgSetBool("/sim/atc/opt6",false);
319 fgSetBool("/sim/atc/opt7",false);
320 fgSetBool("/sim/atc/opt8",false);
321 fgSetBool("/sim/atc/opt9",false);
327 if ( atcmlist.size() != 0 ){
328 int k=atcmlist.size();
330 //cout << "k = " << k << endl;
331 int y = (fgGetInt("/sim/startup/ysize") - 200 - 20 - k*20);
332 ATCMenuBox = new puDialogBox (100, y);
333 ATCMenuFrame = new puFrame (0,0,xsize,yc+40);
334 // loop over all entries in atcmentrylist
335 ATCOptionsList = new puButtonBox (50, 50, 450, 50+(k*25), NULL, true);
336 char** optList = new char*[k+1];
338 for ( ; current != last ; ++current ) {
340 sprintf( buf, "%i", kk+1 );
343 mentry[kk] = dum + ". " + current->menuentry;
344 optList[kk] = new char[strlen(mentry[kk].c_str()) + 1];
345 strcpy(optList[kk], mentry[kk].c_str());
346 //cout << "optList[" << kk << "] = " << optList[kk] << endl;
347 mtrans[kk] = current->transmission;
348 //ATCMenuBoxMessage = new puText (10, yc);
349 //ATCMenuBoxMessage -> setLabel( mentry[kk].c_str() );
355 ATCOptionsList->newList(optList);
357 int y = (fgGetInt("/sim/startup/ysize") - 100 - 20 );
358 ATCMenuBox = new puDialogBox (10, y);
359 ATCMenuFrame = new puFrame (0,0,xsize,yc+40);
360 ATCMenuBoxMessage = new puText (10, yc-10);
361 ATCMenuBoxMessage -> setLabel( "No transmission available" );
364 ATCMenuBoxMessage = new puText (10, yc+10);
365 ATCMenuBoxMessage -> setLabel( "ATC Menu" );
366 atcDialogOkButton = new puOneShot ((xsize/2)-85, 10, (xsize/2)-25, 50);
367 atcDialogOkButton -> setLegend (gui_msg_OK);
368 atcDialogOkButton -> makeReturnDefault (TRUE);
369 atcDialogOkButton -> setCallback (AKATCDialogOK);
371 atcDialogCancelButton = new puOneShot ((xsize/2)+25, 10, (xsize/2)+85, 50);
372 atcDialogCancelButton -> setLegend (gui_msg_CANCEL);
373 atcDialogCancelButton -> setCallback (AKATCDialogCancel);
374 FG_FINALIZE_PUI_DIALOG( ATCMenuBox );
375 FG_PUSH_PUI_DIALOG( ATCMenuBox );
379 if ( atckey != -1 && TransDisplayed && mtrans[atckey-1].c_str() != "" ) {
380 cout << mtrans[atckey-1].c_str() << endl;
381 TPar = current_transmissionlist->extract_transpar( mtrans[atckey-1].c_str() );
382 current_atcmentrylist->reset = true;
383 current_transparlist->add_entry( TPar );
385 // transpar_list_type test = current_transparlist;
386 // transpar_list_iterator current = test.begin();
387 //for ( ; current != test.end(); ++current ) {
388 // current->tpar.intention;
392 if ( current_atcmentrylist->freq != (int)(comm1_freq*100.0 + 0.5) ) {
393 current_atcmentrylist->reset = true;
396 // reset (delete) ATCmenue list if reset is true
397 if ( current_atcmentrylist->reset == true ) {
398 delete ( current_atcmentrylist );
399 current_atcmentrylist = new FGatcmentryList;
400 current_atcmentrylist->init( (int)(comm1_freq*100.0 + 0.5) );
401 if ( TransDisplayed ) {
402 FG_POP_PUI_DIALOG( ATCMenuBox );
403 TransDisplayed = false;
410 //////////////////////////////////////////////////////
412 // STUFF FOR THE FREQUENCY SEARCH DIALOG
414 //////////////////////////////////////////////////////
416 static puDialogBox* atcFreqDialog;
417 static puFrame* atcFreqDialogFrame;
418 static puText* atcFreqDialogMessage;
419 static puInput* atcFreqDialogInput;
420 static puOneShot* atcFreqDialogOkButton;
421 static puOneShot* atcFreqDialogCancelButton;
423 static puDialogBox* atcFreqDisplay;
424 static puFrame* atcFreqDisplayFrame;
425 static puText* atcFreqDisplayMessage;
426 static puOneShot* atcFreqDisplayOkButton;
427 static puOneShot* atcFreqDisplayCancelButton;
428 static puText* atcFreqDisplayText[20];
430 static void FreqDialogCancel(puObject*) {
431 FG_POP_PUI_DIALOG(atcFreqDialog);
434 static void FreqDialogOK(puObject*) {
435 string tmp = atcFreqDialogInput->getStringValue();
436 FG_POP_PUI_DIALOG(atcFreqDialog);
437 current_atcdialog->FreqDisplay(tmp);
440 static void FreqDisplayOK(puObject*) {
441 FG_POP_PUI_DIALOG(atcFreqDisplay);
444 static void FreqDisplayCancel(puObject*) {
445 FG_POP_PUI_DIALOG(atcFreqDisplay);
448 void FGATCDialog::FreqDialog() {
450 // Find the ATC stations within a reasonable range (about 40 miles?)
451 //comm_list_type atc_stations;
452 //comm_list_iterator atc_stat_itr;
454 //double lon = fgGetDouble("/position/longitude-deg");
455 //double lat = fgGetDouble("/position/latitude-deg");
456 //double elev = fgGetDouble("/position/altitude-ft");
459 // search stations in range
460 int num_stat = current_commlist->FindByPos(lon, lat, elev, 40.0, &atc_stations);
463 // Make up a message saying no things in range
467 //char defaultATCLabel[] = "Enter desired option to communicate with ATC:";
471 atcFreqDialog = new puDialogBox (150, 50);
473 atcFreqDialogFrame = new puFrame (0, 0, 300, hsize);
475 atcFreqDialogMessage = new puText (40, (hsize - 30));
476 atcFreqDialogMessage -> setDefaultValue ("Enter airport identifier:");
477 atcFreqDialogMessage -> getDefaultValue (&s);
478 atcFreqDialogMessage -> setLabel (s);
480 atcFreqDialogInput = new puInput (50, (hsize - 75), 150, (hsize - 45));
481 atcFreqDialogInput->acceptInput();
483 atcFreqDialogOkButton = new puOneShot (50, 10, 110, 50);
484 atcFreqDialogOkButton -> setLegend (gui_msg_OK);
485 atcFreqDialogOkButton -> makeReturnDefault (TRUE);
486 atcFreqDialogOkButton -> setCallback (FreqDialogOK);
488 atcFreqDialogCancelButton = new puOneShot (140, 10, 210, 50);
489 atcFreqDialogCancelButton -> setLegend (gui_msg_CANCEL);
490 atcFreqDialogCancelButton -> setCallback (FreqDialogCancel);
493 FG_FINALIZE_PUI_DIALOG(atcFreqDialog);
495 FG_PUSH_PUI_DIALOG(atcFreqDialog);
499 static void atcUppercase(string &s)
501 for(unsigned int i=0; i<s.size(); ++i) {
502 s[i] = toupper(s[i]);
506 void FGATCDialog::FreqDisplay(string ident) {
510 //char defaultATCLabel[] = "Enter desired option to communicate with ATC:";
511 string label = "Frequencies for airport ";
516 int n = 0; // Number of ATC frequencies at this airport
521 if ( dclFindAirportID( ident, &a ) ) {
522 comm_list_type stations;
523 int found = current_commlist->FindByPos(a.longitude, a.latitude, a.elevation, 20.0, &stations);
526 comm_list_iterator itr = stations.begin();
527 while(itr != stations.end()) {
528 if((*itr).ident == ident) {
529 if((*itr).type != INVALID) {
531 freqs[n] = ostr.str();
532 freqs[n].append(" - ");
533 sprintf(buf, "%.2f", ((*itr).freq / 100.0)); // Convert from KHz to MHz
535 if(buf[5] == '3') buf[5] = '2';
536 if(buf[5] == '8') buf[5] = '7';
548 label += " not found in database.";
553 label = "No frequencies found for airport ";
557 int hsize = (n < 0 ? 100 : 105 + (n * 30));
558 atcFreqDisplay = new puDialogBox (250, 50);
560 atcFreqDisplayFrame = new puFrame (0, 0, 400, hsize);
562 atcFreqDisplayMessage = new puText (40, (hsize - 30));
563 atcFreqDisplayMessage -> setDefaultValue (label.c_str());
564 atcFreqDisplayMessage -> getDefaultValue (&s);
565 atcFreqDisplayMessage -> setLabel (s);
567 for(int i=0; i<n; ++i) {
568 atcFreqDisplayText[i] = new puText(40, hsize - 65 - (30 * i));
569 atcFreqDisplayText[i]->setDefaultValue(freqs[i].c_str());
570 atcFreqDisplayText[i]-> getDefaultValue (&s);
571 atcFreqDisplayText[i]-> setLabel (s);
574 atcFreqDisplayOkButton = new puOneShot (50, 10, 110, 50);
575 atcFreqDisplayOkButton -> setLegend (gui_msg_OK);
576 atcFreqDisplayOkButton -> makeReturnDefault (TRUE);
577 atcFreqDisplayOkButton -> setCallback (FreqDisplayOK);
579 atcFreqDisplayCancelButton = new puOneShot (140, 10, 210, 50);
580 atcFreqDisplayCancelButton -> setLegend (gui_msg_CANCEL);
581 atcFreqDisplayCancelButton -> setCallback (FreqDisplayCancel);
584 FG_FINALIZE_PUI_DIALOG(atcFreqDisplay);
586 FG_PUSH_PUI_DIALOG(atcFreqDisplay);