]> git.mxchange.org Git - flightgear.git/blob - src/ATC/ATCDialog.cxx
Mathias Fröhlich:
[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 "ATCdisplay.hxx"
32 #include "commlist.hxx"
33 #include "ATCutils.hxx"
34 #include <Airports/simple.hxx>
35
36 #include <sstream>
37
38 SG_USING_STD(ostringstream);
39
40 FGATCDialog *current_atcdialog;
41
42 // For the command manager - maybe eventually this should go in the built in command list
43 static bool do_ATC_dialog(const SGPropertyNode* arg) {
44         current_atcdialog->PopupDialog();
45         return(true);
46 }
47
48 static bool do_ATC_freq_search(const SGPropertyNode* arg) {
49         current_atcdialog->FreqDialog();
50         return(true);
51 }
52
53 ATCMenuEntry::ATCMenuEntry() {
54   stationid    = "";
55   //stationfr    = 0;
56   transmission = "";
57   menuentry    = "";
58   callback_code = 0;
59 }
60
61 ATCMenuEntry::~ATCMenuEntry() {
62 }
63
64 static void atcUppercase(string &s) {
65         for(unsigned int i=0; i<s.size(); ++i) {
66                 s[i] = toupper(s[i]);
67         }
68 }
69
70 // ----------------------- Popup Dialog Statics------------------
71 static puDialogBox*     atcDialog;
72 static puFrame*         atcDialogFrame;
73 static puText*          atcDialogMessage;
74 static puOneShot*       atcDialogOkButton;
75 static puOneShot*       atcDialogCancelButton;
76 static puButtonBox*     atcDialogCommunicationOptions;
77 // --------------------------------------------------------------
78
79 // ----------------------- Freq Dialog Statics-------------------
80 static const int ATC_MAX_FREQ_DISPLAY = 20;             // Maximum number of frequencies that can be displayed for any one airport
81
82 static puDialogBox*     atcFreqDialog;
83 static puFrame*         atcFreqDialogFrame;
84 static puText*          atcFreqDialogMessage;
85 static puInput*         atcFreqDialogInput;
86 static puOneShot*       atcFreqDialogOkButton;
87 static puOneShot*       atcFreqDialogCancelButton;
88
89 static puDialogBox*     atcFreqDisplay;
90 static puFrame*         atcFreqDisplayFrame;
91 static puText*          atcFreqDisplayMessage;
92 static puOneShot*       atcFreqDisplayOkButton;
93 static puText*          atcFreqDisplayText[ATC_MAX_FREQ_DISPLAY];
94 // --------------------------------------------------------------
95
96 //////////////// Popup callbacks ///////////////////
97 static void ATCDialogOK(puObject*) {
98         current_atcdialog->PopupCallback();
99         FG_POP_PUI_DIALOG( atcDialog );
100 }
101
102 static void ATCDialogCancel(puObject*) {
103     FG_POP_PUI_DIALOG( atcDialog );
104 }
105 //////////////////////////////////////////////////
106
107
108 ///////////////// Freq search callbacks ///////////
109 static void FreqDialogCancel(puObject*) {
110         FG_POP_PUI_DIALOG(atcFreqDialog);
111 }
112
113 static void FreqDialogOK(puObject*) {
114         string tmp = atcFreqDialogInput->getStringValue();
115         FG_POP_PUI_DIALOG(atcFreqDialog);
116         current_atcdialog->FreqDisplay(tmp);
117 }
118
119 static void FreqDisplayOK(puObject*) {
120         FG_POP_PUI_DIALOG(atcFreqDisplay);
121 }
122 //////////////////////////////////////////////////
123
124
125 FGATCDialog::FGATCDialog() {
126         _callbackPending = false;
127         _callbackTimer = 0.0;
128         _callbackWait = 0.0;
129         _callbackPtr = NULL;
130         _callbackCode = 0;
131 }
132
133 FGATCDialog::~FGATCDialog() {
134         if(atcDialog) puDeleteObject(atcDialog);
135         if(atcFreqDialog) puDeleteObject(atcFreqDialog);
136         if(atcFreqDisplay) puDeleteObject(atcFreqDisplay);
137 }
138
139 void FGATCDialog::Init() {
140         // Add ATC-dialog to the command list
141         globals->get_commands()->addCommand("ATC-dialog", do_ATC_dialog);
142         // Add ATC-freq-search to the command list
143         globals->get_commands()->addCommand("ATC-freq-search", do_ATC_freq_search);
144         
145         int w;
146         int h;
147         int x;
148         int y;
149         
150         // Init the freq-search dialog
151         w = 300;
152         h = 150;
153         x = (fgGetInt("/sim/startup/xsize") / 2) - (w / 2);
154         y = 50;
155         char *s;
156         atcFreqDialog = new puDialogBox (x, y);
157         {
158                 atcFreqDialogFrame = new puFrame (0, 0, w, h);
159                 atcFreqDialogMessage = new puText          (40, (h - 30));
160                 atcFreqDialogMessage->setDefaultValue ("Enter airport identifier:");
161                 atcFreqDialogMessage->getDefaultValue (&s);
162                 atcFreqDialogMessage->setLabel(s);
163         
164                 atcFreqDialogInput = new puInput (50, (h - 75), 150, (h - 45));
165                         
166                 atcFreqDialogOkButton     =  new puOneShot         (50, 10, 110, 50);
167                 atcFreqDialogOkButton     ->     setLegend         (gui_msg_OK);
168                 atcFreqDialogOkButton     ->     makeReturnDefault (TRUE);
169                 atcFreqDialogOkButton     ->     setCallback       (FreqDialogOK);
170                         
171                 atcFreqDialogCancelButton =  new puOneShot         (140, 10, 210, 50);
172                 atcFreqDialogCancelButton ->     setLegend         (gui_msg_CANCEL);
173                 atcFreqDialogCancelButton ->     setCallback       (FreqDialogCancel);
174                 
175                 atcFreqDialogInput->acceptInput();
176         }
177         
178         FG_FINALIZE_PUI_DIALOG(atcFreqDialog);
179         
180         // Init the freq-display dialog
181         w = 400;
182         h = 100;
183         x = (fgGetInt("/sim/startup/xsize") / 2) - (w / 2);
184         y = 50;
185         atcFreqDisplay = new puDialogBox (x, y);
186         {
187                 atcFreqDisplayFrame   = new puFrame (0, 0, w, h);
188                 
189                 atcFreqDisplayMessage = new puText          (40, (h - 30));
190                 atcFreqDisplayMessage    -> setDefaultValue ("No freqencies found");
191                 atcFreqDisplayMessage    -> getDefaultValue (&s);
192                 atcFreqDisplayMessage    -> setLabel        (s);
193                 
194                 for(int i=0; i<ATC_MAX_FREQ_DISPLAY; ++i) {
195                         atcFreqDisplayText[i] = new puText(40, h - 65 - (30 * i));
196                         atcFreqDisplayText[i]->setDefaultValue("");
197                         atcFreqDisplayText[i]-> getDefaultValue (&s);
198                         atcFreqDisplayText[i]-> setLabel        (s);
199                         atcFreqDisplayText[i]->hide();
200                 }
201                 
202                 atcFreqDisplayOkButton     =  new puOneShot         (50, 10, 110, 50);
203                 atcFreqDisplayOkButton     ->     setLegend         (gui_msg_OK);
204                 atcFreqDisplayOkButton     ->     makeReturnDefault (TRUE);
205                 atcFreqDisplayOkButton     ->     setCallback       (FreqDisplayOK);
206         }
207         FG_FINALIZE_PUI_DIALOG(atcFreqDisplay);
208         
209         // Init AK's interactive ATC menus
210         w = 500;
211         h = 110;
212         x = (fgGetInt("/sim/startup/xsize") / 2) - (w / 2);
213         //y = (fgGetInt("/sim/startup/ysize") / 2) - (h / 2);
214         y = 50;
215         atcDialog = new puDialogBox (x, y);
216         {
217                 atcDialogFrame = new puFrame (0,0,w,h);
218                 atcDialogMessage = new puText (w / 2, h - 30);
219                 atcDialogMessage -> setLabel( "No transmission available" );
220                 atcDialogMessage -> setLabelPlace(PUPLACE_TOP_CENTERED);
221                 atcDialogCommunicationOptions = new puButtonBox (50, 60, 450, 50, NULL, true);
222                 atcDialogCommunicationOptions -> hide();
223                 atcDialogOkButton     =  new puOneShot         ((w/2)-85, 10, (w/2)-25, 50);
224                 atcDialogOkButton     ->     setLegend         (gui_msg_OK);
225                 atcDialogOkButton     ->     makeReturnDefault (TRUE);
226                 atcDialogOkButton     ->     setCallback       (ATCDialogOK);
227                 
228                 atcDialogCancelButton =  new puOneShot         ((w/2)+25, 10, (w/2)+85, 50);
229                 atcDialogCancelButton ->     setLegend         (gui_msg_CANCEL);
230                 atcDialogCancelButton ->     setCallback       (ATCDialogCancel);
231         }
232         FG_FINALIZE_PUI_DIALOG(atcDialog);
233 }
234
235 void FGATCDialog::Update(double dt) {
236         if(_callbackPending) {
237                 if(_callbackTimer > _callbackWait) {
238                         _callbackPtr->ReceiveUserCallback(_callbackCode);
239                         _callbackPtr->NotifyTransmissionFinished(fgGetString("/sim/user/callsign"));
240                         _callbackPending = false;
241                 } else {
242                         _callbackTimer += dt;
243                 }
244         }
245 }
246
247 // Add an entry
248 void FGATCDialog::add_entry(string station, string transmission, string menutext, atc_type type, int code) {
249
250   ATCMenuEntry a;
251
252   a.stationid = station;
253   a.transmission = transmission;
254   a.menuentry = menutext;
255   a.callback_code = code;
256
257   (available_dialog[type])[station.c_str()].push_back(a);
258
259 }
260
261 void FGATCDialog::remove_entry( const string &station, const string &trans, atc_type type ) {
262   atcmentry_vec_type* p = &((available_dialog[type])[station]);
263   atcmentry_vec_iterator current = p->begin();  
264   while(current != p->end()) {
265     if(current->transmission == trans) current = p->erase(current);
266         else ++current;
267   }
268 }
269
270 void FGATCDialog::remove_entry( const string &station, int code, atc_type type ) {
271   atcmentry_vec_type* p = &((available_dialog[type])[station]);
272   atcmentry_vec_iterator current = p->begin();
273   while(current != p->end()) {
274     if(current->callback_code == code) current = p->erase(current);
275         else ++current;
276   }
277 }
278
279 // query the database whether the transmission is already registered; 
280 bool FGATCDialog::trans_reg( const string &station, const string &trans, atc_type type ) {
281   atcmentry_vec_type* p = &((available_dialog[type])[station]);
282   atcmentry_vec_iterator current = p->begin();
283   for ( ; current != p->end() ; ++current ) {
284     if ( current->transmission == trans ) return true;
285   }
286   return false;
287 }
288
289 // query the database whether the transmission is already registered; 
290 bool FGATCDialog::trans_reg( const string &station, int code, atc_type type ) {
291   atcmentry_vec_type* p = &((available_dialog[type])[station]);
292   atcmentry_vec_iterator current = p->begin();
293   for ( ; current != p->end() ; ++current ) {
294     if ( current->callback_code == code ) return true;
295   }
296   return false;
297 }
298
299 // Display the ATC popup dialog box with options relevant to the users current situation.
300 void FGATCDialog::PopupDialog() {
301         
302         static string mentry[10];
303         static string mtrans[10];
304         char   buf[10];
305         TransPar TPar;
306         FGATC* atcptr = globals->get_ATC_mgr()->GetComm1ATCPointer();   // Hardwired to comm1 at the moment
307         
308         int w = 500;
309         int h = 100;
310         if(atcptr) {
311                 if(atcptr->GetType() == ATIS) {
312                         atcDialogCommunicationOptions->hide();
313                         atcDialogMessage -> setLabel( "Tuned to ATIS - no communication possible" );
314                         atcDialogFrame->setSize(w, h);
315                         atcDialogMessage -> setPosition(w / 2, h - 30);
316                 } else {
317                         
318                         atcmentry_vec_type atcmlist = (available_dialog[atcptr->GetType()])[atcptr->get_ident()];
319                         atcmentry_vec_iterator current = atcmlist.begin();
320                         atcmentry_vec_iterator last = atcmlist.end();
321                         
322                         // Set all opt flags to false before displaying box
323                         fgSetBool("/sim/atc/opt0",false);
324                         fgSetBool("/sim/atc/opt1",false);
325                         fgSetBool("/sim/atc/opt2",false);
326                         fgSetBool("/sim/atc/opt3",false);
327                         fgSetBool("/sim/atc/opt4",false);
328                         fgSetBool("/sim/atc/opt5",false);
329                         fgSetBool("/sim/atc/opt6",false);
330                         fgSetBool("/sim/atc/opt7",false);
331                         fgSetBool("/sim/atc/opt8",false);
332                         fgSetBool("/sim/atc/opt9",false);
333                         
334                         int k = atcmlist.size();
335                         h += k * 25;
336                         //cout << "k = " << k << '\n';
337                         
338                         atcDialogFrame->setSize(w, h); 
339                         
340                         if(k) { 
341                                 // loop over all entries in atcmentrylist
342                                 char** optList = new char*[k+1];
343                                 int kk = 0;
344                                 for ( ; current != last ; ++current ) {
345                                         string dum;
346                                         sprintf( buf, "%i", kk+1 );
347                                         buf[1] = '\0';
348                                         dum = buf;
349                                         mentry[kk] = dum + ". " + current->menuentry;
350                                         optList[kk] = new char[strlen(mentry[kk].c_str()) + 1];
351                                         strcpy(optList[kk], mentry[kk].c_str());
352                                         //cout << "optList[" << kk << "] = " << optList[kk] << endl; 
353                                         mtrans[kk] =              current->transmission;
354                                         ++kk;
355                                 } 
356                                 optList[k] = NULL;
357                                 atcDialogCommunicationOptions->newList(optList);
358                                 atcDialogCommunicationOptions->setSize(w-100, h-90);
359                                 atcDialogCommunicationOptions->reveal();
360                                 atcDialogMessage -> setLabel( "ATC Menu" );
361                                 atcDialogMessage -> setPosition(w / 2, h - 30);
362                         } else {
363                                 atcDialogCommunicationOptions->hide();
364                                 atcDialogMessage -> setLabel( "No transmission available" );
365                                 atcDialogMessage -> setPosition(w / 2, h - 30);
366                         }
367                 }
368         } else {
369                 atcDialogCommunicationOptions->hide();
370                 atcDialogMessage -> setLabel( "Not currently tuned to any ATC service" );
371                 atcDialogFrame->setSize(w, h);
372                 atcDialogMessage -> setPosition(w / 2, h - 30);
373         }
374                 
375         FG_PUSH_PUI_DIALOG(atcDialog);
376 }
377
378 void FGATCDialog::PopupCallback() {
379         FGATC* atcptr = globals->get_ATC_mgr()->GetComm1ATCPointer();   // FIXME - Hardwired to comm1 at the moment
380
381         if(atcptr) {
382                 if(atcptr->GetType() == APPROACH) {
383                         switch(atcDialogCommunicationOptions->getValue()) {
384                         case 0:
385                                 fgSetBool("/sim/atc/opt0",true);
386                                 break;
387                         case 1:
388                                 fgSetBool("/sim/atc/opt1",true);
389                                 break;
390                         case 2:
391                                 fgSetBool("/sim/atc/opt2",true);
392                                 break;
393                         case 3:
394                                 fgSetBool("/sim/atc/opt3",true);
395                                 break;
396                         default:
397                                 break;
398                         }
399                 } else if(atcptr->GetType() == TOWER) {
400                         //cout << "TOWER " << endl;
401                         //cout << "ident is " << atcptr->get_ident() << endl;
402                         atcmentry_vec_type atcmlist = (available_dialog[TOWER])[atcptr->get_ident()];
403                         if(atcmlist.size()) {
404                                 //cout << "Doing callback...\n";
405                                 ATCMenuEntry a = atcmlist[atcDialogCommunicationOptions->getValue()];
406                                 atcptr->SetFreqInUse();
407                                 // This is the user's speech getting displayed.
408                                 globals->get_ATC_display()->RegisterSingleMessage(atcptr->GenText(a.transmission, a.callback_code));
409                                 _callbackPending = true;
410                                 _callbackTimer = 0.0;
411                                 _callbackWait = 5.0;
412                                 _callbackPtr = atcptr;
413                                 _callbackCode = a.callback_code;
414                         } else {
415                                 //cout << "No options available...\n";
416                         }
417                         //cout << "Donded" << endl;
418                 }
419         }
420 }
421
422 void FGATCDialog::FreqDialog() {
423
424         // Find the ATC stations within a reasonable range (about 40 miles?)
425         //comm_list_type atc_stations;
426         //comm_list_iterator atc_stat_itr;
427         
428         //double lon = fgGetDouble("/position/longitude-deg");
429         //double lat = fgGetDouble("/position/latitude-deg");
430         //double elev = fgGetDouble("/position/altitude-ft");
431         
432         /*
433         // search stations in range
434         int num_stat = current_commlist->FindByPos(lon, lat, elev, 40.0, &atc_stations);
435         if (num_stat != 0) {
436         } else {
437                 // Make up a message saying no things in range
438         }
439         */
440         
441         // TODO - it would be nice to display a drop-down list of airports within the general vicinity of the user
442         //        in addition to the general input box (started above).
443         
444         atcFreqDialogInput->setValue("");
445         atcFreqDialogInput->acceptInput();
446         FG_PUSH_PUI_DIALOG(atcFreqDialog);
447 }
448
449 void FGATCDialog::FreqDisplay(string ident) {
450
451         atcUppercase(ident);
452         
453         string label;
454         char *s;
455         
456         int n = 0;      // Number of ATC frequencies at this airport
457         string freqs[ATC_MAX_FREQ_DISPLAY];
458         char buf[8];
459
460     FGAirport a;
461     if ( dclFindAirportID( ident, &a ) ) {
462                 comm_list_type stations;
463                 int found = current_commlist->FindByPos(a.getLongitude(), a.getLatitude(), a.getElevation(), 20.0, &stations);
464                 if(found) {
465                         ostringstream ostr;
466                         comm_list_iterator itr = stations.begin();
467                         while(itr != stations.end()) {
468                                 if((*itr).ident == ident) {
469                                         if((*itr).type != INVALID) {
470                                                 ostr << (*itr).type;
471                                                 freqs[n] = ostr.str();
472                                                 freqs[n].append("     -     ");
473                                                 sprintf(buf, "%.2f", ((*itr).freq / 100.0));    // Convert from KHz to MHz
474                                                 // Hack alert!
475                                                 if(buf[5] == '3') buf[5] = '2';
476                                                 if(buf[5] == '8') buf[5] = '7';
477                                                 freqs[n] += buf;
478                                                 ostr.seekp(0);
479                                                 n++;
480                                         }
481                                 }
482                                 ++itr;
483                         }
484                 }
485                 if(n == 0) {
486                         label = "No frequencies found for airport ";
487                         label += ident;
488                 } else {
489                         label = "Frequencies for airport ";
490                         label += ident;
491                         label += ":";
492                 }
493     } else {
494                 label = "Airport ";
495                 label += ident;
496                 label += " not found in database.";
497         }
498
499         int hsize = 105 + (n * 30);
500         
501         atcFreqDisplayFrame->setSize(400, hsize);
502         
503         atcFreqDisplayMessage -> setPosition (40, (hsize - 30));
504         atcFreqDisplayMessage -> setValue    (label.c_str());
505         atcFreqDisplayMessage -> getValue    (&s);
506         atcFreqDisplayMessage -> setLabel    (s);
507         
508         for(int i=0; i<n; ++i) {
509                 atcFreqDisplayText[i] -> setPosition(40, hsize - 65 - (30 * i));
510                 atcFreqDisplayText[i] -> setValue(freqs[i].c_str());
511                 atcFreqDisplayText[i] -> getValue (&s);
512                 atcFreqDisplayText[i] -> setLabel (s);
513                 atcFreqDisplayText[i] -> reveal();
514         }
515         for(int j=n; j<ATC_MAX_FREQ_DISPLAY; ++j) {
516                 atcFreqDisplayText[j] -> hide();
517         }
518         
519         FG_PUSH_PUI_DIALOG(atcFreqDisplay);
520         
521 }
522