I'm attaching diffs to add a new FGInput module to FlightGear
(src/Input). So far, FGInput replaces most of src/Main/keyboard.cxx
(I've left a tiny stub); in the very near future, it will also take
over control of the joystick, mouse (Norm permitting), and panel
instrument interactions, so that there is a single mechanism for
configuring all input devices.
The new format should be (close to) self-explanatory by looking at the
new base-package file keyboard.xml, which is now included by
preferences.xml (I'll do the same thing for the joystick when I have a
chance). I have not managed to move all keybindings into this file
yet, but I've made a good start. I'm including Tony in the recipient
list so that he can see how bindings can use an external XML file.
This patch also adds support for multiple bindings for a single key,
special keys (i.e. keypad and function keys), and key modifiers
(shift/alt/ctrl); special keys use the PUI convention of adding 256 to
the Glut key code.
Unfortunately, everything comes with a price; in this case, I have not
yet found a general mechanism for the old (hard-coded) modal bindings,
which behaved differently depending on the autopilot state (i.e. left
rudder or move AP heading left); with my patches, this functionality
disappears, but you can still adjust the autopilot using the panel or
the GUI input dialogs.
2001-05-23 23:01:15 +00:00
|
|
|
|
// fg_props.cxx -- support for FlightGear properties.
|
2001-01-05 17:37:59 +00:00
|
|
|
|
//
|
I'm attaching diffs to add a new FGInput module to FlightGear
(src/Input). So far, FGInput replaces most of src/Main/keyboard.cxx
(I've left a tiny stub); in the very near future, it will also take
over control of the joystick, mouse (Norm permitting), and panel
instrument interactions, so that there is a single mechanism for
configuring all input devices.
The new format should be (close to) self-explanatory by looking at the
new base-package file keyboard.xml, which is now included by
preferences.xml (I'll do the same thing for the joystick when I have a
chance). I have not managed to move all keybindings into this file
yet, but I've made a good start. I'm including Tony in the recipient
list so that he can see how bindings can use an external XML file.
This patch also adds support for multiple bindings for a single key,
special keys (i.e. keypad and function keys), and key modifiers
(shift/alt/ctrl); special keys use the PUI convention of adding 256 to
the Glut key code.
Unfortunately, everything comes with a price; in this case, I have not
yet found a general mechanism for the old (hard-coded) modal bindings,
which behaved differently depending on the autopilot state (i.e. left
rudder or move AP heading left); with my patches, this functionality
disappears, but you can still adjust the autopilot using the panel or
the GUI input dialogs.
2001-05-23 23:01:15 +00:00
|
|
|
|
// Written by David Megginson, started 2000.
|
2001-01-05 17:37:59 +00:00
|
|
|
|
//
|
I'm attaching diffs to add a new FGInput module to FlightGear
(src/Input). So far, FGInput replaces most of src/Main/keyboard.cxx
(I've left a tiny stub); in the very near future, it will also take
over control of the joystick, mouse (Norm permitting), and panel
instrument interactions, so that there is a single mechanism for
configuring all input devices.
The new format should be (close to) self-explanatory by looking at the
new base-package file keyboard.xml, which is now included by
preferences.xml (I'll do the same thing for the joystick when I have a
chance). I have not managed to move all keybindings into this file
yet, but I've made a good start. I'm including Tony in the recipient
list so that he can see how bindings can use an external XML file.
This patch also adds support for multiple bindings for a single key,
special keys (i.e. keypad and function keys), and key modifiers
(shift/alt/ctrl); special keys use the PUI convention of adding 256 to
the Glut key code.
Unfortunately, everything comes with a price; in this case, I have not
yet found a general mechanism for the old (hard-coded) modal bindings,
which behaved differently depending on the autopilot state (i.e. left
rudder or move AP heading left); with my patches, this functionality
disappears, but you can still adjust the autopilot using the panel or
the GUI input dialogs.
2001-05-23 23:01:15 +00:00
|
|
|
|
// Copyright (C) 2000, 2001 David Megginson - david@megginson.com
|
2001-01-05 17:37:59 +00:00
|
|
|
|
//
|
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
|
|
|
// modify it under the terms of the GNU General Public License as
|
|
|
|
|
// published by the Free Software Foundation; either version 2 of the
|
|
|
|
|
// License, or (at your option) any later version.
|
|
|
|
|
//
|
|
|
|
|
// This program is distributed in the hope that it will be useful, but
|
|
|
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
// General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
|
// along with this program; if not, write to the Free Software
|
|
|
|
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
//
|
|
|
|
|
// $Id$
|
|
|
|
|
|
2001-04-02 02:59:31 +00:00
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
# include <simgear/compiler.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2001-07-19 04:51:05 +00:00
|
|
|
|
#include <simgear/misc/exception.hxx>
|
2002-03-16 00:18:38 +00:00
|
|
|
|
#include <simgear/magvar/magvar.hxx>
|
|
|
|
|
#include <simgear/timing/sg_time.hxx>
|
2001-07-19 04:51:05 +00:00
|
|
|
|
|
2001-04-02 02:59:31 +00:00
|
|
|
|
#include STL_IOSTREAM
|
2001-01-05 17:37:59 +00:00
|
|
|
|
|
2001-12-11 22:40:14 +00:00
|
|
|
|
#include <ATC/ATCdisplay.hxx>
|
2001-06-05 22:13:26 +00:00
|
|
|
|
#include <Aircraft/aircraft.hxx>
|
|
|
|
|
#include <Time/tmp.hxx>
|
|
|
|
|
#include <FDM/UIUCModel/uiuc_aircraftdir.h>
|
2002-02-19 15:16:08 +00:00
|
|
|
|
#ifndef FG_NEW_ENVIRONMENT
|
2001-06-05 22:13:26 +00:00
|
|
|
|
# include <WeatherCM/FGLocalWeatherDatabase.h>
|
|
|
|
|
#else
|
2002-02-19 15:16:08 +00:00
|
|
|
|
# include <Environment/environment.hxx>
|
|
|
|
|
#endif // FG_NEW_ENVIRONMENT
|
2001-06-26 21:59:59 +00:00
|
|
|
|
#include <Objects/matlib.hxx>
|
2001-06-05 22:13:26 +00:00
|
|
|
|
|
2001-07-19 04:51:05 +00:00
|
|
|
|
#include <GUI/gui.h>
|
2002-04-19 04:00:02 +00:00
|
|
|
|
#include <Sound/soundmgr.hxx>
|
2001-07-19 04:51:05 +00:00
|
|
|
|
|
2002-01-06 16:51:31 +00:00
|
|
|
|
#include "globals.hxx"
|
2001-06-05 22:13:26 +00:00
|
|
|
|
#include "fgfs.hxx"
|
2001-01-05 17:37:59 +00:00
|
|
|
|
#include "fg_props.hxx"
|
|
|
|
|
|
2001-04-02 02:59:31 +00:00
|
|
|
|
#if !defined(SG_HAVE_NATIVE_SGI_COMPILERS)
|
|
|
|
|
SG_USING_STD(istream);
|
|
|
|
|
SG_USING_STD(ostream);
|
|
|
|
|
#endif
|
2001-01-05 17:37:59 +00:00
|
|
|
|
|
2002-02-19 15:16:08 +00:00
|
|
|
|
#if !defined(FG_NEW_ENVIRONMENT)
|
2001-06-05 22:13:26 +00:00
|
|
|
|
static double getWindNorth ();
|
|
|
|
|
static double getWindEast ();
|
|
|
|
|
static double getWindDown ();
|
2002-02-19 15:16:08 +00:00
|
|
|
|
#endif // FG_NEW_ENVIRONMENT
|
2001-06-05 22:13:26 +00:00
|
|
|
|
|
2001-10-05 20:27:43 +00:00
|
|
|
|
static bool winding_ccw = true; // FIXME: temporary
|
2001-07-16 04:35:35 +00:00
|
|
|
|
|
|
|
|
|
static bool fdm_data_logging = false; // FIXME: temporary
|
|
|
|
|
|
2002-04-19 04:00:02 +00:00
|
|
|
|
static bool frozen = false; // FIXME: temporary
|
|
|
|
|
|
2001-07-16 04:35:35 +00:00
|
|
|
|
|
2001-06-05 22:13:26 +00:00
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Default property bindings (not yet handled by any module).
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2001-11-20 22:03:17 +00:00
|
|
|
|
struct LogClassMapping {
|
|
|
|
|
sgDebugClass c;
|
|
|
|
|
string name;
|
2001-12-09 05:20:13 +00:00
|
|
|
|
LogClassMapping(sgDebugClass cc, string nname) { c = cc; name = nname; }
|
2001-11-20 22:03:17 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
LogClassMapping log_class_mappings [] = {
|
2001-12-09 05:20:13 +00:00
|
|
|
|
LogClassMapping(SG_NONE, "none"),
|
|
|
|
|
LogClassMapping(SG_TERRAIN, "terrain"),
|
|
|
|
|
LogClassMapping(SG_ASTRO, "astro"),
|
|
|
|
|
LogClassMapping(SG_FLIGHT, "flight"),
|
|
|
|
|
LogClassMapping(SG_INPUT, "input"),
|
|
|
|
|
LogClassMapping(SG_GL, "gl"),
|
|
|
|
|
LogClassMapping(SG_VIEW, "view"),
|
|
|
|
|
LogClassMapping(SG_COCKPIT, "cockpit"),
|
|
|
|
|
LogClassMapping(SG_GENERAL, "general"),
|
|
|
|
|
LogClassMapping(SG_MATH, "math"),
|
|
|
|
|
LogClassMapping(SG_EVENT, "event"),
|
|
|
|
|
LogClassMapping(SG_AIRCRAFT, "aircraft"),
|
|
|
|
|
LogClassMapping(SG_AUTOPILOT, "autopilot"),
|
|
|
|
|
LogClassMapping(SG_IO, "io"),
|
|
|
|
|
LogClassMapping(SG_CLIPPER, "clipper"),
|
|
|
|
|
LogClassMapping(SG_NETWORK, "network"),
|
|
|
|
|
LogClassMapping(SG_UNDEFD, "")
|
2001-11-20 22:03:17 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the logging classes.
|
|
|
|
|
*/
|
2002-03-19 17:12:13 +00:00
|
|
|
|
static const char *
|
2001-11-20 22:03:17 +00:00
|
|
|
|
getLoggingClasses ()
|
|
|
|
|
{
|
|
|
|
|
sgDebugClass classes = logbuf::get_log_classes();
|
2002-04-07 21:20:16 +00:00
|
|
|
|
static string result = ""; // FIXME
|
2001-11-20 22:03:17 +00:00
|
|
|
|
for (int i = 0; log_class_mappings[i].c != SG_UNDEFD; i++) {
|
|
|
|
|
if ((classes&log_class_mappings[i].c) > 0) {
|
2002-03-20 19:16:13 +00:00
|
|
|
|
if (!result.empty())
|
2001-11-20 22:03:17 +00:00
|
|
|
|
result += '|';
|
|
|
|
|
result += log_class_mappings[i].name;
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-03-19 17:12:13 +00:00
|
|
|
|
return result.c_str();
|
2001-11-20 22:03:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-03-19 17:12:13 +00:00
|
|
|
|
static void
|
|
|
|
|
addLoggingClass (const string &name)
|
2001-11-20 22:03:17 +00:00
|
|
|
|
{
|
|
|
|
|
sgDebugClass classes = logbuf::get_log_classes();
|
|
|
|
|
for (int i = 0; log_class_mappings[i].c != SG_UNDEFD; i++) {
|
|
|
|
|
if (name == log_class_mappings[i].name) {
|
|
|
|
|
logbuf::set_log_classes(sgDebugClass(classes|log_class_mappings[i].c));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
SG_LOG(SG_GENERAL, SG_ALERT, "Unknown logging class: " << name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set the logging classes.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2002-03-19 17:12:13 +00:00
|
|
|
|
setLoggingClasses (const char * c)
|
2001-11-20 22:03:17 +00:00
|
|
|
|
{
|
2002-03-19 17:12:13 +00:00
|
|
|
|
string classes = c;
|
2001-11-20 22:03:17 +00:00
|
|
|
|
logbuf::set_log_classes(SG_NONE);
|
|
|
|
|
|
|
|
|
|
if (classes == "none") {
|
|
|
|
|
SG_LOG(SG_GENERAL, SG_INFO, "Disabled all logging classes");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2002-03-20 19:16:13 +00:00
|
|
|
|
if (classes.empty() || classes == "all") { // default
|
2001-11-20 22:03:17 +00:00
|
|
|
|
logbuf::set_log_classes(SG_ALL);
|
|
|
|
|
SG_LOG(SG_GENERAL, SG_INFO, "Enabled all logging classes: "
|
|
|
|
|
<< getLoggingClasses());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string rest = classes;
|
|
|
|
|
string name = "";
|
|
|
|
|
int sep = rest.find('|');
|
|
|
|
|
while (sep > 0) {
|
|
|
|
|
name = rest.substr(0, sep);
|
|
|
|
|
rest = rest.substr(sep+1);
|
|
|
|
|
addLoggingClass(name);
|
|
|
|
|
sep = rest.find('|');
|
|
|
|
|
}
|
|
|
|
|
addLoggingClass(rest);
|
|
|
|
|
SG_LOG(SG_GENERAL, SG_INFO, "Set logging classes to "
|
|
|
|
|
<< getLoggingClasses());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the logging priority.
|
|
|
|
|
*/
|
2002-03-19 17:12:13 +00:00
|
|
|
|
static const char *
|
2001-11-20 22:03:17 +00:00
|
|
|
|
getLoggingPriority ()
|
|
|
|
|
{
|
|
|
|
|
switch (logbuf::get_log_priority()) {
|
|
|
|
|
case SG_BULK:
|
|
|
|
|
return "bulk";
|
|
|
|
|
case SG_DEBUG:
|
|
|
|
|
return "debug";
|
|
|
|
|
case SG_INFO:
|
|
|
|
|
return "info";
|
|
|
|
|
case SG_WARN:
|
|
|
|
|
return "warn";
|
|
|
|
|
case SG_ALERT:
|
|
|
|
|
return "alert";
|
|
|
|
|
default:
|
|
|
|
|
SG_LOG(SG_GENERAL, SG_WARN, "Internal: Unknown logging priority number: "
|
|
|
|
|
<< logbuf::get_log_priority());
|
|
|
|
|
return "unknown";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set the logging priority.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2002-03-19 17:12:13 +00:00
|
|
|
|
setLoggingPriority (const char * p)
|
2001-11-20 22:03:17 +00:00
|
|
|
|
{
|
2002-03-19 17:12:13 +00:00
|
|
|
|
string priority = p;
|
2001-11-20 22:03:17 +00:00
|
|
|
|
if (priority == "bulk") {
|
|
|
|
|
logbuf::set_log_priority(SG_BULK);
|
|
|
|
|
} else if (priority == "debug") {
|
|
|
|
|
logbuf::set_log_priority(SG_DEBUG);
|
2002-03-20 19:16:13 +00:00
|
|
|
|
} else if (priority.empty() || priority == "info") { // default
|
2001-11-20 22:03:17 +00:00
|
|
|
|
logbuf::set_log_priority(SG_INFO);
|
|
|
|
|
} else if (priority == "warn") {
|
|
|
|
|
logbuf::set_log_priority(SG_WARN);
|
|
|
|
|
} else if (priority == "alert") {
|
|
|
|
|
logbuf::set_log_priority(SG_ALERT);
|
|
|
|
|
} else {
|
|
|
|
|
SG_LOG(SG_GENERAL, SG_WARN, "Unknown logging priority " << priority);
|
|
|
|
|
}
|
|
|
|
|
SG_LOG(SG_GENERAL, SG_INFO, "Logging priority is " << getLoggingPriority());
|
|
|
|
|
}
|
|
|
|
|
|
2001-06-26 21:59:59 +00:00
|
|
|
|
|
2002-04-19 04:00:02 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return the current frozen state.
|
|
|
|
|
*/
|
|
|
|
|
static bool
|
|
|
|
|
getFreeze ()
|
|
|
|
|
{
|
|
|
|
|
return frozen;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set the current frozen state.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
setFreeze (bool f)
|
|
|
|
|
{
|
|
|
|
|
frozen = f;
|
|
|
|
|
// Stop sound on a pause
|
|
|
|
|
if (f)
|
|
|
|
|
globals->get_soundmgr()->pause();
|
|
|
|
|
else
|
|
|
|
|
globals->get_soundmgr()->resume();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2001-06-05 22:13:26 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return the current aircraft directory (UIUC) as a string.
|
|
|
|
|
*/
|
2002-03-19 17:12:13 +00:00
|
|
|
|
static const char *
|
2001-06-05 22:13:26 +00:00
|
|
|
|
getAircraftDir ()
|
|
|
|
|
{
|
2002-03-19 17:12:13 +00:00
|
|
|
|
return aircraft_dir.c_str();
|
2001-06-05 22:13:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set the current aircraft directory (UIUC).
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2002-03-19 17:12:13 +00:00
|
|
|
|
setAircraftDir (const char * dir)
|
2001-06-05 22:13:26 +00:00
|
|
|
|
{
|
2002-03-19 17:12:13 +00:00
|
|
|
|
aircraft_dir = dir;
|
2001-06-05 22:13:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-03-12 16:29:32 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return the number of milliseconds elapsed since simulation started.
|
|
|
|
|
*/
|
2002-04-20 14:52:43 +00:00
|
|
|
|
static double
|
2002-05-11 16:28:50 +00:00
|
|
|
|
getElapsedTime_sec ()
|
2002-03-12 16:29:32 +00:00
|
|
|
|
{
|
2002-05-11 16:28:50 +00:00
|
|
|
|
return globals->get_sim_time_sec();
|
2002-03-12 16:29:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2001-06-05 22:13:26 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return the current Zulu time.
|
|
|
|
|
*/
|
2002-03-19 17:12:13 +00:00
|
|
|
|
static const char *
|
2001-06-05 22:13:26 +00:00
|
|
|
|
getDateString ()
|
|
|
|
|
{
|
2002-04-07 21:20:16 +00:00
|
|
|
|
static char buf[64]; // FIXME
|
2001-06-05 22:13:26 +00:00
|
|
|
|
struct tm * t = globals->get_time_params()->getGmt();
|
|
|
|
|
sprintf(buf, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d",
|
|
|
|
|
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
|
|
|
|
|
t->tm_hour, t->tm_min, t->tm_sec);
|
2002-04-07 21:20:16 +00:00
|
|
|
|
return buf;
|
2001-06-05 22:13:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set the current Zulu time.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2002-03-19 17:12:13 +00:00
|
|
|
|
setDateString (const char * date_string)
|
2001-06-05 22:13:26 +00:00
|
|
|
|
{
|
2002-02-11 23:33:20 +00:00
|
|
|
|
static const SGPropertyNode *cur_time_override
|
|
|
|
|
= fgGetNode("/sim/time/cur-time-override", true);
|
|
|
|
|
|
2001-06-05 22:13:26 +00:00
|
|
|
|
SGTime * st = globals->get_time_params();
|
|
|
|
|
struct tm * current_time = st->getGmt();
|
|
|
|
|
struct tm new_time;
|
|
|
|
|
|
|
|
|
|
// Scan for basic ISO format
|
|
|
|
|
// YYYY-MM-DDTHH:MM:SS
|
2002-03-19 17:12:13 +00:00
|
|
|
|
int ret = sscanf(date_string, "%d-%d-%dT%d:%d:%d",
|
2001-06-05 22:13:26 +00:00
|
|
|
|
&(new_time.tm_year), &(new_time.tm_mon),
|
|
|
|
|
&(new_time.tm_mday), &(new_time.tm_hour),
|
|
|
|
|
&(new_time.tm_min), &(new_time.tm_sec));
|
|
|
|
|
|
|
|
|
|
// Be pretty picky about this, so
|
|
|
|
|
// that strange things don't happen
|
|
|
|
|
// if the save file has been edited
|
|
|
|
|
// by hand.
|
|
|
|
|
if (ret != 6) {
|
|
|
|
|
SG_LOG(SG_INPUT, SG_ALERT, "Date/time string " << date_string
|
|
|
|
|
<< " not in YYYY-MM-DDTHH:MM:SS format; skipped");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// OK, it looks like we got six
|
|
|
|
|
// values, one way or another.
|
|
|
|
|
new_time.tm_year -= 1900;
|
|
|
|
|
new_time.tm_mon -= 1;
|
|
|
|
|
|
|
|
|
|
// Now, tell flight gear to use
|
|
|
|
|
// the new time. This was far
|
|
|
|
|
// too difficult, by the way.
|
|
|
|
|
long int warp =
|
|
|
|
|
mktime(&new_time) - mktime(current_time) + globals->get_warp();
|
|
|
|
|
double lon = current_aircraft.fdm_state->get_Longitude();
|
|
|
|
|
double lat = current_aircraft.fdm_state->get_Latitude();
|
|
|
|
|
globals->set_warp(warp);
|
2002-02-11 23:33:20 +00:00
|
|
|
|
st->update(lon, lat, cur_time_override->getLongValue(), warp);
|
2001-06-05 22:13:26 +00:00
|
|
|
|
fgUpdateSkyAndLightingParams();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return the GMT as a string.
|
|
|
|
|
*/
|
2002-03-19 17:12:13 +00:00
|
|
|
|
static const char *
|
2001-06-05 22:13:26 +00:00
|
|
|
|
getGMTString ()
|
|
|
|
|
{
|
2002-04-07 21:20:16 +00:00
|
|
|
|
static char buf[16]; // FIXME
|
2002-02-11 23:33:20 +00:00
|
|
|
|
struct tm *t = globals->get_time_params()->getGmt();
|
2001-06-05 22:13:26 +00:00
|
|
|
|
sprintf(buf, " %.2d:%.2d:%.2d",
|
|
|
|
|
t->tm_hour, t->tm_min, t->tm_sec);
|
2002-02-11 23:33:20 +00:00
|
|
|
|
// cout << t << " " << buf << endl;
|
2002-04-07 21:20:16 +00:00
|
|
|
|
return buf;
|
2001-06-05 22:13:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-06-26 21:59:59 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the texture rendering state.
|
|
|
|
|
*/
|
|
|
|
|
static bool
|
|
|
|
|
getTextures ()
|
|
|
|
|
{
|
|
|
|
|
return (material_lib.get_step() == 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set the texture rendering state.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
setTextures (bool textures)
|
|
|
|
|
{
|
|
|
|
|
if (textures)
|
|
|
|
|
material_lib.set_step(0);
|
|
|
|
|
else
|
|
|
|
|
material_lib.set_step(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2001-06-05 22:13:26 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return the magnetic variation
|
|
|
|
|
*/
|
|
|
|
|
static double
|
|
|
|
|
getMagVar ()
|
|
|
|
|
{
|
|
|
|
|
return globals->get_mag()->get_magvar() * SGD_RADIANS_TO_DEGREES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return the magnetic dip
|
|
|
|
|
*/
|
|
|
|
|
static double
|
|
|
|
|
getMagDip ()
|
|
|
|
|
{
|
|
|
|
|
return globals->get_mag()->get_magdip() * SGD_RADIANS_TO_DEGREES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return the current heading in degrees.
|
|
|
|
|
*/
|
|
|
|
|
static double
|
|
|
|
|
getHeadingMag ()
|
|
|
|
|
{
|
|
|
|
|
return current_aircraft.fdm_state->get_Psi() * SGD_RADIANS_TO_DEGREES - getMagVar();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-02-19 15:16:08 +00:00
|
|
|
|
#if !defined(FG_NEW_ENVIRONMENT)
|
2002-02-19 01:26:44 +00:00
|
|
|
|
|
2001-06-05 22:13:26 +00:00
|
|
|
|
/**
|
|
|
|
|
* Get the current visibility (meters).
|
|
|
|
|
*/
|
|
|
|
|
static double
|
|
|
|
|
getVisibility ()
|
|
|
|
|
{
|
|
|
|
|
return WeatherDatabase->getWeatherVisibility();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set the current visibility (meters).
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
setVisibility (double visibility)
|
|
|
|
|
{
|
|
|
|
|
WeatherDatabase->setWeatherVisibility(visibility);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the current wind north velocity (feet/second).
|
|
|
|
|
*/
|
|
|
|
|
static double
|
|
|
|
|
getWindNorth ()
|
|
|
|
|
{
|
|
|
|
|
return current_aircraft.fdm_state->get_V_north_airmass();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set the current wind north velocity (feet/second).
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
setWindNorth (double speed)
|
|
|
|
|
{
|
|
|
|
|
current_aircraft.fdm_state
|
|
|
|
|
->set_Velocities_Local_Airmass(speed, getWindEast(), getWindDown());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the current wind east velocity (feet/second).
|
|
|
|
|
*/
|
|
|
|
|
static double
|
|
|
|
|
getWindEast ()
|
|
|
|
|
{
|
|
|
|
|
return current_aircraft.fdm_state->get_V_east_airmass();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set the current wind east velocity (feet/second).
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
setWindEast (double speed)
|
|
|
|
|
{
|
|
|
|
|
cout << "Set wind-east to " << speed << endl;
|
|
|
|
|
current_aircraft.fdm_state->set_Velocities_Local_Airmass(getWindNorth(),
|
|
|
|
|
speed,
|
|
|
|
|
getWindDown());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the current wind down velocity (feet/second).
|
|
|
|
|
*/
|
|
|
|
|
static double
|
|
|
|
|
getWindDown ()
|
|
|
|
|
{
|
|
|
|
|
return current_aircraft.fdm_state->get_V_down_airmass();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set the current wind down velocity (feet/second).
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
setWindDown (double speed)
|
|
|
|
|
{
|
|
|
|
|
current_aircraft.fdm_state->set_Velocities_Local_Airmass(getWindNorth(),
|
|
|
|
|
getWindEast(),
|
|
|
|
|
speed);
|
|
|
|
|
}
|
|
|
|
|
|
2002-02-19 15:16:08 +00:00
|
|
|
|
#endif // FG_NEW_ENVIRONMENT
|
2002-02-19 01:26:44 +00:00
|
|
|
|
|
2001-06-26 21:59:59 +00:00
|
|
|
|
static long
|
|
|
|
|
getWarp ()
|
|
|
|
|
{
|
|
|
|
|
return globals->get_warp();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
setWarp (long warp)
|
|
|
|
|
{
|
|
|
|
|
globals->set_warp(warp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static long
|
|
|
|
|
getWarpDelta ()
|
|
|
|
|
{
|
|
|
|
|
return globals->get_warp_delta();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
setWarpDelta (long delta)
|
|
|
|
|
{
|
|
|
|
|
globals->set_warp_delta(delta);
|
|
|
|
|
}
|
2001-06-05 22:13:26 +00:00
|
|
|
|
|
2001-07-16 04:35:35 +00:00
|
|
|
|
static bool
|
|
|
|
|
getWindingCCW ()
|
|
|
|
|
{
|
|
|
|
|
return winding_ccw;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
setWindingCCW (bool state)
|
|
|
|
|
{
|
|
|
|
|
winding_ccw = state;
|
|
|
|
|
if ( winding_ccw )
|
|
|
|
|
glFrontFace ( GL_CCW );
|
|
|
|
|
else
|
|
|
|
|
glFrontFace ( GL_CW );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
getFullScreen ()
|
|
|
|
|
{
|
|
|
|
|
#if defined(FX) && !defined(WIN32)
|
2002-01-06 16:51:31 +00:00
|
|
|
|
return globals->get_fullscreen();
|
2001-07-16 04:35:35 +00:00
|
|
|
|
#else
|
|
|
|
|
return false;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
setFullScreen (bool state)
|
|
|
|
|
{
|
|
|
|
|
#if defined(FX) && !defined(WIN32)
|
2002-01-06 16:51:31 +00:00
|
|
|
|
globals->set_fullscreen(state);
|
2001-07-16 04:35:35 +00:00
|
|
|
|
# if defined(XMESA_FX_FULLSCREEN) && defined(XMESA_FX_WINDOW)
|
2002-01-06 16:51:31 +00:00
|
|
|
|
XMesaSetFXmode( state ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW );
|
2001-07-16 04:35:35 +00:00
|
|
|
|
# endif
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
getFDMDataLogging ()
|
|
|
|
|
{
|
|
|
|
|
return fdm_data_logging;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
setFDMDataLogging (bool state)
|
|
|
|
|
{
|
|
|
|
|
// kludge; no getter or setter available
|
|
|
|
|
if (state != fdm_data_logging) {
|
|
|
|
|
fgToggleFDMdataLogging();
|
|
|
|
|
fdm_data_logging = state;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Tie the properties.
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
2001-06-05 22:13:26 +00:00
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
fgInitProps ()
|
|
|
|
|
{
|
|
|
|
|
// Simulation
|
2001-11-20 22:03:17 +00:00
|
|
|
|
fgTie("/sim/logging/priority", getLoggingPriority, setLoggingPriority);
|
|
|
|
|
fgTie("/sim/logging/classes", getLoggingClasses, setLoggingClasses);
|
2002-04-19 04:00:02 +00:00
|
|
|
|
fgTie("/sim/freeze/master", getFreeze, setFreeze);
|
2001-06-05 22:13:26 +00:00
|
|
|
|
fgTie("/sim/aircraft-dir", getAircraftDir, setAircraftDir);
|
2002-03-14 00:29:20 +00:00
|
|
|
|
|
2002-05-11 16:28:50 +00:00
|
|
|
|
fgTie("/sim/time/elapsed-sec", getElapsedTime_sec);
|
2001-06-05 22:13:26 +00:00
|
|
|
|
fgTie("/sim/time/gmt", getDateString, setDateString);
|
2001-07-12 23:35:56 +00:00
|
|
|
|
fgSetArchivable("/sim/time/gmt");
|
2001-06-05 22:13:26 +00:00
|
|
|
|
fgTie("/sim/time/gmt-string", getGMTString);
|
2001-06-26 21:59:59 +00:00
|
|
|
|
fgTie("/sim/rendering/textures", getTextures, setTextures);
|
2001-06-05 22:13:26 +00:00
|
|
|
|
|
|
|
|
|
// Orientation
|
2001-07-02 22:27:24 +00:00
|
|
|
|
fgTie("/orientation/heading-magnetic-deg", getHeadingMag);
|
2001-06-05 22:13:26 +00:00
|
|
|
|
|
|
|
|
|
// Environment
|
2002-02-19 15:16:08 +00:00
|
|
|
|
#if !defined(FG_NEW_ENVIRONMENT)
|
2001-07-02 22:27:24 +00:00
|
|
|
|
fgTie("/environment/visibility-m", getVisibility, setVisibility);
|
2001-07-12 23:35:56 +00:00
|
|
|
|
fgSetArchivable("/environment/visibility-m");
|
2002-02-20 22:58:42 +00:00
|
|
|
|
fgTie("/environment/wind-from-north-fps", getWindNorth, setWindNorth);
|
|
|
|
|
fgSetArchivable("/environment/wind-from-north-fps");
|
|
|
|
|
fgTie("/environment/wind-from-east-fps", getWindEast, setWindEast);
|
|
|
|
|
fgSetArchivable("/environment/wind-from-east-fps");
|
|
|
|
|
fgTie("/environment/wind-from-down-fps", getWindDown, setWindDown);
|
|
|
|
|
fgSetArchivable("/environment/wind-from-down-fps");
|
2002-02-19 01:26:44 +00:00
|
|
|
|
#endif
|
2001-07-12 23:35:56 +00:00
|
|
|
|
|
2001-07-02 22:27:24 +00:00
|
|
|
|
fgTie("/environment/magnetic-variation-deg", getMagVar);
|
|
|
|
|
fgTie("/environment/magnetic-dip-deg", getMagDip);
|
2001-06-05 22:13:26 +00:00
|
|
|
|
|
2001-07-02 16:44:02 +00:00
|
|
|
|
fgTie("/sim/time/warp", getWarp, setWarp, false);
|
2001-06-26 21:59:59 +00:00
|
|
|
|
fgTie("/sim/time/warp-delta", getWarpDelta, setWarpDelta);
|
2001-07-16 04:35:35 +00:00
|
|
|
|
|
|
|
|
|
// Misc. Temporary junk.
|
2001-10-05 20:27:43 +00:00
|
|
|
|
fgTie("/sim/temp/winding-ccw", getWindingCCW, setWindingCCW, false);
|
2001-07-16 04:35:35 +00:00
|
|
|
|
fgTie("/sim/temp/full-screen", getFullScreen, setFullScreen);
|
|
|
|
|
fgTie("/sim/temp/fdm-data-logging", getFDMDataLogging, setFDMDataLogging);
|
|
|
|
|
|
2001-06-05 22:13:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
fgUpdateProps ()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Save and restore.
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2001-01-05 17:37:59 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Save the current state of the simulator to a stream.
|
|
|
|
|
*/
|
|
|
|
|
bool
|
2002-03-03 22:48:40 +00:00
|
|
|
|
fgSaveFlight (ostream &output, bool write_all)
|
2001-01-05 17:37:59 +00:00
|
|
|
|
{
|
2002-03-14 14:25:30 +00:00
|
|
|
|
|
|
|
|
|
fgSetBool("/sim/startup/onground", false);
|
|
|
|
|
fgSetArchivable("/sim/startup/onground");
|
|
|
|
|
fgSetBool("/sim/startup/trim", false);
|
|
|
|
|
fgSetArchivable("/sim/startup/trim");
|
|
|
|
|
fgSetString("/sim/startup/speed-set", "UVW");
|
|
|
|
|
fgSetArchivable("/sim/startup/speed-set");
|
|
|
|
|
|
2001-07-19 04:51:05 +00:00
|
|
|
|
try {
|
2002-03-03 22:48:40 +00:00
|
|
|
|
writeProperties(output, globals->get_props(), write_all);
|
2001-07-24 23:51:47 +00:00
|
|
|
|
} catch (const sg_exception &e) {
|
|
|
|
|
guiErrorMessage("Error saving flight: ", e);
|
2001-07-19 04:51:05 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2001-01-05 17:37:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Restore the current state of the simulator from a stream.
|
|
|
|
|
*/
|
|
|
|
|
bool
|
|
|
|
|
fgLoadFlight (istream &input)
|
|
|
|
|
{
|
2001-01-19 22:57:24 +00:00
|
|
|
|
SGPropertyNode props;
|
2001-07-19 04:51:05 +00:00
|
|
|
|
try {
|
|
|
|
|
readProperties(input, &props);
|
2001-07-24 23:51:47 +00:00
|
|
|
|
} catch (const sg_exception &e) {
|
|
|
|
|
guiErrorMessage("Error reading saved flight: ", e);
|
2001-01-19 22:57:24 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2002-03-14 14:25:30 +00:00
|
|
|
|
|
|
|
|
|
fgSetBool("/sim/startup/onground", false);
|
|
|
|
|
fgSetBool("/sim/startup/trim", false);
|
|
|
|
|
fgSetString("/sim/startup/speed-set", "UVW");
|
|
|
|
|
|
2001-07-19 04:51:05 +00:00
|
|
|
|
copyProperties(&props, globals->get_props());
|
|
|
|
|
// When loading a flight, make it the
|
|
|
|
|
// new initial state.
|
|
|
|
|
globals->saveInitialState();
|
2001-05-18 20:30:36 +00:00
|
|
|
|
return true;
|
2001-01-05 17:37:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-08-03 00:19:41 +00:00
|
|
|
|
|
2002-03-19 17:12:13 +00:00
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Property convenience functions.
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
SGPropertyNode *
|
|
|
|
|
fgGetNode (const char * path, bool create)
|
|
|
|
|
{
|
|
|
|
|
return globals->get_props()->getNode(path, create);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SGPropertyNode *
|
|
|
|
|
fgGetNode (const char * path, int index, bool create)
|
|
|
|
|
{
|
|
|
|
|
return globals->get_props()->getNode(path, index, create);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
fgHasNode (const char * path)
|
|
|
|
|
{
|
|
|
|
|
return (fgGetNode(path, false) != 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
fgGetBool (const char * name, bool defaultValue)
|
|
|
|
|
{
|
|
|
|
|
return globals->get_props()->getBoolValue(name, defaultValue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
fgGetInt (const char * name, int defaultValue)
|
|
|
|
|
{
|
|
|
|
|
return globals->get_props()->getIntValue(name, defaultValue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
fgGetLong (const char * name, long defaultValue)
|
|
|
|
|
{
|
|
|
|
|
return globals->get_props()->getLongValue(name, defaultValue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float
|
|
|
|
|
fgGetFloat (const char * name, float defaultValue)
|
|
|
|
|
{
|
|
|
|
|
return globals->get_props()->getFloatValue(name, defaultValue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double
|
|
|
|
|
fgGetDouble (const char * name, double defaultValue)
|
|
|
|
|
{
|
|
|
|
|
return globals->get_props()->getDoubleValue(name, defaultValue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
fgGetString (const char * name, const char * defaultValue)
|
|
|
|
|
{
|
|
|
|
|
return globals->get_props()->getStringValue(name, defaultValue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
fgSetBool (const char * name, bool val)
|
|
|
|
|
{
|
|
|
|
|
return globals->get_props()->setBoolValue(name, val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
fgSetInt (const char * name, int val)
|
|
|
|
|
{
|
|
|
|
|
return globals->get_props()->setIntValue(name, val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
fgSetLong (const char * name, long val)
|
|
|
|
|
{
|
|
|
|
|
return globals->get_props()->setLongValue(name, val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
fgSetFloat (const char * name, float val)
|
|
|
|
|
{
|
|
|
|
|
return globals->get_props()->setFloatValue(name, val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
fgSetDouble (const char * name, double val)
|
|
|
|
|
{
|
|
|
|
|
return globals->get_props()->setDoubleValue(name, val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
fgSetString (const char * name, const char * val)
|
|
|
|
|
{
|
|
|
|
|
return globals->get_props()->setStringValue(name, val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
fgSetArchivable (const char * name, bool state)
|
|
|
|
|
{
|
|
|
|
|
SGPropertyNode * node = globals->get_props()->getNode(name);
|
|
|
|
|
if (node == 0)
|
|
|
|
|
SG_LOG(SG_GENERAL, SG_ALERT,
|
|
|
|
|
"Attempt to set archive flag for non-existant property "
|
|
|
|
|
<< name);
|
|
|
|
|
else
|
|
|
|
|
node->setAttribute(SGPropertyNode::ARCHIVE, state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
fgSetReadable (const char * name, bool state)
|
|
|
|
|
{
|
|
|
|
|
SGPropertyNode * node = globals->get_props()->getNode(name);
|
|
|
|
|
if (node == 0)
|
|
|
|
|
SG_LOG(SG_GENERAL, SG_ALERT,
|
|
|
|
|
"Attempt to set read flag for non-existant property "
|
|
|
|
|
<< name);
|
|
|
|
|
else
|
|
|
|
|
node->setAttribute(SGPropertyNode::READ, state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
fgSetWritable (const char * name, bool state)
|
|
|
|
|
{
|
|
|
|
|
SGPropertyNode * node = globals->get_props()->getNode(name);
|
|
|
|
|
if (node == 0)
|
|
|
|
|
SG_LOG(SG_GENERAL, SG_ALERT,
|
|
|
|
|
"Attempt to set write flag for non-existant property "
|
|
|
|
|
<< name);
|
|
|
|
|
else
|
|
|
|
|
node->setAttribute(SGPropertyNode::WRITE, state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
fgUntie (const char * name)
|
|
|
|
|
{
|
|
|
|
|
if (!globals->get_props()->untie(name))
|
|
|
|
|
SG_LOG(SG_GENERAL, SG_WARN, "Failed to untie property " << name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2001-08-03 00:19:41 +00:00
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Implementation of FGCondition.
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
FGCondition::FGCondition ()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FGCondition::~FGCondition ()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Implementation of FGPropertyCondition.
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2002-03-19 17:12:13 +00:00
|
|
|
|
FGPropertyCondition::FGPropertyCondition (const char * propname)
|
2001-08-03 00:19:41 +00:00
|
|
|
|
: _node(fgGetNode(propname, true))
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FGPropertyCondition::~FGPropertyCondition ()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Implementation of FGNotCondition.
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
FGNotCondition::FGNotCondition (FGCondition * condition)
|
|
|
|
|
: _condition(condition)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FGNotCondition::~FGNotCondition ()
|
|
|
|
|
{
|
|
|
|
|
delete _condition;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
FGNotCondition::test () const
|
|
|
|
|
{
|
|
|
|
|
return !(_condition->test());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Implementation of FGAndCondition.
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
FGAndCondition::FGAndCondition ()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FGAndCondition::~FGAndCondition ()
|
|
|
|
|
{
|
2001-08-31 18:07:23 +00:00
|
|
|
|
for (unsigned int i = 0; i < _conditions.size(); i++)
|
2001-08-03 00:19:41 +00:00
|
|
|
|
delete _conditions[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
FGAndCondition::test () const
|
|
|
|
|
{
|
|
|
|
|
int nConditions = _conditions.size();
|
|
|
|
|
for (int i = 0; i < nConditions; i++) {
|
|
|
|
|
if (!_conditions[i]->test())
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
FGAndCondition::addCondition (FGCondition * condition)
|
|
|
|
|
{
|
|
|
|
|
_conditions.push_back(condition);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Implementation of FGOrCondition.
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
FGOrCondition::FGOrCondition ()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FGOrCondition::~FGOrCondition ()
|
|
|
|
|
{
|
2001-08-31 18:07:23 +00:00
|
|
|
|
for (unsigned int i = 0; i < _conditions.size(); i++)
|
2001-08-03 00:19:41 +00:00
|
|
|
|
delete _conditions[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
FGOrCondition::test () const
|
|
|
|
|
{
|
|
|
|
|
int nConditions = _conditions.size();
|
|
|
|
|
for (int i = 0; i < nConditions; i++) {
|
|
|
|
|
if (_conditions[i]->test())
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
FGOrCondition::addCondition (FGCondition * condition)
|
|
|
|
|
{
|
|
|
|
|
_conditions.push_back(condition);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Implementation of FGComparisonCondition.
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
doComparison (const SGPropertyNode * left, const SGPropertyNode *right)
|
|
|
|
|
{
|
|
|
|
|
switch (left->getType()) {
|
|
|
|
|
case SGPropertyNode::BOOL: {
|
|
|
|
|
bool v1 = left->getBoolValue();
|
|
|
|
|
bool v2 = right->getBoolValue();
|
|
|
|
|
if (v1 < v2)
|
|
|
|
|
return FGComparisonCondition::LESS_THAN;
|
|
|
|
|
else if (v1 > v2)
|
|
|
|
|
return FGComparisonCondition::GREATER_THAN;
|
|
|
|
|
else
|
|
|
|
|
return FGComparisonCondition::EQUALS;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SGPropertyNode::INT: {
|
|
|
|
|
int v1 = left->getIntValue();
|
|
|
|
|
int v2 = right->getIntValue();
|
|
|
|
|
if (v1 < v2)
|
|
|
|
|
return FGComparisonCondition::LESS_THAN;
|
|
|
|
|
else if (v1 > v2)
|
|
|
|
|
return FGComparisonCondition::GREATER_THAN;
|
|
|
|
|
else
|
|
|
|
|
return FGComparisonCondition::EQUALS;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SGPropertyNode::LONG: {
|
|
|
|
|
long v1 = left->getLongValue();
|
|
|
|
|
long v2 = right->getLongValue();
|
|
|
|
|
if (v1 < v2)
|
|
|
|
|
return FGComparisonCondition::LESS_THAN;
|
|
|
|
|
else if (v1 > v2)
|
|
|
|
|
return FGComparisonCondition::GREATER_THAN;
|
|
|
|
|
else
|
|
|
|
|
return FGComparisonCondition::EQUALS;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SGPropertyNode::FLOAT: {
|
|
|
|
|
float v1 = left->getFloatValue();
|
|
|
|
|
float v2 = right->getFloatValue();
|
|
|
|
|
if (v1 < v2)
|
|
|
|
|
return FGComparisonCondition::LESS_THAN;
|
|
|
|
|
else if (v1 > v2)
|
|
|
|
|
return FGComparisonCondition::GREATER_THAN;
|
|
|
|
|
else
|
|
|
|
|
return FGComparisonCondition::EQUALS;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SGPropertyNode::DOUBLE: {
|
|
|
|
|
double v1 = left->getDoubleValue();
|
|
|
|
|
double v2 = right->getDoubleValue();
|
|
|
|
|
if (v1 < v2)
|
|
|
|
|
return FGComparisonCondition::LESS_THAN;
|
|
|
|
|
else if (v1 > v2)
|
|
|
|
|
return FGComparisonCondition::GREATER_THAN;
|
|
|
|
|
else
|
|
|
|
|
return FGComparisonCondition::EQUALS;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SGPropertyNode::STRING:
|
|
|
|
|
case SGPropertyNode::NONE:
|
|
|
|
|
case SGPropertyNode::UNSPECIFIED: {
|
|
|
|
|
string v1 = left->getStringValue();
|
|
|
|
|
string v2 = right->getStringValue();
|
|
|
|
|
if (v1 < v2)
|
|
|
|
|
return FGComparisonCondition::LESS_THAN;
|
|
|
|
|
else if (v1 > v2)
|
|
|
|
|
return FGComparisonCondition::GREATER_THAN;
|
|
|
|
|
else
|
|
|
|
|
return FGComparisonCondition::EQUALS;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
throw sg_exception("Unrecognized node type");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FGComparisonCondition::FGComparisonCondition (Type type, bool reverse)
|
|
|
|
|
: _type(type),
|
|
|
|
|
_reverse(reverse),
|
|
|
|
|
_left_property(0),
|
|
|
|
|
_right_property(0),
|
|
|
|
|
_right_value(0)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FGComparisonCondition::~FGComparisonCondition ()
|
|
|
|
|
{
|
|
|
|
|
delete _right_value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
FGComparisonCondition::test () const
|
|
|
|
|
{
|
|
|
|
|
// Always fail if incompletely specified
|
|
|
|
|
if (_left_property == 0 ||
|
|
|
|
|
(_right_property == 0 && _right_value == 0))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// Get LESS_THAN, EQUALS, or GREATER_THAN
|
|
|
|
|
int cmp =
|
|
|
|
|
doComparison(_left_property,
|
|
|
|
|
(_right_property != 0 ? _right_property : _right_value));
|
|
|
|
|
if (!_reverse)
|
|
|
|
|
return (cmp == _type);
|
|
|
|
|
else
|
|
|
|
|
return (cmp != _type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2002-03-19 17:12:13 +00:00
|
|
|
|
FGComparisonCondition::setLeftProperty (const char * propname)
|
2001-08-03 00:19:41 +00:00
|
|
|
|
{
|
|
|
|
|
_left_property = fgGetNode(propname, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2002-03-19 17:12:13 +00:00
|
|
|
|
FGComparisonCondition::setRightProperty (const char * propname)
|
2001-08-03 00:19:41 +00:00
|
|
|
|
{
|
|
|
|
|
delete _right_value;
|
|
|
|
|
_right_value = 0;
|
|
|
|
|
_right_property = fgGetNode(propname, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
FGComparisonCondition::setRightValue (const SGPropertyNode *node)
|
|
|
|
|
{
|
|
|
|
|
_right_property = 0;
|
|
|
|
|
delete _right_value;
|
|
|
|
|
_right_value = new SGPropertyNode(*node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Read a condition and use it if necessary.
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
// Forward declaration
|
|
|
|
|
static FGCondition * readCondition (const SGPropertyNode * node);
|
|
|
|
|
|
|
|
|
|
static FGCondition *
|
|
|
|
|
readPropertyCondition (const SGPropertyNode * node)
|
|
|
|
|
{
|
|
|
|
|
return new FGPropertyCondition(node->getStringValue());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static FGCondition *
|
|
|
|
|
readNotCondition (const SGPropertyNode * node)
|
|
|
|
|
{
|
|
|
|
|
int nChildren = node->nChildren();
|
|
|
|
|
for (int i = 0; i < nChildren; i++) {
|
|
|
|
|
const SGPropertyNode * child = node->getChild(i);
|
|
|
|
|
FGCondition * condition = readCondition(child);
|
|
|
|
|
if (condition != 0)
|
|
|
|
|
return new FGNotCondition(condition);
|
|
|
|
|
}
|
|
|
|
|
SG_LOG(SG_COCKPIT, SG_ALERT, "Panel: empty 'not' condition");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static FGCondition *
|
|
|
|
|
readAndConditions (const SGPropertyNode * node)
|
|
|
|
|
{
|
|
|
|
|
FGAndCondition * andCondition = new FGAndCondition;
|
|
|
|
|
int nChildren = node->nChildren();
|
|
|
|
|
for (int i = 0; i < nChildren; i++) {
|
|
|
|
|
const SGPropertyNode * child = node->getChild(i);
|
|
|
|
|
FGCondition * condition = readCondition(child);
|
|
|
|
|
if (condition != 0)
|
|
|
|
|
andCondition->addCondition(condition);
|
|
|
|
|
}
|
|
|
|
|
return andCondition;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static FGCondition *
|
|
|
|
|
readOrConditions (const SGPropertyNode * node)
|
|
|
|
|
{
|
|
|
|
|
FGOrCondition * orCondition = new FGOrCondition;
|
|
|
|
|
int nChildren = node->nChildren();
|
|
|
|
|
for (int i = 0; i < nChildren; i++) {
|
|
|
|
|
const SGPropertyNode * child = node->getChild(i);
|
|
|
|
|
FGCondition * condition = readCondition(child);
|
|
|
|
|
if (condition != 0)
|
|
|
|
|
orCondition->addCondition(condition);
|
|
|
|
|
}
|
|
|
|
|
return orCondition;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static FGCondition *
|
|
|
|
|
readComparison (const SGPropertyNode * node,
|
|
|
|
|
FGComparisonCondition::Type type,
|
|
|
|
|
bool reverse)
|
|
|
|
|
{
|
|
|
|
|
FGComparisonCondition * condition = new FGComparisonCondition(type, reverse);
|
|
|
|
|
condition->setLeftProperty(node->getStringValue("property[0]"));
|
|
|
|
|
if (node->hasValue("property[1]"))
|
|
|
|
|
condition->setRightProperty(node->getStringValue("property[1]"));
|
|
|
|
|
else
|
|
|
|
|
condition->setRightValue(node->getChild("value", 0));
|
|
|
|
|
|
|
|
|
|
return condition;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static FGCondition *
|
|
|
|
|
readCondition (const SGPropertyNode * node)
|
|
|
|
|
{
|
|
|
|
|
const string &name = node->getName();
|
|
|
|
|
if (name == "property")
|
|
|
|
|
return readPropertyCondition(node);
|
|
|
|
|
else if (name == "not")
|
|
|
|
|
return readNotCondition(node);
|
|
|
|
|
else if (name == "and")
|
|
|
|
|
return readAndConditions(node);
|
|
|
|
|
else if (name == "or")
|
|
|
|
|
return readOrConditions(node);
|
|
|
|
|
else if (name == "less-than")
|
|
|
|
|
return readComparison(node, FGComparisonCondition::LESS_THAN, false);
|
|
|
|
|
else if (name == "less-than-equals")
|
|
|
|
|
return readComparison(node, FGComparisonCondition::GREATER_THAN, true);
|
|
|
|
|
else if (name == "greater-than")
|
|
|
|
|
return readComparison(node, FGComparisonCondition::GREATER_THAN, false);
|
|
|
|
|
else if (name == "greater-than-equals")
|
|
|
|
|
return readComparison(node, FGComparisonCondition::LESS_THAN, true);
|
|
|
|
|
else if (name == "equals")
|
|
|
|
|
return readComparison(node, FGComparisonCondition::EQUALS, false);
|
|
|
|
|
else if (name == "not-equals")
|
|
|
|
|
return readComparison(node, FGComparisonCondition::EQUALS, true);
|
|
|
|
|
else
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Implementation of FGConditional.
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
FGConditional::FGConditional ()
|
|
|
|
|
: _condition (0)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FGConditional::~FGConditional ()
|
|
|
|
|
{
|
|
|
|
|
delete _condition;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
FGConditional::setCondition (FGCondition * condition)
|
|
|
|
|
{
|
|
|
|
|
delete _condition;
|
|
|
|
|
_condition = condition;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
FGConditional::test () const
|
|
|
|
|
{
|
|
|
|
|
return ((_condition == 0) || _condition->test());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The top-level is always an implicit 'and' group
|
|
|
|
|
FGCondition *
|
|
|
|
|
fgReadCondition (const SGPropertyNode * node)
|
|
|
|
|
{
|
|
|
|
|
return readAndConditions(node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2001-01-05 17:37:59 +00:00
|
|
|
|
// end of fg_props.cxx
|