#include <simgear/structure/event_mgr.hxx>
#include <simgear/sound/soundmgr_openal.hxx>
#include <simgear/timing/sg_time.hxx>
-#include <simgear/misc/interpolator.hxx>
-#include <simgear/io/HTTPRequest.hxx>
+#include <simgear/io/HTTPMemoryRequest.hxx>
#include <FDM/flight.hxx>
#include <GUI/gui.h>
#include <boost/scoped_array.hpp>
-#ifdef FG_HAVE_GPERFTOOLS
+#if FG_HAVE_GPERFTOOLS
# include <google/profiler.h>
#endif
}
-\f
+
////////////////////////////////////////////////////////////////////////
// Command implementations.
////////////////////////////////////////////////////////////////////////
fgSetBool("/sim/freeze/master",!paused);
fgSetBool("/sim/freeze/clock",!paused);
}
+
+ SGPropertyNode_ptr args(new SGPropertyNode);
+ args->setStringValue("id", "sim-pause");
+ if (!paused && fgGetBool("/sim/view-name-popup")) {
+ args->setStringValue("label", "Simulation is paused");
+ globals->get_commands()->execute("show-message", args);
+ } else {
+ globals->get_commands()->execute("clear-message", args);
+ }
+
return true;
}
}
static void
-do_view_next( bool )
+do_view_next(bool do_it)
{
+ // Only switch view if really requested to do so (and not for example while
+ // reset/reposition where /command/view/next is set to false)
+ if( do_it )
+ {
globals->get_current_view()->setHeadingOffset_deg(0.0);
globals->get_viewmgr()->next_view();
+ }
}
static void
-do_view_prev( bool )
+do_view_prev(bool do_it)
{
+ if( do_it )
+ {
globals->get_current_view()->setHeadingOffset_deg(0.0);
globals->get_viewmgr()->prev_view();
+ }
+}
+
+/**
+ * An fgcommand to toggle fullscreen mode.
+ * No parameters.
+ */
+static bool
+do_toggle_fullscreen(const SGPropertyNode *arg)
+{
+ fgOSFullScreen();
+ return true;
}
/**
static bool
do_tile_cache_reload (const SGPropertyNode * arg)
{
- static const SGPropertyNode *master_freeze
- = fgGetNode("/sim/freeze/master");
+ SGPropertyNode *master_freeze = fgGetNode("/sim/freeze/master");
bool freeze = master_freeze->getBoolValue();
SG_LOG(SG_INPUT, SG_INFO, "ReIniting TileCache");
if ( !freeze ) {
- fgSetBool("/sim/freeze/master", true);
+ master_freeze->setBoolValue(true);
}
globals->get_subsystem("tile-manager")->reinit();
if ( !freeze ) {
- fgSetBool("/sim/freeze/master", false);
+ master_freeze->setBoolValue(false);
}
return true;
}
do_property_cycle (const SGPropertyNode * arg)
{
SGPropertyNode * prop = get_prop(arg);
- vector<SGPropertyNode_ptr> values = arg->getChildren("value");
+ std::vector<SGPropertyNode_ptr> values = arg->getChildren("value");
+
+ bool wrap = arg->getBoolValue("wrap", true);
+ // compatible with knob/pick animations
+ int offset = arg->getIntValue("offset", 1);
+
int selection = -1;
int nSelections = values.size();
// Try to find the current selection
for (int i = 0; i < nSelections; i++) {
if (compare_values(prop, values[i])) {
- selection = i + 1;
+ selection = i;
break;
}
}
- // Default or wrap to the first selection
- if (selection < 0 || selection >= nSelections)
+ if (selection < 0) { // default to first selection
selection = 0;
-
+ } else {
+ selection += offset;
+ if (wrap) {
+ selection = (selection + nSelections) % nSelections;
+ } else {
+ SG_CLAMP_RANGE(selection, 0, nSelections - 1);
+ }
+ }
+
prop->setUnspecifiedValue(values[selection]->getStringValue());
return true;
}
* Built-in command: interpolate a property value over time
*
* property: the name of the property value to interpolate.
+ * type: the interpolation type ("numeric", "color", etc.)
+ * easing: name of easing function (see http://easings.net/)
* value[0..n] any number of constant values to interpolate
* time/rate[0..n] time between each value, number of time elements must
* match those of value elements. Instead of time also rate can
* be used which automatically calculates the time to change
* the property value at the given speed.
* -or-
- * property[1..n] any number of target values taken from named properties
+ * property[1..n+1] any number of target values taken from named properties
* time/rate[0..n] time between each value, number of time elements must
* match those of value elements. Instead of time also rate can
* be used which automatically calculates the time to change
static bool
do_property_interpolate (const SGPropertyNode * arg)
{
- SGPropertyNode * prop = get_prop(arg);
+ SGPropertyNode * prop = get_prop(arg);
+ if( !prop )
+ return false;
- simgear::PropertyList valueNodes = arg->getChildren( "value" );
- simgear::PropertyList timeNodes = arg->getChildren( "time" );
- simgear::PropertyList rateNodes = arg->getChildren( "rate" );
+ simgear::PropertyList time_nodes = arg->getChildren("time");
+ simgear::PropertyList rate_nodes = arg->getChildren("rate");
- if( !timeNodes.empty() && !rateNodes.empty() )
- // mustn't specify time and rate
- return false;
+ if( !time_nodes.empty() && !rate_nodes.empty() )
+ // mustn't specify time and rate
+ return false;
- simgear::PropertyList::size_type num_times = timeNodes.empty()
- ? rateNodes.size()
- : timeNodes.size();
+ simgear::PropertyList::size_type num_times = time_nodes.empty()
+ ? rate_nodes.size()
+ : time_nodes.size();
- boost::scoped_array<double> value;
- boost::scoped_array<double> time;
+ simgear::PropertyList value_nodes = arg->getChildren("value");
+ if( value_nodes.empty() )
+ {
+ simgear::PropertyList prop_nodes = arg->getChildren("property");
- if( valueNodes.size() > 0 ) {
- // must match
- if( num_times != valueNodes.size() )
- return false;
+ // must have one more property node
+ if( prop_nodes.size() != num_times + 1 )
+ return false;
- value.reset( new double[valueNodes.size()] );
- for( simgear::PropertyList::size_type n = 0; n < valueNodes.size(); n++ ) {
- value[n] = valueNodes[n]->getDoubleValue();
- }
- } else {
- valueNodes = arg->getChildren("property");
- // must have one more property node
- if( valueNodes.size() - 1 != num_times )
- return false;
+ value_nodes.reserve(num_times);
+ for( size_t i = 1; i < prop_nodes.size(); ++i )
+ value_nodes.push_back( fgGetNode(prop_nodes[i]->getStringValue()) );
+ }
- value.reset( new double[valueNodes.size()-1] );
- for( simgear::PropertyList::size_type n = 0; n < valueNodes.size()-1; n++ ) {
- value[n] = fgGetNode(valueNodes[n+1]->getStringValue(), "/null")->getDoubleValue();
- }
+ // must match
+ if( value_nodes.size() != num_times )
+ return false;
- }
+ double_list deltas;
+ deltas.reserve(num_times);
- time.reset( new double[num_times] );
- if( !timeNodes.empty() ) {
- for( simgear::PropertyList::size_type n = 0; n < num_times; n++ ) {
- time[n] = timeNodes[n]->getDoubleValue();
- }
- } else {
- for( simgear::PropertyList::size_type n = 0; n < num_times; n++ ) {
- double delta = value[n]
- - (n > 0 ? value[n - 1] : prop->getDoubleValue());
- time[n] = fabs(delta / rateNodes[n]->getDoubleValue());
- }
+ if( !time_nodes.empty() )
+ {
+ for( size_t i = 0; i < num_times; ++i )
+ deltas.push_back( time_nodes[i]->getDoubleValue() );
+ }
+ else
+ {
+ for( size_t i = 0; i < num_times; ++i )
+ {
+ // TODO calculate delta based on property type
+ double delta = value_nodes[i]->getDoubleValue()
+ - ( i > 0
+ ? value_nodes[i - 1]->getDoubleValue()
+ : prop->getDoubleValue()
+ );
+ deltas.push_back( fabs(delta / rate_nodes[i]->getDoubleValue()) );
}
+ }
- ((SGInterpolator*)globals->get_subsystem_mgr()
- ->get_group(SGSubsystemMgr::INIT)->get_subsystem("interpolator"))
- ->interpolate(prop, num_times, value.get(), time.get() );
-
- return true;
+ return prop->interpolate
+ (
+ arg->getStringValue("type", "numeric"),
+ value_nodes,
+ deltas,
+ arg->getStringValue("easing", "linear")
+ );
}
/**
return true;
}
-
-/**
- * Set mouse cursor coordinates and cursor shape.
- */
-static bool
-do_set_cursor (const SGPropertyNode * arg)
-{
- if (arg->hasValue("x") || arg->hasValue("y")) {
- SGPropertyNode *mx = fgGetNode("/devices/status/mice/mouse/x", true);
- SGPropertyNode *my = fgGetNode("/devices/status/mice/mouse/y", true);
- int x = arg->getIntValue("x", mx->getIntValue());
- int y = arg->getIntValue("y", my->getIntValue());
- fgWarpMouse(x, y);
- mx->setIntValue(x);
- my->setIntValue(y);
- }
-
- SGPropertyNode *cursor = const_cast<SGPropertyNode *>(arg)->getNode("cursor", true);
- if (cursor->getType() != simgear::props::NONE)
- fgSetMouseCursor(cursor->getIntValue());
-
- cursor->setIntValue(fgGetMouseCursor());
- return true;
-}
-
-
/**
* Built-in command: play an audio message (i.e. a wav file) This is
* fire and forget. Call this once per message and it will get dumped
return true;
}
-class RemoteXMLRequest : public simgear::HTTP::Request
+class RemoteXMLRequest:
+ public simgear::HTTP::MemoryRequest
{
public:
SGPropertyNode_ptr _complete;
SGPropertyNode_ptr _status;
SGPropertyNode_ptr _failed;
SGPropertyNode_ptr _target;
- string propsData;
-
- RemoteXMLRequest(const std::string& url, SGPropertyNode* targetNode) :
- simgear::HTTP::Request(url),
- _target(targetNode)
+
+ RemoteXMLRequest(const std::string& url, SGPropertyNode* targetNode) :
+ simgear::HTTP::MemoryRequest(url),
+ _target(targetNode)
{
}
{
_failed = p;
}
+
protected:
- virtual void gotBodyData(const char* s, int n)
+
+ virtual void onFail()
{
- propsData += string(s, n);
+ SG_LOG(SG_IO, SG_INFO, "network level failure in RemoteXMLRequest");
+ if (_failed) {
+ _failed->setBoolValue(true);
+ }
}
- virtual void responseComplete()
+ virtual void onDone()
{
int response = responseCode();
bool failed = false;
if (response == 200) {
try {
- const char* buffer = propsData.c_str();
- readProperties(buffer, propsData.size(), _target, true);
+ const char* buffer = responseBody().c_str();
+ readProperties(buffer, responseBody().size(), _target, true);
} catch (const sg_exception &e) {
SG_LOG(SG_IO, SG_WARN, "parsing XML from remote, failed: " << e.getFormattedMessage());
failed = true;
// now the response data is output, signal Nasal / listeners
if (_complete) _complete->setBoolValue(true);
if (_status) _status->setIntValue(response);
- if (_failed) _failed->setBoolValue(failed);
+ if (_failed && failed) _failed->setBoolValue(true);
}
};
static bool
do_load_xml_from_url(const SGPropertyNode * arg)
{
+ FGHTTPClient* http = static_cast<FGHTTPClient*>(globals->get_subsystem("http"));
+ if (!http) {
+ SG_LOG(SG_IO, SG_ALERT, "xmlhttprequest: HTTP client not running");
+ return false;
+ }
+
std::string url(arg->getStringValue("url"));
if (url.empty())
return false;
RemoteXMLRequest* req = new RemoteXMLRequest(url, targetnode);
+ if (arg->hasChild("body"))
+ req->setBodyData(arg->getChild("body"));
+
// connect up optional reporting properties
if (arg->hasValue("complete"))
req->setCompletionProp(fgGetNode(arg->getStringValue("complete"), true));
if (arg->hasValue("status"))
req->setStatusProp(fgGetNode(arg->getStringValue("status"), true));
- FGHTTPClient::instance()->makeRequest(req);
-
+ http->makeRequest(req);
return true;
}
// Optional profiling commands using gperftools:
// http://code.google.com/p/gperftools/
-#ifndef FG_HAVE_GPERFTOOLS
+#if !FG_HAVE_GPERFTOOLS
static void
no_profiling_support()
{
static bool
do_profiler_start(const SGPropertyNode *arg)
{
-#ifdef FG_HAVE_GPERFTOOLS
+#if FG_HAVE_GPERFTOOLS
const char *filename = arg->getStringValue("filename", "fgfs.profile");
ProfilerStart(filename);
return true;
static bool
do_profiler_stop(const SGPropertyNode *arg)
{
-#ifdef FG_HAVE_GPERFTOOLS
+#if FG_HAVE_GPERFTOOLS
ProfilerStop();
return true;
#else
#endif
}
+
////////////////////////////////////////////////////////////////////////
// Command setup.
////////////////////////////////////////////////////////////////////////
{ "load-tape", do_load_tape },
{ "panel-load", do_panel_load },
{ "preferences-load", do_preferences_load },
+ { "toggle-fullscreen", do_toggle_fullscreen },
{ "view-cycle", do_view_cycle },
{ "screen-capture", do_screen_capture },
{ "hires-screen-capture", do_hires_screen_capture },
{ "open-browser", do_open_browser },
{ "gui-redraw", do_gui_redraw },
{ "add-model", do_add_model },
- { "set-cursor", do_set_cursor },
{ "play-audio-sample", do_play_audio_sample },
{ "presets-commit", do_presets_commit },
{ "log-level", do_log_level },
typedef bool (*dummy)();
fgTie( "/command/view/next", dummy(0), do_view_next );
fgTie( "/command/view/prev", dummy(0), do_view_prev );
+
+ globals->get_props()->setValueReadOnly( "/sim/debug/profiler-available",
+ bool(FG_HAVE_GPERFTOOLS) );
}
// end of fg_commands.cxx