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
|
2006-02-21 01:16:04 +00:00
|
|
|
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2001-01-05 17:37:59 +00:00
|
|
|
|
//
|
|
|
|
|
// $Id$
|
|
|
|
|
|
2018-06-27 10:27:12 +00:00
|
|
|
|
#include "config.h"
|
2001-04-02 02:59:31 +00:00
|
|
|
|
|
2006-02-18 13:58:09 +00:00
|
|
|
|
#include <simgear/compiler.h>
|
2003-09-24 17:20:55 +00:00
|
|
|
|
#include <simgear/structure/exception.hxx>
|
2008-07-31 12:04:32 +00:00
|
|
|
|
#include <simgear/props/props_io.hxx>
|
2018-06-27 10:27:12 +00:00
|
|
|
|
#include <simgear/misc/strutils.hxx>
|
2002-03-16 00:18:38 +00:00
|
|
|
|
#include <simgear/timing/sg_time.hxx>
|
2002-11-06 18:57:31 +00:00
|
|
|
|
#include <simgear/misc/sg_path.hxx>
|
2010-03-27 10:59:04 +00:00
|
|
|
|
#include <simgear/scene/model/particles.hxx>
|
2016-07-06 11:27:14 +00:00
|
|
|
|
#include <simgear/sound/soundmgr.hxx>
|
2001-07-19 04:51:05 +00:00
|
|
|
|
|
|
|
|
|
#include <GUI/gui.h>
|
|
|
|
|
|
2002-01-06 16:51:31 +00:00
|
|
|
|
#include "globals.hxx"
|
2001-01-05 17:37:59 +00:00
|
|
|
|
#include "fg_props.hxx"
|
|
|
|
|
|
2002-04-19 04:00:02 +00:00
|
|
|
|
static bool frozen = false; // FIXME: temporary
|
|
|
|
|
|
2008-07-31 12:04:32 +00:00
|
|
|
|
using std::string;
|
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"),
|
2004-10-24 11:05:14 +00:00
|
|
|
|
LogClassMapping(SG_INSTR, "instrumentation"),
|
2011-08-11 22:09:26 +00:00
|
|
|
|
LogClassMapping(SG_ATC, "atc"),
|
|
|
|
|
LogClassMapping(SG_NASAL, "nasal"),
|
2004-10-24 11:05:14 +00:00
|
|
|
|
LogClassMapping(SG_SYSTEMS, "systems"),
|
2011-08-11 22:09:26 +00:00
|
|
|
|
LogClassMapping(SG_AI, "ai"),
|
|
|
|
|
LogClassMapping(SG_ENVIRONMENT, "environment"),
|
|
|
|
|
LogClassMapping(SG_SOUND, "sound"),
|
2012-11-23 20:14:40 +00:00
|
|
|
|
LogClassMapping(SG_NAVAID, "navaid"),
|
2014-05-31 00:43:03 +00:00
|
|
|
|
LogClassMapping(SG_GUI, "gui"),
|
2016-01-16 21:48:50 +00:00
|
|
|
|
LogClassMapping(SG_TERRASYNC, "terrasync"),
|
2001-12-09 05:20:13 +00:00
|
|
|
|
LogClassMapping(SG_UNDEFD, "")
|
2001-11-20 22:03:17 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the logging classes.
|
|
|
|
|
*/
|
2009-12-30 16:34:58 +00:00
|
|
|
|
// XXX Making the result buffer be global is a band-aid that hopefully
|
|
|
|
|
// delays its destruction 'til after its last use.
|
|
|
|
|
namespace
|
|
|
|
|
{
|
|
|
|
|
string loggingResult;
|
|
|
|
|
}
|
|
|
|
|
|
2002-03-19 17:12:13 +00:00
|
|
|
|
static const char *
|
2001-11-20 22:03:17 +00:00
|
|
|
|
getLoggingClasses ()
|
|
|
|
|
{
|
2013-02-06 18:05:45 +00:00
|
|
|
|
sgDebugClass classes = sglog().get_log_classes();
|
2009-12-30 16:34:58 +00:00
|
|
|
|
loggingResult.clear();
|
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) {
|
2009-12-30 16:34:58 +00:00
|
|
|
|
if (!loggingResult.empty())
|
|
|
|
|
loggingResult += '|';
|
|
|
|
|
loggingResult += log_class_mappings[i].name;
|
2001-11-20 22:03:17 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2009-12-30 16:34:58 +00:00
|
|
|
|
return loggingResult.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
|
|
|
|
{
|
2013-02-06 18:05:45 +00:00
|
|
|
|
sgDebugClass classes = sglog().get_log_classes();
|
2001-11-20 22:03:17 +00:00
|
|
|
|
for (int i = 0; log_class_mappings[i].c != SG_UNDEFD; i++) {
|
|
|
|
|
if (name == log_class_mappings[i].name) {
|
2013-02-06 18:05:45 +00:00
|
|
|
|
sglog().set_log_classes(sgDebugClass(classes|log_class_mappings[i].c));
|
2001-11-20 22:03:17 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-11-25 17:10:36 +00:00
|
|
|
|
SG_LOG(SG_GENERAL, SG_WARN, "Unknown logging class: " << name);
|
2001-11-20 22:03:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set the logging classes.
|
|
|
|
|
*/
|
2011-12-11 12:55:56 +00:00
|
|
|
|
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;
|
2013-02-06 18:05:45 +00:00
|
|
|
|
sglog().set_log_classes(SG_NONE);
|
2001-11-20 22:03:17 +00:00
|
|
|
|
|
|
|
|
|
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
|
2013-02-06 18:05:45 +00:00
|
|
|
|
sglog().set_log_classes(SG_ALL);
|
2001-11-20 22:03:17 +00:00
|
|
|
|
SG_LOG(SG_GENERAL, SG_INFO, "Enabled all logging classes: "
|
|
|
|
|
<< getLoggingClasses());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string rest = classes;
|
|
|
|
|
string name = "";
|
2011-12-11 12:55:56 +00:00
|
|
|
|
string::size_type sep = rest.find('|');
|
|
|
|
|
if (sep == string::npos)
|
|
|
|
|
sep = rest.find(',');
|
|
|
|
|
while (sep != string::npos) {
|
2001-11-20 22:03:17 +00:00
|
|
|
|
name = rest.substr(0, sep);
|
|
|
|
|
rest = rest.substr(sep+1);
|
|
|
|
|
addLoggingClass(name);
|
|
|
|
|
sep = rest.find('|');
|
2011-12-11 12:55:56 +00:00
|
|
|
|
if (sep == string::npos)
|
|
|
|
|
sep = rest.find(',');
|
2001-11-20 22:03:17 +00:00
|
|
|
|
}
|
|
|
|
|
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 ()
|
|
|
|
|
{
|
2013-02-06 18:05:45 +00:00
|
|
|
|
switch (sglog().get_log_priority()) {
|
2001-11-20 22:03:17 +00:00
|
|
|
|
case SG_BULK:
|
|
|
|
|
return "bulk";
|
|
|
|
|
case SG_DEBUG:
|
|
|
|
|
return "debug";
|
|
|
|
|
case SG_INFO:
|
|
|
|
|
return "info";
|
|
|
|
|
case SG_WARN:
|
|
|
|
|
return "warn";
|
|
|
|
|
case SG_ALERT:
|
2016-07-20 13:03:15 +00:00
|
|
|
|
case SG_POPUP:
|
2001-11-20 22:03:17 +00:00
|
|
|
|
return "alert";
|
|
|
|
|
default:
|
|
|
|
|
SG_LOG(SG_GENERAL, SG_WARN, "Internal: Unknown logging priority number: "
|
2013-02-06 18:05:45 +00:00
|
|
|
|
<< sglog().get_log_priority());
|
2001-11-20 22:03:17 +00:00
|
|
|
|
return "unknown";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set the logging priority.
|
|
|
|
|
*/
|
2011-12-11 12:55:56 +00:00
|
|
|
|
void
|
2002-03-19 17:12:13 +00:00
|
|
|
|
setLoggingPriority (const char * p)
|
2001-11-20 22:03:17 +00:00
|
|
|
|
{
|
2003-11-25 17:10:36 +00:00
|
|
|
|
if (p == 0)
|
|
|
|
|
return;
|
2002-03-19 17:12:13 +00:00
|
|
|
|
string priority = p;
|
2001-11-20 22:03:17 +00:00
|
|
|
|
if (priority == "bulk") {
|
2013-02-06 18:05:45 +00:00
|
|
|
|
sglog().set_log_priority(SG_BULK);
|
2001-11-20 22:03:17 +00:00
|
|
|
|
} else if (priority == "debug") {
|
2013-02-06 18:05:45 +00:00
|
|
|
|
sglog().set_log_priority(SG_DEBUG);
|
2002-03-20 19:16:13 +00:00
|
|
|
|
} else if (priority.empty() || priority == "info") { // default
|
2013-02-06 18:05:45 +00:00
|
|
|
|
sglog().set_log_priority(SG_INFO);
|
2001-11-20 22:03:17 +00:00
|
|
|
|
} else if (priority == "warn") {
|
2013-02-06 18:05:45 +00:00
|
|
|
|
sglog().set_log_priority(SG_WARN);
|
2001-11-20 22:03:17 +00:00
|
|
|
|
} else if (priority == "alert") {
|
2013-02-06 18:05:45 +00:00
|
|
|
|
sglog().set_log_priority(SG_ALERT);
|
2001-11-20 22:03:17 +00:00
|
|
|
|
} else {
|
|
|
|
|
SG_LOG(SG_GENERAL, SG_WARN, "Unknown logging priority " << priority);
|
|
|
|
|
}
|
2003-11-25 17:10:36 +00:00
|
|
|
|
SG_LOG(SG_GENERAL, SG_DEBUG, "Logging priority is " << getLoggingPriority());
|
2001-11-20 22:03:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2002-12-11 21:07:30 +00:00
|
|
|
|
frozen = f;
|
|
|
|
|
|
2010-03-27 10:59:04 +00:00
|
|
|
|
// Pause the particle system
|
|
|
|
|
simgear::Particles::setFrozen(f);
|
2002-04-19 04:00:02 +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
|
2010-11-21 23:43:41 +00:00
|
|
|
|
|
|
|
|
|
SGTime * st = globals->get_time_params();
|
|
|
|
|
if (!st) {
|
|
|
|
|
buf[0] = 0;
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct tm * t = st->getGmt();
|
2001-06-05 22:13:26 +00:00
|
|
|
|
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
|
|
|
|
{
|
|
|
|
|
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) {
|
2003-11-25 17:10:36 +00:00
|
|
|
|
SG_LOG(SG_INPUT, SG_WARN, "Date/time string " << date_string
|
2001-06-05 22:13:26 +00:00
|
|
|
|
<< " 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();
|
2010-11-21 23:43:41 +00:00
|
|
|
|
|
|
|
|
|
fgSetInt("/sim/time/warp", warp);
|
2001-06-05 22:13:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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 ()
|
|
|
|
|
{
|
2006-06-17 18:25:12 +00:00
|
|
|
|
static char buf[16];
|
2010-11-21 23:43:41 +00:00
|
|
|
|
SGTime * st = globals->get_time_params();
|
|
|
|
|
if (!st) {
|
|
|
|
|
buf[0] = 0;
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct tm *t = st->getGmt();
|
2006-06-17 18:25:12 +00:00
|
|
|
|
snprintf(buf, 16, "%.2d:%.2d:%.2d",
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
2012-11-18 15:35:54 +00:00
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Tie the properties.
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
SGConstPropertyNode_ptr FGProperties::_longDeg;
|
|
|
|
|
SGConstPropertyNode_ptr FGProperties::_latDeg;
|
|
|
|
|
SGConstPropertyNode_ptr FGProperties::_lonLatformat;
|
|
|
|
|
|
2018-06-27 10:27:12 +00:00
|
|
|
|
using namespace simgear;
|
2006-06-17 16:33:00 +00:00
|
|
|
|
|
2018-06-27 10:27:12 +00:00
|
|
|
|
const char* FGProperties::getLongitudeString ()
|
2015-07-14 16:57:42 +00:00
|
|
|
|
{
|
2018-06-27 10:27:12 +00:00
|
|
|
|
const double d = _longDeg->getDoubleValue();
|
|
|
|
|
auto format = static_cast<strutils::LatLonFormat>(_lonLatformat->getIntValue());
|
|
|
|
|
const char c = d < 0.0 ? 'W' : 'E';
|
|
|
|
|
|
|
|
|
|
static char longitudeBuffer[64];
|
|
|
|
|
const auto s = strutils::formatLatLonValueAsString(d, format, c);
|
|
|
|
|
memcpy(longitudeBuffer, s.c_str(), s.size() + 1);
|
|
|
|
|
return longitudeBuffer;
|
2015-07-14 16:57:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-06-27 10:27:12 +00:00
|
|
|
|
const char* FGProperties::getLatitudeString ()
|
2015-07-14 16:57:42 +00:00
|
|
|
|
{
|
2018-06-27 10:27:12 +00:00
|
|
|
|
const double d = _latDeg->getDoubleValue();
|
|
|
|
|
auto format = static_cast<strutils::LatLonFormat>(_lonLatformat->getIntValue());
|
|
|
|
|
const char c = d < 0.0 ? 'S' : 'N';
|
|
|
|
|
|
|
|
|
|
static char latitudeBuffer[64];
|
|
|
|
|
const auto s = strutils::formatLatLonValueAsString(d, format, c);
|
|
|
|
|
memcpy(latitudeBuffer, s.c_str(), s.size() + 1);
|
|
|
|
|
return latitudeBuffer;
|
2006-06-17 16:33:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2004-02-20 17:35:33 +00:00
|
|
|
|
FGProperties::FGProperties ()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FGProperties::~FGProperties ()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2001-06-05 22:13:26 +00:00
|
|
|
|
void
|
2004-02-20 17:35:33 +00:00
|
|
|
|
FGProperties::init ()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
FGProperties::bind ()
|
2001-06-05 22:13:26 +00:00
|
|
|
|
{
|
2012-11-18 15:35:54 +00:00
|
|
|
|
_longDeg = fgGetNode("/position/longitude-deg", true);
|
|
|
|
|
_latDeg = fgGetNode("/position/latitude-deg", true);
|
|
|
|
|
_lonLatformat = fgGetNode("/sim/lon-lat-format", true);
|
|
|
|
|
|
|
|
|
|
_offset = fgGetNode("/sim/time/local-offset", true);
|
|
|
|
|
|
|
|
|
|
// utc date/time
|
|
|
|
|
_uyear = fgGetNode("/sim/time/utc/year", true);
|
|
|
|
|
_umonth = fgGetNode("/sim/time/utc/month", true);
|
|
|
|
|
_uday = fgGetNode("/sim/time/utc/day", true);
|
|
|
|
|
_uhour = fgGetNode("/sim/time/utc/hour", true);
|
|
|
|
|
_umin = fgGetNode("/sim/time/utc/minute", true);
|
|
|
|
|
_usec = fgGetNode("/sim/time/utc/second", true);
|
|
|
|
|
_uwday = fgGetNode("/sim/time/utc/weekday", true);
|
|
|
|
|
_udsec = fgGetNode("/sim/time/utc/day-seconds", true);
|
|
|
|
|
|
|
|
|
|
// real local date/time
|
|
|
|
|
_ryear = fgGetNode("/sim/time/real/year", true);
|
|
|
|
|
_rmonth = fgGetNode("/sim/time/real/month", true);
|
|
|
|
|
_rday = fgGetNode("/sim/time/real/day", true);
|
|
|
|
|
_rhour = fgGetNode("/sim/time/real/hour", true);
|
|
|
|
|
_rmin = fgGetNode("/sim/time/real/minute", true);
|
|
|
|
|
_rsec = fgGetNode("/sim/time/real/second", true);
|
|
|
|
|
_rwday = fgGetNode("/sim/time/real/weekday", true);
|
|
|
|
|
|
2012-03-04 14:30:08 +00:00
|
|
|
|
_tiedProperties.setRoot(globals->get_props());
|
2002-03-14 00:29:20 +00:00
|
|
|
|
|
2012-03-04 14:30:08 +00:00
|
|
|
|
// Simulation
|
|
|
|
|
_tiedProperties.Tie("/sim/logging/priority", getLoggingPriority, setLoggingPriority);
|
|
|
|
|
_tiedProperties.Tie("/sim/logging/classes", getLoggingClasses, setLoggingClasses);
|
|
|
|
|
_tiedProperties.Tie("/sim/freeze/master", getFreeze, setFreeze);
|
|
|
|
|
|
2016-06-01 21:57:11 +00:00
|
|
|
|
_tiedProperties.Tie<double>("/sim/time/elapsed-sec", getElapsedTime_sec);
|
2012-03-04 14:30:08 +00:00
|
|
|
|
_tiedProperties.Tie("/sim/time/gmt", getDateString, setDateString);
|
2001-07-12 23:35:56 +00:00
|
|
|
|
fgSetArchivable("/sim/time/gmt");
|
2016-06-01 21:57:11 +00:00
|
|
|
|
_tiedProperties.Tie<const char*>("/sim/time/gmt-string", getGMTString);
|
2001-06-05 22:13:26 +00:00
|
|
|
|
|
2012-03-04 14:30:08 +00:00
|
|
|
|
// Position
|
2016-06-01 21:57:11 +00:00
|
|
|
|
_tiedProperties.Tie<const char*>("/position/latitude-string", getLatitudeString);
|
|
|
|
|
_tiedProperties.Tie<const char*>("/position/longitude-string", getLongitudeString);
|
2006-06-17 16:33:00 +00:00
|
|
|
|
|
2020-04-01 15:20:29 +00:00
|
|
|
|
_headingMagnetic = fgGetNode("/orientation/heading-magnetic-deg", true);
|
|
|
|
|
_trackMagnetic = fgGetNode("/orientation/track-magnetic-deg", true);
|
|
|
|
|
_magVar = fgGetNode("/environment/magnetic-variation-deg", true);
|
|
|
|
|
_trueHeading = fgGetNode("/orientatino/heading-deg", true);
|
|
|
|
|
_trueTrack = fgGetNode("/orientation/track-deg", true);
|
2001-06-05 22:13:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2004-02-20 17:35:33 +00:00
|
|
|
|
FGProperties::unbind ()
|
2001-06-05 22:13:26 +00:00
|
|
|
|
{
|
2012-03-04 14:30:08 +00:00
|
|
|
|
_tiedProperties.Untie();
|
2012-11-18 15:35:54 +00:00
|
|
|
|
|
|
|
|
|
// drop static references to properties
|
|
|
|
|
_longDeg = 0;
|
|
|
|
|
_latDeg = 0;
|
|
|
|
|
_lonLatformat = 0;
|
2004-02-20 17:35:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
FGProperties::update (double dt)
|
|
|
|
|
{
|
2012-11-18 15:35:54 +00:00
|
|
|
|
_offset->setIntValue(globals->get_time_params()->get_local_offset());
|
2009-02-15 22:49:51 +00:00
|
|
|
|
|
|
|
|
|
// utc date/time
|
|
|
|
|
struct tm *u = globals->get_time_params()->getGmt();
|
2012-11-18 15:35:54 +00:00
|
|
|
|
_uyear->setIntValue(u->tm_year + 1900);
|
|
|
|
|
_umonth->setIntValue(u->tm_mon + 1);
|
|
|
|
|
_uday->setIntValue(u->tm_mday);
|
|
|
|
|
_uhour->setIntValue(u->tm_hour);
|
|
|
|
|
_umin->setIntValue(u->tm_min);
|
|
|
|
|
_usec->setIntValue(u->tm_sec);
|
|
|
|
|
_uwday->setIntValue(u->tm_wday);
|
|
|
|
|
_udsec->setIntValue(u->tm_hour * 3600 + u->tm_min * 60 + u->tm_sec);
|
2009-02-15 22:49:51 +00:00
|
|
|
|
|
|
|
|
|
// real local date/time
|
|
|
|
|
time_t real = time(0);
|
|
|
|
|
struct tm *r = localtime(&real);
|
2012-11-18 15:35:54 +00:00
|
|
|
|
_ryear->setIntValue(r->tm_year + 1900);
|
|
|
|
|
_rmonth->setIntValue(r->tm_mon + 1);
|
|
|
|
|
_rday->setIntValue(r->tm_mday);
|
|
|
|
|
_rhour->setIntValue(r->tm_hour);
|
|
|
|
|
_rmin->setIntValue(r->tm_min);
|
|
|
|
|
_rsec->setIntValue(r->tm_sec);
|
|
|
|
|
_rwday->setIntValue(r->tm_wday);
|
2020-04-01 15:20:29 +00:00
|
|
|
|
|
|
|
|
|
const double magvar = _magVar->getDoubleValue();
|
|
|
|
|
_headingMagnetic->setDoubleValue(_trueHeading->getDoubleValue() - magvar);
|
|
|
|
|
_trackMagnetic->setDoubleValue(_trueTrack->getDoubleValue() - magvar);
|
2001-06-05 22:13:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-05-07 06:46:44 +00:00
|
|
|
|
// Register the subsystem.
|
|
|
|
|
SGSubsystemMgr::Registrant<FGProperties> registrantFGProperties;
|
|
|
|
|
|
2001-06-05 22:13:26 +00:00
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Save and restore.
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2001-01-05 17:37:59 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Save the current state of the simulator to a stream.
|
|
|
|
|
*/
|
|
|
|
|
bool
|
2008-07-31 12:04:32 +00:00
|
|
|
|
fgSaveFlight (std::ostream &output, bool write_all)
|
2001-01-05 17:37:59 +00:00
|
|
|
|
{
|
2002-03-14 14:25:30 +00:00
|
|
|
|
|
2002-11-15 21:13:29 +00:00
|
|
|
|
fgSetBool("/sim/presets/onground", false);
|
|
|
|
|
fgSetArchivable("/sim/presets/onground");
|
|
|
|
|
fgSetBool("/sim/presets/trim", false);
|
|
|
|
|
fgSetArchivable("/sim/presets/trim");
|
|
|
|
|
fgSetString("/sim/presets/speed-set", "UVW");
|
|
|
|
|
fgSetArchivable("/sim/presets/speed-set");
|
2002-03-14 14:25:30 +00:00
|
|
|
|
|
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
|
2008-07-31 12:04:32 +00:00
|
|
|
|
fgLoadFlight (std::istream &input)
|
2001-01-05 17:37:59 +00:00
|
|
|
|
{
|
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
|
|
|
|
|
2002-11-15 21:13:29 +00:00
|
|
|
|
fgSetBool("/sim/presets/onground", false);
|
|
|
|
|
fgSetBool("/sim/presets/trim", false);
|
|
|
|
|
fgSetString("/sim/presets/speed-set", "UVW");
|
2002-03-14 14:25:30 +00:00
|
|
|
|
|
2001-07-19 04:51:05 +00:00
|
|
|
|
copyProperties(&props, globals->get_props());
|
2014-03-10 17:29:28 +00:00
|
|
|
|
|
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
|
|
|
|
|
2003-01-21 02:08:00 +00:00
|
|
|
|
bool
|
2016-06-23 13:26:34 +00:00
|
|
|
|
fgLoadProps (const std::string& path, SGPropertyNode * props, bool in_fg_root, int default_mode)
|
2003-01-21 02:08:00 +00:00
|
|
|
|
{
|
2016-06-23 13:26:34 +00:00
|
|
|
|
SGPath fullpath;
|
2003-01-21 02:08:00 +00:00
|
|
|
|
if (in_fg_root) {
|
|
|
|
|
SGPath loadpath(globals->get_fg_root());
|
|
|
|
|
loadpath.append(path);
|
2016-06-23 13:26:34 +00:00
|
|
|
|
fullpath = loadpath;
|
2003-01-21 02:08:00 +00:00
|
|
|
|
} else {
|
2016-06-23 13:26:34 +00:00
|
|
|
|
fullpath = SGPath::fromUtf8(path);
|
2003-01-21 02:08:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
2005-12-17 15:34:37 +00:00
|
|
|
|
readProperties(fullpath, props, default_mode);
|
2003-01-21 02:08:00 +00:00
|
|
|
|
} catch (const sg_exception &e) {
|
|
|
|
|
guiErrorMessage("Error reading properties: ", e);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2002-11-06 18:57:31 +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);
|
|
|
|
|
}
|
|
|
|
|
|
2002-06-18 03:27:21 +00:00
|
|
|
|
void
|
|
|
|
|
fgAddChangeListener (SGPropertyChangeListener * listener, const char * path)
|
|
|
|
|
{
|
|
|
|
|
fgGetNode(path, true)->addChangeListener(listener);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
fgAddChangeListener (SGPropertyChangeListener * listener,
|
|
|
|
|
const char * path, int index)
|
|
|
|
|
{
|
|
|
|
|
fgGetNode(path, index, true)->addChangeListener(listener);
|
|
|
|
|
}
|
|
|
|
|
|
2002-03-19 17:12:13 +00:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-25 21:08:52 +00:00
|
|
|
|
long
|
2002-03-19 17:12:13 +00:00
|
|
|
|
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)
|
2003-11-25 17:10:36 +00:00
|
|
|
|
SG_LOG(SG_GENERAL, SG_DEBUG,
|
2002-03-19 17:12:13 +00:00
|
|
|
|
"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)
|
2003-11-25 17:10:36 +00:00
|
|
|
|
SG_LOG(SG_GENERAL, SG_DEBUG,
|
2002-03-19 17:12:13 +00:00
|
|
|
|
"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)
|
2003-11-25 17:10:36 +00:00
|
|
|
|
SG_LOG(SG_GENERAL, SG_DEBUG,
|
2002-03-19 17:12:13 +00:00
|
|
|
|
"Attempt to set write flag for non-existant property "
|
|
|
|
|
<< name);
|
|
|
|
|
else
|
|
|
|
|
node->setAttribute(SGPropertyNode::WRITE, state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2010-07-01 01:04:16 +00:00
|
|
|
|
fgUntie(const char * name)
|
2002-03-19 17:12:13 +00:00
|
|
|
|
{
|
2010-07-01 01:04:16 +00:00
|
|
|
|
SGPropertyNode* node = globals->get_props()->getNode(name);
|
|
|
|
|
if (!node) {
|
|
|
|
|
SG_LOG(SG_GENERAL, SG_WARN, "fgUntie: unknown property " << name);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!node->isTied()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!node->untie()) {
|
2002-03-19 17:12:13 +00:00
|
|
|
|
SG_LOG(SG_GENERAL, SG_WARN, "Failed to untie property " << name);
|
2010-07-01 01:04:16 +00:00
|
|
|
|
}
|
2002-03-19 17:12:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2001-01-05 17:37:59 +00:00
|
|
|
|
// end of fg_props.cxx
|