]> git.mxchange.org Git - flightgear.git/blob - src/ATC/ATCDialog.cxx
Enhancements to AI plane transmissions
[flightgear.git] / src / ATC / ATCDialog.cxx
1 // ATCDialog.cxx - Functions and classes to handle the pop-up ATC dialog
2 //
3 // Written by Alexander Kappes and David Luff, started February 2003.
4 //
5 // Copyright (C) 2003  Alexander Kappes and David Luff
6 //
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.
11 //
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.
16 //
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.
20
21 #include <simgear/compiler.h>
22
23 #include <simgear/structure/commands.hxx>
24
25 #include <Main/globals.hxx>
26 #include <GUI/gui.h>
27
28 #include "ATCDialog.hxx"
29 #include "ATC.hxx"
30 #include "ATCmgr.hxx"
31 #include "commlist.hxx"
32 #include "ATCutils.hxx"
33 #include <Airports/simple.hxx>
34
35 #include <sstream>
36
37 SG_USING_STD(ostringstream);
38
39 FGATCDialog *current_atcdialog;
40
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();
44         return(true);
45 }
46
47 static bool do_ATC_freq_search(const SGPropertyNode* arg) {
48         current_atcdialog->FreqDialog();
49         return(true);
50 }
51
52 ATCMenuEntry::ATCMenuEntry() {
53   stationid    = "";
54   stationfr    = 0;
55   transmission = "";
56   menuentry    = "";
57 }
58
59 ATCMenuEntry::~ATCMenuEntry() {
60 }
61
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];
66
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 // ----------------------------------------------------------------------
77
78 // ------------------------ AK ------------------------------------------
79 static puDialogBox  *ATCMenuBox = 0;
80 static puFrame      *ATCMenuFrame = 0;
81 static puText       *ATCMenuBoxMessage = 0;
82 static puButtonBox      *ATCOptionsList = 0;
83 // ----------------------------------------------------------------------
84
85 // AK
86 static void AKATCDialogOK(puObject *)
87 {
88         switch(ATCOptionsList->getValue()) {
89         case 0:
90                 //cout << "Option 0 chosen\n";
91                 fgSetBool("/sim/atc/opt0",true);
92                 break;
93         case 1:
94                 //cout << "Option 1 chosen\n";
95                 fgSetBool("/sim/atc/opt1",true);
96                 break;
97         case 2:
98                 //cout << "Option 2 chosen\n";
99                 fgSetBool("/sim/atc/opt2",true);
100                 break;
101         case 3:
102                 //cout << "Option 2 chosen\n";
103                 fgSetBool("/sim/atc/opt3",true);
104                 break;
105         default:
106                 break;
107         }
108         FG_POP_PUI_DIALOG( ATCMenuBox );
109 }
110
111 // AK
112 static void AKATCDialogCancel(puObject *)
113 {
114     FG_POP_PUI_DIALOG( ATCMenuBox );
115 }
116
117 // DCL
118 static void ATCDialogCancel(puObject *)
119 {
120     //ATCDialogInput->rejectInput();
121     FG_POP_PUI_DIALOG( atcDialog );
122 }
123
124 // DCL
125 static void ATCDialogOK (puObject *me)
126 {
127         // Note that currently the dialog is hardwired to comm1 only here.
128         switch(globals->get_ATC_mgr()->GetComm1ATCType()) {
129         case INVALID:
130                 break;
131         case ATIS:
132                 break;
133         case TOWER: {
134                 /*
135                 FGTower* twr = (FGTower*)globals->get_ATC_mgr()->GetComm1ATCPointer();
136                 switch(atcDialogCommunicationOptions->getValue()) {
137                 case 0:
138                         //cout << "Option 0 chosen\n";
139                         twr->RequestLandingClearance("charlie foxtrot sierra");
140                         break;
141                 case 1:
142                         //cout << "Option 1 chosen\n";
143                         twr->RequestDepartureClearance("charlie foxtrot sierra");
144                         break;
145                 case 2:
146                         //cout << "Option 2 chosen\n";
147                         twr->ReportRunwayVacated("charlie foxtrot sierra");
148                         break;
149                 default:
150                         break;
151                 }
152                 */
153                 break;
154         }
155         case GROUND:
156                 break;
157         case APPROACH:
158                 break;
159         default:
160                 break;
161         }
162
163     ATCDialogCancel(me);
164     //if(error) mkDialog(s.c_str());
165 }
166
167 // DCL
168 static void ATCDialog(puObject *cb)
169 {
170     //ApHeadingDialogInput   ->    setValue ( heading );
171     //ApHeadingDialogInput    -> acceptInput();
172     FG_PUSH_PUI_DIALOG(atcDialog);
173 }
174
175 // DCL
176 void ATCDialogInit()
177 {
178         char defaultATCLabel[] = "Enter desired option to communicate with ATC:";
179         char *s;
180
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;
189         
190         atcDialog = new puDialogBox (150, 50);
191         {
192                 atcDialogFrame   = new puFrame (0, 0, 500, 250);
193                 
194                 atcDialogMessage = new puText          (250, 220);
195                 atcDialogMessage    -> setDefaultValue (defaultATCLabel);
196                 atcDialogMessage    -> getDefaultValue (&s);
197                 atcDialogMessage    -> setLabel        (s);
198                 atcDialogMessage    -> setLabelPlace   (PUPLACE_TOP_CENTERED);
199
200                 atcDialogCommunicationOptions = new puButtonBox (50, 50, 450, 210, NULL, true);
201                 
202                 atcDialogOkButton     =  new puOneShot         (50, 10, 110, 50);
203                 atcDialogOkButton     ->     setLegend         (gui_msg_OK);
204                 atcDialogOkButton     ->     makeReturnDefault (TRUE);
205                 atcDialogOkButton     ->     setCallback       (ATCDialogOK);
206                 
207                 atcDialogCancelButton =  new puOneShot         (140, 10, 210, 50);
208                 atcDialogCancelButton ->     setLegend         (gui_msg_CANCEL);
209                 atcDialogCancelButton ->     setCallback       (ATCDialogCancel);
210                 
211         }
212         FG_FINALIZE_PUI_DIALOG(atcDialog);
213         
214         // Add ATC-dialog to the command list
215         globals->get_commands()->addCommand("ATC-dialog", do_ATC_dialog);
216 }
217
218 ///////////////////////////////////////////////////////////////////////
219 //
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
224 //
225 ///////////////////////////////////////////////////////////////////////
226 void ATCDoDialog(atc_type type) {
227         switch(type) {
228         case INVALID:
229                 atcDialogCommunicationOptions->newList(NULL);
230                 atcDialogMessage->setLabel("Not tuned in to any ATC service.");
231                 break;
232         case ATIS:
233                 atcDialogCommunicationOptions->newList(NULL);
234                 atcDialogMessage->setLabel("Tuned in to ATIS: no communication possible.");
235                 break;
236         case TOWER: 
237                 atcDialogCommunicationOptions->newList(towerOptions);
238                 atcDialogMessage->setLabel("Tuned in to Tower - select communication to transmit:");
239                 break;
240         case GROUND:
241                 atcDialogCommunicationOptions->newList(NULL);
242                 atcDialogMessage->setLabel("Tuned in to Ground - select communication to transmit:");
243                 break;
244         case APPROACH:
245                 current_atcdialog->DoDialog();
246                 break;
247         default:
248                 atcDialogCommunicationOptions->newList(NULL);
249                 atcDialogMessage->setLabel("Tuned in to unknown ATC service - enter transmission:");
250                 break;
251         }
252
253         // Third - display the dialog without pausing sim.
254         if(type != APPROACH) {  
255                 ATCDialog(NULL);
256         }
257 }
258
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);
262 }
263
264 // AK
265 // Add an entry
266 void FGATCDialog::add_entry(string station, string transmission, string menutext ) {
267   
268   ATCMenuEntry a;
269
270   a.stationid = station;
271   a.transmission = transmission;
272   a.menuentry = menutext;
273
274   atcmentrylist_station[station.c_str()].push_back(a);
275
276 }
277
278 // AK
279 // query the database whether the transmission is already registered; 
280 bool FGATCDialog::trans_reg( const string &station, const string &trans ) {
281
282   atcmentry_list_type     atcmlist = atcmentrylist_station[station];
283   atcmentry_list_iterator current  = atcmlist.begin();
284   atcmentry_list_iterator last     = atcmlist.end();
285   
286   for ( ; current != last ; ++current ) {
287     if ( current->transmission == trans ) return true;
288   }
289   return false;
290 }
291
292 // AK
293 // ===================================================
294 // ===  Update ATC menue and look for keys pressed ===
295 // ===================================================
296 void FGATCDialog::DoDialog() {
297         
298         static string mentry[10];
299         static string mtrans[10];
300         char   buf[10];
301         TransPar TPar;
302         FGATC* atcptr = globals->get_ATC_mgr()->GetComm1ATCPointer();   // Hardwired to comm1 at the moment
303         
304         if(atcptr != NULL) {
305                 
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();
310                 
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);
322                 
323                 //int yc = 10;
324                 int yc = 70;
325                 int xsize = 600;
326                 
327                 if ( atcmlist.size() != 0 ){ 
328                         int k=atcmlist.size();
329                         //int k = 3;
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];
337                         int kk = 0;
338                         for ( ; current != last ; ++current ) {
339                                 string dum;
340                                 sprintf( buf, "%i", kk+1 );
341                                 buf[1] = '\0';
342                                 dum = buf;
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() );
350                                 yc += 20;
351                                 ++kk;
352                         } 
353                         yc += 2*20;
354                         optList[k] = NULL;
355                         ATCOptionsList->newList(optList);
356                 } else {
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" );
362                 }
363                 
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);
370                 
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 );
376                 
377                 
378                 /*      
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 );
384                         
385                         //    transpar_list_type test = current_transparlist;
386                         // transpar_list_iterator current = test.begin();
387                         //for ( ; current != test.end(); ++current ) {
388                                 // current->tpar.intention;
389                         //}
390                 }
391                 
392                 if ( current_atcmentrylist->freq != (int)(comm1_freq*100.0 + 0.5) ) {
393                         current_atcmentrylist->reset = true;
394                 }
395                 
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;
404                         }
405                 }
406                 */      
407         }
408 }
409
410 //////////////////////////////////////////////////////
411 //
412 //  STUFF FOR THE FREQUENCY SEARCH DIALOG
413 //
414 //////////////////////////////////////////////////////
415
416 static puDialogBox*             atcFreqDialog;
417 static puFrame*                 atcFreqDialogFrame;
418 static puText*                  atcFreqDialogMessage;
419 static puInput*                 atcFreqDialogInput;
420 static puOneShot*               atcFreqDialogOkButton;
421 static puOneShot*               atcFreqDialogCancelButton;
422 //static puButtonBox*           atcFreqDialogCommunicationOptions;
423
424 static puText* atcFreqDisplayText[20];
425         
426 static void FreqDialogCancel(puObject*) {
427         FG_POP_PUI_DIALOG(atcFreqDialog);
428         delete atcFreqDialog;
429 }
430
431 static void FreqDialogOK(puObject*) {
432         string tmp = atcFreqDialogInput->getStringValue();
433         FG_POP_PUI_DIALOG(atcFreqDialog);
434         delete atcFreqDialog;
435         current_atcdialog->FreqDisplay(tmp);
436 }
437
438 static void FreqDisplayOK(puObject*) {
439         FG_POP_PUI_DIALOG(atcFreqDialog);
440         delete atcFreqDialog;
441 }
442
443 void FGATCDialog::FreqDialog() {
444
445         // Find the ATC stations within a reasonable range (about 40 miles?)
446         //comm_list_type atc_stations;
447         //comm_list_iterator atc_stat_itr;
448         
449         //double lon = fgGetDouble("/position/longitude-deg");
450         //double lat = fgGetDouble("/position/latitude-deg");
451         //double elev = fgGetDouble("/position/altitude-ft");
452         
453         /*
454         // search stations in range
455         int num_stat = current_commlist->FindByPos(lon, lat, elev, 40.0, &atc_stations);
456         if (num_stat != 0) {
457         } else {
458                 // Make up a message saying no things in range
459         }
460         */
461         
462         //char defaultATCLabel[] = "Enter desired option to communicate with ATC:";
463         char *s;
464         
465         int hsize = 150;
466         atcFreqDialog = new puDialogBox (150, 50);
467         {
468                 atcFreqDialogFrame   = new puFrame (0, 0, 300, hsize);
469                 
470                 atcFreqDialogMessage = new puText          (40, (hsize - 30));
471                 atcFreqDialogMessage    -> setDefaultValue ("Enter airport identifier:");
472                 atcFreqDialogMessage    -> getDefaultValue (&s);
473                 atcFreqDialogMessage    -> setLabel        (s);
474                 //atcFreqDialogMessage    -> setLabelPlace   (PUPLACE_TOP_CENTERED);
475                 //atcFreqDialogMessage    -> setLabelPlace   (0);
476
477                 atcFreqDialogInput = new puInput (50, (hsize - 75), 150, (hsize - 45));
478                 atcFreqDialogInput->acceptInput();
479                 
480                 atcFreqDialogOkButton     =  new puOneShot         (50, 10, 110, 50);
481                 atcFreqDialogOkButton     ->     setLegend         (gui_msg_OK);
482                 atcFreqDialogOkButton     ->     makeReturnDefault (TRUE);
483                 atcFreqDialogOkButton     ->     setCallback       (FreqDialogOK);
484                 
485                 atcFreqDialogCancelButton =  new puOneShot         (140, 10, 210, 50);
486                 atcFreqDialogCancelButton ->     setLegend         (gui_msg_CANCEL);
487                 atcFreqDialogCancelButton ->     setCallback       (FreqDialogCancel);
488                 
489         }
490         FG_FINALIZE_PUI_DIALOG(atcFreqDialog);
491         
492         FG_PUSH_PUI_DIALOG(atcFreqDialog);
493         
494 }
495
496 static void atcUppercase(string &s)
497 {
498         for(unsigned int i=0; i<s.size(); ++i) {
499                 s[i] = toupper(s[i]);
500         }
501 }
502
503 void FGATCDialog::FreqDisplay(string ident) {
504
505         atcUppercase(ident);
506         
507         //char defaultATCLabel[] = "Enter desired option to communicate with ATC:";
508         string label = "Frequencies for airport ";
509         label += ident;
510         label += ":";
511         char *s;
512         
513         int n = 0;      // Number of ATC frequencies at this airport
514         string freqs[20];
515         char buf[8];
516
517     FGAirport a;
518     if ( dclFindAirportID( ident, &a ) ) {
519                 comm_list_type stations;
520                 int found = current_commlist->FindByPos(a.longitude, a.latitude, a.elevation, 20.0, &stations);
521                 if(found) {
522                         ostringstream ostr;
523                         comm_list_iterator itr = stations.begin();
524                         while(itr != stations.end()) {
525                                 if((*itr).ident == ident) {
526                                         if((*itr).type != INVALID) {
527                                                 ostr << (*itr).type;
528                                                 freqs[n] = ostr.str();
529                                                 freqs[n].append("     -     ");
530                                                 sprintf(buf, "%.2f", ((*itr).freq / 100.0));    // Convert from KHz to MHz
531                                                 // Hack alert!
532                                                 if(buf[5] == '3') buf[5] = '2';
533                                                 if(buf[5] == '8') buf[5] = '7';
534                                                 freqs[n] += buf;
535                                                 ostr.seekp(0);
536                                                 n++;
537                                         }
538                                 }
539                                 ++itr;
540                         }
541                 }
542     } else {
543                 label = "Airport ";
544                 label += ident;
545                 label += " not found in database.";
546                 n = -1;
547         }
548         
549         if(n == 0) {
550                 label = "No frequencies found for airport ";
551                 label += ident;
552         }
553
554         int hsize = (n < 0 ? 100 : 105 + (n * 30));
555         atcFreqDialog = new puDialogBox (250, 50);
556         {
557                 atcFreqDialogFrame   = new puFrame (0, 0, 400, hsize);
558                 
559                 atcFreqDialogMessage = new puText          (40, (hsize - 30));
560                 atcFreqDialogMessage    -> setDefaultValue (label.c_str());
561                 atcFreqDialogMessage    -> getDefaultValue (&s);
562                 atcFreqDialogMessage    -> setLabel        (s);
563                 
564                 for(int i=0; i<n; ++i) {
565                         atcFreqDisplayText[i] = new puText(40, hsize - 65 - (30 * i));
566                         atcFreqDisplayText[i]->setDefaultValue(freqs[i].c_str());
567                         atcFreqDisplayText[i]-> getDefaultValue (&s);
568                         atcFreqDisplayText[i]-> setLabel        (s);
569                 }
570                 
571                 atcFreqDialogOkButton     =  new puOneShot         (50, 10, 110, 50);
572                 atcFreqDialogOkButton     ->     setLegend         (gui_msg_OK);
573                 atcFreqDialogOkButton     ->     makeReturnDefault (TRUE);
574                 atcFreqDialogOkButton     ->     setCallback       (FreqDisplayOK);
575                 
576                 atcFreqDialogCancelButton =  new puOneShot         (140, 10, 210, 50);
577                 atcFreqDialogCancelButton ->     setLegend         (gui_msg_CANCEL);
578                 atcFreqDialogCancelButton ->     setCallback       (FreqDialogCancel);
579                 
580         }
581         FG_FINALIZE_PUI_DIALOG(atcFreqDialog);
582         
583         FG_PUSH_PUI_DIALOG(atcFreqDialog);
584         
585 }
586