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 "ATCdisplay.hxx"
32 #include "commlist.hxx"
33 #include "ATCutils.hxx"
34 #include <Airports/simple.hxx>
38 SG_USING_STD(ostringstream);
40 FGATCDialog *current_atcdialog;
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();
48 static bool do_ATC_freq_search(const SGPropertyNode* arg) {
49 current_atcdialog->FreqDialog();
53 ATCMenuEntry::ATCMenuEntry() {
61 ATCMenuEntry::~ATCMenuEntry() {
64 static void atcUppercase(string &s) {
65 for(unsigned int i=0; i<s.size(); ++i) {
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 // --------------------------------------------------------------
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
82 static puDialogBox* atcFreqDialog;
83 static puFrame* atcFreqDialogFrame;
84 static puText* atcFreqDialogMessage;
85 static puInput* atcFreqDialogInput;
86 static puOneShot* atcFreqDialogOkButton;
87 static puOneShot* atcFreqDialogCancelButton;
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 // --------------------------------------------------------------
96 //////////////// Popup callbacks ///////////////////
97 static void ATCDialogOK(puObject*) {
98 current_atcdialog->PopupCallback();
99 FG_POP_PUI_DIALOG( atcDialog );
102 static void ATCDialogCancel(puObject*) {
103 FG_POP_PUI_DIALOG( atcDialog );
105 //////////////////////////////////////////////////
108 ///////////////// Freq search callbacks ///////////
109 static void FreqDialogCancel(puObject*) {
110 FG_POP_PUI_DIALOG(atcFreqDialog);
113 static void FreqDialogOK(puObject*) {
114 string tmp = atcFreqDialogInput->getStringValue();
115 FG_POP_PUI_DIALOG(atcFreqDialog);
116 current_atcdialog->FreqDisplay(tmp);
119 static void FreqDisplayOK(puObject*) {
120 FG_POP_PUI_DIALOG(atcFreqDisplay);
122 //////////////////////////////////////////////////
125 FGATCDialog::FGATCDialog() {
126 _callbackPending = false;
127 _callbackTimer = 0.0;
133 FGATCDialog::~FGATCDialog() {
134 if(atcDialog) puDeleteObject(atcDialog);
135 if(atcFreqDialog) puDeleteObject(atcFreqDialog);
136 if(atcFreqDisplay) puDeleteObject(atcFreqDisplay);
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);
150 // Init the freq-search dialog
153 x = (fgGetInt("/sim/startup/xsize") / 2) - (w / 2);
156 atcFreqDialog = new puDialogBox (x, y);
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);
164 atcFreqDialogInput = new puInput (50, (h - 75), 150, (h - 45));
166 atcFreqDialogOkButton = new puOneShot (50, 10, 110, 50);
167 atcFreqDialogOkButton -> setLegend (gui_msg_OK);
168 atcFreqDialogOkButton -> makeReturnDefault (TRUE);
169 atcFreqDialogOkButton -> setCallback (FreqDialogOK);
171 atcFreqDialogCancelButton = new puOneShot (140, 10, 210, 50);
172 atcFreqDialogCancelButton -> setLegend (gui_msg_CANCEL);
173 atcFreqDialogCancelButton -> setCallback (FreqDialogCancel);
175 atcFreqDialogInput->acceptInput();
178 FG_FINALIZE_PUI_DIALOG(atcFreqDialog);
180 // Init the freq-display dialog
183 x = (fgGetInt("/sim/startup/xsize") / 2) - (w / 2);
185 atcFreqDisplay = new puDialogBox (x, y);
187 atcFreqDisplayFrame = new puFrame (0, 0, w, h);
189 atcFreqDisplayMessage = new puText (40, (h - 30));
190 atcFreqDisplayMessage -> setDefaultValue ("No freqencies found");
191 atcFreqDisplayMessage -> getDefaultValue (&s);
192 atcFreqDisplayMessage -> setLabel (s);
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();
202 atcFreqDisplayOkButton = new puOneShot (50, 10, 110, 50);
203 atcFreqDisplayOkButton -> setLegend (gui_msg_OK);
204 atcFreqDisplayOkButton -> makeReturnDefault (TRUE);
205 atcFreqDisplayOkButton -> setCallback (FreqDisplayOK);
207 FG_FINALIZE_PUI_DIALOG(atcFreqDisplay);
209 // Init AK's interactive ATC menus
212 x = (fgGetInt("/sim/startup/xsize") / 2) - (w / 2);
213 //y = (fgGetInt("/sim/startup/ysize") / 2) - (h / 2);
215 atcDialog = new puDialogBox (x, y);
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);
228 atcDialogCancelButton = new puOneShot ((w/2)+25, 10, (w/2)+85, 50);
229 atcDialogCancelButton -> setLegend (gui_msg_CANCEL);
230 atcDialogCancelButton -> setCallback (ATCDialogCancel);
232 FG_FINALIZE_PUI_DIALOG(atcDialog);
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;
242 _callbackTimer += dt;
248 void FGATCDialog::add_entry(string station, string transmission, string menutext, atc_type type, int code) {
252 a.stationid = station;
253 a.transmission = transmission;
254 a.menuentry = menutext;
255 a.callback_code = code;
257 (available_dialog[type])[station.c_str()].push_back(a);
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);
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);
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;
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;
299 // Display the ATC popup dialog box with options relevant to the users current situation.
300 void FGATCDialog::PopupDialog() {
302 static string mentry[10];
303 static string mtrans[10];
306 FGATC* atcptr = globals->get_ATC_mgr()->GetComm1ATCPointer(); // Hardwired to comm1 at the moment
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);
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();
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);
334 int k = atcmlist.size();
336 //cout << "k = " << k << '\n';
338 atcDialogFrame->setSize(w, h);
341 // loop over all entries in atcmentrylist
342 char** optList = new char*[k+1];
344 for ( ; current != last ; ++current ) {
346 sprintf( buf, "%i", kk+1 );
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;
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);
363 atcDialogCommunicationOptions->hide();
364 atcDialogMessage -> setLabel( "No transmission available" );
365 atcDialogMessage -> setPosition(w / 2, h - 30);
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);
375 FG_PUSH_PUI_DIALOG(atcDialog);
378 void FGATCDialog::PopupCallback() {
379 FGATC* atcptr = globals->get_ATC_mgr()->GetComm1ATCPointer(); // FIXME - Hardwired to comm1 at the moment
382 if(atcptr->GetType() == APPROACH) {
383 switch(atcDialogCommunicationOptions->getValue()) {
385 fgSetBool("/sim/atc/opt0",true);
388 fgSetBool("/sim/atc/opt1",true);
391 fgSetBool("/sim/atc/opt2",true);
394 fgSetBool("/sim/atc/opt3",true);
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;
412 _callbackPtr = atcptr;
413 _callbackCode = a.callback_code;
415 //cout << "No options available...\n";
417 //cout << "Donded" << endl;
422 void FGATCDialog::FreqDialog() {
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;
428 //double lon = fgGetDouble("/position/longitude-deg");
429 //double lat = fgGetDouble("/position/latitude-deg");
430 //double elev = fgGetDouble("/position/altitude-ft");
433 // search stations in range
434 int num_stat = current_commlist->FindByPos(lon, lat, elev, 40.0, &atc_stations);
437 // Make up a message saying no things in range
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).
444 atcFreqDialogInput->setValue("");
445 atcFreqDialogInput->acceptInput();
446 FG_PUSH_PUI_DIALOG(atcFreqDialog);
449 void FGATCDialog::FreqDisplay(string ident) {
456 int n = 0; // Number of ATC frequencies at this airport
457 string freqs[ATC_MAX_FREQ_DISPLAY];
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);
466 comm_list_iterator itr = stations.begin();
467 while(itr != stations.end()) {
468 if((*itr).ident == ident) {
469 if((*itr).type != INVALID) {
471 freqs[n] = ostr.str();
472 freqs[n].append(" - ");
473 sprintf(buf, "%.2f", ((*itr).freq / 100.0)); // Convert from KHz to MHz
475 if(buf[5] == '3') buf[5] = '2';
476 if(buf[5] == '8') buf[5] = '7';
486 label = "No frequencies found for airport ";
489 label = "Frequencies for airport ";
496 label += " not found in database.";
499 int hsize = 105 + (n * 30);
501 atcFreqDisplayFrame->setSize(400, hsize);
503 atcFreqDisplayMessage -> setPosition (40, (hsize - 30));
504 atcFreqDisplayMessage -> setValue (label.c_str());
505 atcFreqDisplayMessage -> getValue (&s);
506 atcFreqDisplayMessage -> setLabel (s);
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();
515 for(int j=n; j<ATC_MAX_FREQ_DISPLAY; ++j) {
516 atcFreqDisplayText[j] -> hide();
519 FG_PUSH_PUI_DIALOG(atcFreqDisplay);