4 XCSoar Glide Computer - http://www.xcsoar.org/
5 Copyright (C) 2000-2013 The XCSoar Project
6 A detailed list of copyright holders can be found in the file "AUTHORS".
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 This class is used to control all user and external InputEvents.
29 This includes some Nmea strings, virtual events (Glide Computer
32 What it does not cover is Glide Computer normal processing - this
33 includes GPS and Vario processing.
35 What it does include is what to do when an automatic event (switch
36 to Climb mode) and user events are entered.
38 It also covers the configuration side of on screen labels.
40 For further information on config file formats see
42 source/Common/Data/Input/ALL
43 doc/html/advanced/input/ALL http://xcsoar.sourceforge.net/advanced/input/
47 #include "InputEvents.hpp"
48 #include "Protection.hpp"
49 #include "LogFile.hpp"
50 #include "Device/Parser.hpp"
51 #include "UIState.hpp"
52 #include "Computer/Settings.hpp"
53 #include "MapSettings.hpp"
54 #include "Math/FastMath.h"
55 #include "Dialogs/Dialogs.h"
56 #include "Dialogs/Device/Vega/VoiceSettingsDialog.hpp"
57 #include "Dialogs/Device/Vega/SwitchesDialog.hpp"
58 #include "Dialogs/Airspace/Airspace.hpp"
59 #include "Dialogs/Task/TaskDialogs.hpp"
60 #include "Dialogs/Traffic/TrafficDialogs.hpp"
61 #include "Dialogs/Waypoint/WaypointDialogs.hpp"
62 #include "Dialogs/Weather/WeatherDialogs.hpp"
63 #include "Dialogs/Plane/PlaneDialogs.hpp"
64 #include "Dialogs/Message.hpp"
65 #include "Dialogs/dlgAnalysis.hpp"
66 #include "Dialogs/FileManager.hpp"
67 #include "Dialogs/ReplayDialog.hpp"
68 #include "Message.hpp"
69 #include "Markers/ProtectedMarkers.hpp"
70 #include "InfoBoxes/InfoBoxLayout.hpp"
71 #include "MainWindow.hpp"
72 #include "Projection/MapWindowProjection.hpp"
73 #include "Gauge/GaugeFLARM.hpp"
74 #include "Profile/Profile.hpp"
75 #include "Profile/ProfileKeys.hpp"
76 #include "Util/StringUtil.hpp"
77 #include "Audio/Sound.hpp"
78 #include "UIActions.hpp"
79 #include "Interface.hpp"
80 #include "ActionInterface.hpp"
81 #include "Components.hpp"
82 #include "Language/Language.hpp"
83 #include "Logger/Logger.hpp"
85 #include "Logger/NMEALogger.hpp"
86 #include "Waypoint/Waypoints.hpp"
87 #include "Task/ProtectedTaskManager.hpp"
88 #include "Blackboard/DeviceBlackboard.hpp"
89 #include "UtilsSettings.hpp"
90 #include "PageActions.hpp"
91 #include "Hardware/AltairControl.hpp"
92 #include "NMEA/Aircraft.hpp"
94 #include "Weather/Features.hpp"
95 #include "MapWindow/GlueMapWindow.hpp"
96 #include "Simulator.hpp"
106 if (!CommonInterface::Basic().location_available
)
111 // -----------------------------------------------------------------------
112 // Execution - list of things you can do
113 // -----------------------------------------------------------------------
116 // TODO code: Keep marker text for use in log file etc.
118 InputEvents::eventMarkLocation(const TCHAR
*misc
)
120 const NMEAInfo
&basic
= CommonInterface::Basic();
122 if (StringIsEqual(misc
, _T("reset"))) {
123 protected_marks
->Reset();
125 protected_marks
->MarkLocation(basic
.location
, basic
.date_time_utc
);
127 if (CommonInterface::GetUISettings().sound
.sound_modes_enabled
)
128 PlayResource(_T("IDR_WAV_CLEAR"));
135 InputEvents::eventScreenModes(const TCHAR
*misc
)
137 // toggle switches like this:
139 // -- auxiliary infobox
143 const UIState
&ui_state
= CommonInterface::GetUIState();
145 if (StringIsEqual(misc
, _T("normal"))) {
146 PageActions::OpenLayout(PageLayout::Default());
147 } else if (StringIsEqual(misc
, _T("auxilary"))) {
148 PageActions::OpenLayout(PageLayout::Aux());
149 } else if (StringIsEqual(misc
, _T("toggleauxiliary"))) {
150 PageActions::OpenLayout(ui_state
.auxiliary_enabled
151 ? PageLayout::Default()
152 : PageLayout::Aux());
153 } else if (StringIsEqual(misc
, _T("full"))) {
154 PageActions::OpenLayout(PageLayout::FullScreen());
155 } else if (StringIsEqual(misc
, _T("togglefull"))) {
156 CommonInterface::main_window
->SetFullScreen(
157 !CommonInterface::main_window
->GetFullScreen());
158 } else if (StringIsEqual(misc
, _T("show"))) {
159 if (CommonInterface::main_window
->GetFullScreen())
160 Message::AddMessage(_("Screen Mode Full"));
161 else if (ui_state
.auxiliary_enabled
)
162 Message::AddMessage(_("Auxiliary InfoBoxes"));
164 Message::AddMessage(_("Default InfoBoxes"));
165 } else if (StringIsEqual(misc
, _T("previous")))
174 // ClearStatusMessages
175 // Do Clear Event Warnings
177 InputEvents::eventClearStatusMessages(gcc_unused
const TCHAR
*misc
)
179 // TODO enhancement: allow selection of specific messages (here we are acknowledging all)
180 CommonInterface::main_window
->popup
.Acknowledge();
184 // Sets the current event mode.
185 // The argument is the label of the mode to activate.
186 // This is used to activate menus/submenus of buttons
188 InputEvents::eventMode(const TCHAR
*misc
)
190 assert(misc
!= NULL
);
192 CommonInterface::main_window
->SetDefaultFocus();
194 InputEvents::setMode(misc
);
197 // Don't think we need this.
199 InputEvents::eventMainMenu(gcc_unused
const TCHAR
*misc
)
201 // todo: popup main menu
205 // Displays the checklist dialog
206 // See the checklist dialog section of the reference manual for more info.
208 InputEvents::eventChecklist(gcc_unused
const TCHAR
*misc
)
210 dlgChecklistShowModal();
214 // Displays one of the three status dialogs:
215 // system: display the system status
216 // aircraft: displays the aircraft status
217 // task: displays the task status
218 // See the status dialog section of the reference manual for more info
221 InputEvents::eventStatus(const TCHAR
*misc
)
223 if (StringIsEqual(misc
, _T("system"))) {
224 dlgStatusShowModal(1);
225 } else if (StringIsEqual(misc
, _T("task"))) {
226 dlgStatusShowModal(2);
227 } else if (StringIsEqual(misc
, _T("aircraft"))) {
228 dlgStatusShowModal(0);
230 dlgStatusShowModal(-1);
235 // Displays the analysis/statistics dialog
236 // See the analysis dialog section of the reference manual
239 InputEvents::eventAnalysis(gcc_unused
const TCHAR
*misc
)
241 dlgAnalysisShowModal(*CommonInterface::main_window
,
242 CommonInterface::main_window
->GetLook(),
243 CommonInterface::Full(),
245 protected_task_manager
,
251 // Displays waypoint details
252 // current: the current active waypoint
253 // select: brings up the waypoint selector, if the user then
254 // selects a waypoint, then the details dialog is shown.
255 // See the waypoint dialog section of the reference manual
258 InputEvents::eventWaypointDetails(const TCHAR
*misc
)
260 const NMEAInfo
&basic
= CommonInterface::Basic();
261 const Waypoint
* wp
= NULL
;
263 if (StringIsEqual(misc
, _T("current"))) {
264 if (protected_task_manager
== NULL
)
267 wp
= protected_task_manager
->GetActiveWaypoint();
269 Message::AddMessage(_("No active waypoint!"));
272 } else if (StringIsEqual(misc
, _T("select"))) {
273 wp
= ShowWaypointListDialog(basic
.location
);
276 dlgWaypointDetailsShowModal(*wp
);
280 // Displays a user defined status message.
281 // The argument is the text to be displayed.
282 // No punctuation characters are allowed.
284 InputEvents::eventStatusMessage(const TCHAR
*misc
)
287 Message::AddMessage(gettext(misc
));
290 // Plays a sound from the filename
292 InputEvents::eventPlaySound(const TCHAR
*misc
)
298 InputEvents::eventAutoLogger(const TCHAR
*misc
)
303 LoggerSettings::AutoLogger auto_logger
=
304 CommonInterface::GetComputerSettings().logger
.auto_logger
;
306 if (auto_logger
== LoggerSettings::AutoLogger::OFF
)
309 if (auto_logger
== LoggerSettings::AutoLogger::START_ONLY
&&
310 !StringIsEqual(misc
, _T("start")))
317 // Activates the internal IGC logger
318 // start: starts the logger
319 // start ask: starts the logger after asking the user to confirm
320 // stop: stops the logger
321 // stop ask: stops the logger after asking the user to confirm
322 // toggle: toggles between on and off
323 // toggle ask: toggles between on and off, asking the user to confirm
324 // show: displays a status message indicating whether the logger is active
325 // nmea: turns on and off NMEA logging
326 // note: the text following the 'note' characters is added to the log file
328 InputEvents::eventLogger(const TCHAR
*misc
)
330 if (logger
== nullptr)
333 // TODO feature: start logger without requiring feedback
334 // start stop toggle addnote
336 const NMEAInfo
&basic
= CommonInterface::Basic();
337 const ComputerSettings
&settings_computer
=
338 CommonInterface::GetComputerSettings();
340 if (StringIsEqual(misc
, _T("start ask")))
341 logger
->GUIStartLogger(basic
, settings_computer
,
342 protected_task_manager
);
343 else if (StringIsEqual(misc
, _T("start")))
344 logger
->GUIStartLogger(basic
, settings_computer
,
345 protected_task_manager
, true);
346 else if (StringIsEqual(misc
, _T("stop ask")))
347 logger
->GUIStopLogger(basic
);
348 else if (StringIsEqual(misc
, _T("stop")))
349 logger
->GUIStopLogger(basic
, true);
350 else if (StringIsEqual(misc
, _T("toggle ask")))
351 logger
->GUIToggleLogger(basic
, settings_computer
,
352 protected_task_manager
);
353 else if (StringIsEqual(misc
, _T("toggle")))
354 logger
->GUIToggleLogger(basic
, settings_computer
,
355 protected_task_manager
, true);
356 else if (StringIsEqual(misc
, _T("nmea"))) {
357 NMEALogger::enabled
= !NMEALogger::enabled
;
358 if (NMEALogger::enabled
) {
359 Message::AddMessage(_("NMEA log on"));
361 Message::AddMessage(_("NMEA log off"));
363 } else if (StringIsEqual(misc
, _T("show")))
364 if (logger
->IsLoggerActive()) {
365 Message::AddMessage(_("Logger on"));
367 Message::AddMessage(_("Logger off"));
369 else if (_tcsncmp(misc
, _T("note"), 4))
370 // add note to logger file if available..
371 logger
->LoggerNote(misc
+ 4);
374 // RepeatStatusMessage
375 // Repeats the last status message. If pressed repeatedly, will
376 // repeat previous status messages
378 InputEvents::eventRepeatStatusMessage(gcc_unused
const TCHAR
*misc
)
381 // TODO enhancement: display only by type specified in misc field
382 CommonInterface::main_window
->popup
.Repeat();
385 // NearestWaypointDetails
386 // Displays the waypoint details dialog
387 // aircraft: the waypoint nearest the aircraft
388 // pan: the waypoint nearest to the pan cursor
390 InputEvents::eventNearestWaypointDetails(const TCHAR
*misc
)
392 if (StringIsEqual(misc
, _T("aircraft")))
394 PopupNearestWaypointDetails(way_points
, CommonInterface::Basic().location
,
396 else if (StringIsEqual(misc
, _T("pan"))) {
397 const Projection
&projection
=
398 CommonInterface::main_window
->GetProjection();
401 if (projection
.IsValid())
402 PopupNearestWaypointDetails(way_points
, projection
.GetGeoLocation(),
408 // Displays the map item list dialog
409 // aircraft: the map items to nearest the aircraft
410 // pan: the map items nearest to the pan cursor
412 InputEvents::eventNearestMapItems(const TCHAR
*misc
)
414 if (StringIsEqual(misc
, _T("aircraft")))
415 CommonInterface::main_window
->GetMap()->ShowMapItems(
416 CommonInterface::Basic().location
);
418 else if (StringIsEqual(misc
, _T("pan")))
419 CommonInterface::main_window
->GetMap()->ShowMapItems(
420 CommonInterface::main_window
->GetProjection().GetGeoLocation());
424 // The null event does nothing. This can be used to override
425 // default functionality
427 InputEvents::eventNull(gcc_unused
const TCHAR
*misc
)
433 InputEvents::eventBeep(gcc_unused
const TCHAR
*misc
)
436 altair_control
.ShortBeep();
438 MessageBeep(MB_ICONEXCLAMATION
);
440 PlayResource(_T("IDR_WAV_CLEAR"));
445 // Activates configuration and setting dialogs
446 // Basic: Basic settings (QNH/Bugs/Ballast/MaxTemperature)
447 // Wind: Wind settings
449 // Airspace: Airspace filter settings
450 // Replay: IGC replay dialog
452 InputEvents::eventSetup(const TCHAR
*misc
)
454 if (StringIsEqual(misc
, _T("Basic")))
455 dlgBasicSettingsShowModal();
456 else if (StringIsEqual(misc
, _T("Wind")))
457 ShowWindSettingsDialog();
458 else if (StringIsEqual(misc
, _T("System")))
459 SystemConfiguration();
460 else if (StringIsEqual(misc
, _T("Task")))
461 dlgTaskManagerShowModal(*CommonInterface::main_window
);
462 else if (StringIsEqual(misc
, _T("Airspace")))
463 dlgAirspaceShowModal(false);
464 else if (StringIsEqual(misc
, _T("Weather")))
465 dlgWeatherShowModal();
466 else if (StringIsEqual(misc
, _T("Replay"))) {
467 if (!CommonInterface::MovementDetected())
469 } else if (StringIsEqual(misc
, _T("Switches")))
470 dlgSwitchesShowModal();
471 else if (StringIsEqual(misc
, _T("Voice")))
473 else if (StringIsEqual(misc
, _T("Teamcode")))
474 dlgTeamCodeShowModal();
475 else if (StringIsEqual(misc
, _T("Target")))
476 dlgTargetShowModal();
477 else if (StringIsEqual(misc
, _T("Plane")))
478 dlgPlanesShowModal();
479 else if (StringIsEqual(misc
, _T("Alternates")))
480 dlgAlternatesListShowModal();
486 InputEvents::eventCredits(gcc_unused
const TCHAR
*misc
)
488 dlgCreditsShowModal(*CommonInterface::main_window
);
492 // Runs an external program of the specified filename.
493 // Note that XCSoar will wait until this program exits.
495 InputEvents::eventRun(const TCHAR
*misc
)
498 PROCESS_INFORMATION pi
;
499 if (!::CreateProcess(misc
, NULL
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, NULL
, &pi
))
502 // wait for program to finish!
503 ::WaitForSingleObject(pi
.hProcess
, INFINITE
);
504 ::CloseHandle(pi
.hProcess
);
505 ::CloseHandle(pi
.hThread
);
513 InputEvents::eventBrightness(gcc_unused
const TCHAR
*misc
)
515 dlgBrightnessShowModal();
519 InputEvents::eventExit(gcc_unused
const TCHAR
*misc
)
521 UIActions::SignalShutdown(false);
525 InputEvents::eventUserDisplayModeForce(const TCHAR
*misc
)
527 UIState
&ui_state
= CommonInterface::SetUIState();
529 if (StringIsEqual(misc
, _T("unforce")))
530 ui_state
.force_display_mode
= DisplayMode::NONE
;
531 else if (StringIsEqual(misc
, _T("forceclimb")))
532 ui_state
.force_display_mode
= DisplayMode::CIRCLING
;
533 else if (StringIsEqual(misc
, _T("forcecruise")))
534 ui_state
.force_display_mode
= DisplayMode::CRUISE
;
535 else if (StringIsEqual(misc
, _T("forcefinal")))
536 ui_state
.force_display_mode
= DisplayMode::FINAL_GLIDE
;
538 ActionInterface::UpdateDisplayMode();
539 ActionInterface::SendUIState();
543 InputEvents::eventAddWaypoint(const TCHAR
*misc
)
545 const NMEAInfo
&basic
= CommonInterface::Basic();
546 const DerivedInfo
&calculated
= CommonInterface::Calculated();
548 if (StringIsEqual(misc
, _T("takeoff"))) {
549 if (basic
.location_available
&& calculated
.terrain_valid
) {
550 ScopeSuspendAllThreads suspend
;
551 way_points
.AddTakeoffPoint(basic
.location
, calculated
.terrain_altitude
);
552 way_points
.Optimise();
555 Waypoint edit_waypoint
= way_points
.Create(basic
.location
);
556 edit_waypoint
.elevation
= calculated
.terrain_altitude
;
557 if (!dlgWaypointEditShowModal(edit_waypoint
) || edit_waypoint
.name
.empty()) {
562 ScopeSuspendAllThreads suspend
;
563 way_points
.Append(std::move(edit_waypoint
));
564 way_points
.Optimise();
571 // JMW TODO enhancement: have all inputevents return bool, indicating whether
572 // the button should after processing be hilit or not.
573 // this allows the buttons to indicate whether things are enabled/disabled
574 // SDP TODO enhancement: maybe instead do conditional processing ?
575 // I like this idea; if one returns false, then don't execute the
578 // JMW TODO enhancement: make sure when we change things here we also set registry values...
579 // or maybe have special tag "save" which indicates it should be saved (notice that
580 // the wind adjustment uses this already, see in Process.cpp)
584 eventTaskLoad - Load tasks from a file (misc = filename)
585 eventTaskSave - Save tasks to a file (misc = filename)
586 eventProfileLoad - Load profile from a file (misc = filename)
587 eventProfileSave - Save profile to a file (misc = filename)
591 /* TODO feature: - new events
593 eventPanWaypoint - Set pan to a waypoint
594 - Waypoint could be "next", "first", "last", "previous", or named
595 - Note: wrong name - probably just part of eventPan
596 eventPressure - Increase, Decrease, show, Set pressure value
597 eventDeclare - (JMW separate from internal logger)
598 eventAirspaceDisplay - all, below nnn, below me, auto nnn
599 eventAirspaceWarnings- on, off, time nn, ack nn
600 eventTerrain - see map_window.Event_Terrain
601 eventCompass - on, off, cruise on, crusie off, climb on, climb off
602 eventVario - on, off // JMW what does this do?
603 eventOrientation - north, track, ???
604 eventTerrainRange - on, off (might be part of eventTerrain)
605 eventSounds - Include Task and Modes sounds along with Vario
606 - Include master nn, deadband nn, netto trigger mph/kts/...
613 InputEvents::eventWeather(const TCHAR
*misc
)
616 if (StringIsEqual(misc
, _T("list")))
617 dlgNOAAListShowModal();
622 InputEvents::eventQuickMenu(gcc_unused
const TCHAR
*misc
)
624 dlgQuickMenuShowModal(*CommonInterface::main_window
);
628 InputEvents::eventFileManager(const TCHAR
*misc
)