1
0
Fork 0

Merge branch 'next' into comm-subsystem

This commit is contained in:
adrian 2011-11-24 10:20:34 +02:00
commit 0025dfb9bc
46 changed files with 3332 additions and 2662 deletions

View file

@ -20,6 +20,7 @@ string(STRIP ${versionFile} FLIGHTGEAR_VERSION)
#packaging
# split version string into components, note CMAKE_MATCH_0 is the entire regexp match
file(READ .gitignore CPACK_SOURCE_IGNORE_FILES)
string(REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)" CPACK_PACKAGE_VERSION ${FLIGHTGEAR_VERSION} )
set(CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1})
set(CPACK_PACKAGE_VERSION_MINOR ${CMAKE_MATCH_2})
@ -29,8 +30,8 @@ SET(CPACK_RESOURCE_FILE_README "${PROJECT_SOURCE_DIR}/README")
set(CPACK_SOURCE_GENERATOR TBZ2 ZIP)
set(CPACK_SOURCE_PACKAGE_FILE_NAME "flightgear-${FLIGHTGEAR_VERSION}" CACHE INTERNAL "tarball basename")
set(CPACK_SOURCE_IGNORE_FILES
"^${PROJECT_SOURCE_DIR}/.git;\\\\.gitignore;Makefile.am;~$;${CPACK_SOURCE_IGNORE_FILES}")
#set(CPACK_SOURCE_IGNORE_FILES
# "^${PROJECT_SOURCE_DIR}/.git;\\\\.gitignore;Makefile.am;~$;${CPACK_SOURCE_IGNORE_FILES}")
include (CPack)
@ -64,7 +65,8 @@ IF(APPLE)
set(EVENT_INPUT_DEFAULT 1)
find_library(CORESERVICES_LIBRARY CoreServices)
list(APPEND PLATFORM_LIBS ${CORESERVICES_LIBRARY})
find_library(COCOA_LIBRARY Cocoa)
list(APPEND PLATFORM_LIBS ${COCOA_LIBRARY} ${CORESERVICES_LIBRARY})
elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
# disabled while DBus / HAL / udev issues are decided

View file

@ -385,14 +385,6 @@
RelativePath="..\..\..\src\Aircraft\controls.hxx"
>
</File>
<File
RelativePath="..\..\..\src\Aircraft\replay.cxx"
>
</File>
<File
RelativePath="..\..\..\src\Aircraft\replay.hxx"
>
</File>
<File
RelativePath="..\..\..\src\Aircraft\flightrecorder.cxx"
>
@ -401,6 +393,14 @@
RelativePath="..\..\..\src\Aircraft\flightrecorder.hxx"
>
</File>
<File
RelativePath="..\..\..\src\Aircraft\replay.cxx"
>
</File>
<File
RelativePath="..\..\..\src\Aircraft\replay.hxx"
>
</File>
</Filter>
<Filter
Name="Lib_Airports"
@ -2525,6 +2525,38 @@
RelativePath="..\..\..\src\GUI\dialog.hxx"
>
</File>
<File
RelativePath="..\..\..\src\GUI\FGColor.cxx"
>
</File>
<File
RelativePath="..\..\..\src\GUI\FGColor.hxx"
>
</File>
<File
RelativePath="..\..\..\src\GUI\FGFontCache.cxx"
>
</File>
<File
RelativePath="..\..\..\src\GUI\FGFontCache.hxx"
>
</File>
<File
RelativePath="..\..\..\src\GUI\FGPUIDialog.cxx"
>
</File>
<File
RelativePath="..\..\..\src\GUI\FGPUIDialog.hxx"
>
</File>
<File
RelativePath="..\..\..\src\GUI\FGPUIMenuBar.cxx"
>
</File>
<File
RelativePath="..\..\..\src\GUI\FGPUIMenuBar.hxx"
>
</File>
<File
RelativePath="..\..\..\src\Gui\fonts.cxx"
>
@ -3753,6 +3785,14 @@
RelativePath="..\..\..\src\Instrumentation\mrg.hxx"
>
</File>
<File
RelativePath="..\..\..\src\Instrumentation\NavDisplay.cxx"
>
</File>
<File
RelativePath="..\..\..\src\Instrumentation\NavDisplay.hxx"
>
</File>
<File
RelativePath="..\..\..\src\Instrumentation\navradio.cxx"
>
@ -3777,14 +3817,6 @@
RelativePath="..\..\..\src\Instrumentation\od_gauge.hxx"
>
</File>
<File
RelativePath="..\..\..\src\Instrumentation\NavDisplay.cxx"
>
</File>
<File
RelativePath="..\..\..\src\Instrumentation\NavDisplay.hxx"
>
</File>
<File
RelativePath="..\..\..\src\Instrumentation\rad_alt.cxx"
>

View file

@ -42,6 +42,7 @@
#include <Main/globals.hxx>
#include <Scenery/scenery.hxx>
#include <Scripting/NasalSys.hxx>
#include <Sound/fg_fx.hxx>
#include "AIBase.hxx"
#include "AIManager.hxx"
@ -70,7 +71,8 @@ FGAIBase::FGAIBase(object_type ot, bool enableHot) :
_impact_speed(0),
_refID( _newAIModelID() ),
_otype(ot),
_initialized(false)
_initialized(false),
_fx(0)
{
tgt_heading = hdg = tgt_altitude_ft = tgt_speed = 0.0;
@ -137,6 +139,9 @@ FGAIBase::~FGAIBase() {
if (parent)
model_removed->setStringValue(props->getPath());
}
delete _fx;
_fx = 0;
delete fp;
fp = 0;
}
@ -198,6 +203,19 @@ void FGAIBase::update(double dt) {
ft_per_deg_lat = 366468.96 - 3717.12 * cos(pos.getLatitudeRad());
ft_per_deg_lon = 365228.16 * cos(pos.getLatitudeRad());
if ( _fx )
{
// update model's audio sample values
_fx->set_position_geod( pos );
SGQuatd orient = SGQuatd::fromYawPitchRollDeg(hdg, pitch, roll);
_fx->set_orientation( orient );
SGVec3d velocity;
velocity = SGVec3d( speed_north_deg_sec, speed_east_deg_sec, pitch*speed );
_fx->set_velocity( velocity );
}
}
/** update LOD properties of the model */
@ -293,6 +311,20 @@ bool FGAIBase::init(bool search_in_AI_path) {
aip.setVisible(true);
invisible = false;
globals->get_scenery()->get_scene_graph()->addChild(aip.getSceneGraph());
// Get the sound-path tag from the configuration file and store it
// in the property tree.
string fxpath = props->getStringValue("sim/sound/path");
if ( !fxpath.empty() )
{
props->setStringValue("sim/sound/path", fxpath.c_str());
// initialize the sound configuration
SGSoundMgr *smgr = globals->get_soundmgr();
_fx = new FGFX(smgr, "aifx:"+f, props);
_fx->init();
}
_initialized = true;
} else if (!model_path.empty()) {
@ -400,7 +432,12 @@ void FGAIBase::bind() {
props->setDoubleValue("controls/flight/target-alt", altitude_ft);
props->setDoubleValue("controls/flight/target-pitch", pitch);
props->setDoubleValue("controls/flight/target-spd", speed);
props->setDoubleValue("controls/flight/target-spd", speed);
props->setBoolValue("sim/sound/avionics/enabled", false);
props->setDoubleValue("sim/sound/avionics/volume", 0.0);
props->setBoolValue("sim/sound/avionics/external-view", false);
props->setBoolValue("sim/current-view/internal", false);
}

View file

@ -43,6 +43,7 @@ using std::list;
class SGMaterial;
class FGAIManager;
class FGAIFlightPlan;
class FGFX;
class FGAIBase : public SGReferenced {
@ -225,6 +226,7 @@ private:
object_type _otype;
bool _initialized;
osg::ref_ptr<osg::LOD> _model; //The 3D model LOD object
SGSharedPtr<FGFX> _fx;
public:
object_type getType();

View file

@ -146,7 +146,7 @@ FGAIManager::update(double dt) {
if (!enabled)
return;
FGTrafficManager *tmgr = (FGTrafficManager*) globals->get_subsystem("Traffic Manager");
FGTrafficManager *tmgr = (FGTrafficManager*) globals->get_subsystem("traffic-manager");
_dt = dt;
ai_list_iterator ai_list_itr = ai_list.begin();

View file

@ -45,7 +45,7 @@ FGSubmodelMgr::~FGSubmodelMgr()
FGAIManager* FGSubmodelMgr::aiManager()
{
return (FGAIManager*)globals->get_subsystem("ai_model");
return (FGAIManager*)globals->get_subsystem("ai-model");
}
void FGSubmodelMgr::init()

View file

@ -24,6 +24,7 @@
#include <Main/fg_commands.hxx>
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
#include <simgear/constants.h>
#include <simgear/structure/commands.hxx>

View file

@ -30,6 +30,7 @@
#include <Main/globals.hxx>
#include <GUI/gui.h> // mkDialog
#include <GUI/new_gui.hxx>
#include <Main/fg_props.hxx>
#include "ATCDialogOld.hxx"
#include "ATC.hxx"

View file

@ -57,7 +57,7 @@
#include <Main/fg_props.hxx>
#include <Main/viewmgr.hxx>
#include <Time/light.hxx>
#include <GUI/new_gui.hxx> // FGFontCache
#include <GUI/FGFontCache.hxx>
#include <Main/viewer.hxx>
#include <Instrumentation/dclgps.hxx>

View file

@ -261,8 +261,8 @@ FGGasCell::~FGGasCell()
void FGGasCell::Calculate(double dt)
{
const double AirTemperature = in.Temperature; // [Rankine]
const double AirPressure = in.Pressure; // [lbs/ft²]
const double AirDensity = in.Density; // [slug/ft³]
const double AirPressure = in.Pressure; // [lbs/ft^2]
const double AirDensity = in.Density; // [slug/ft^3]
const double g = in.gravity; // [lbs/slug]
const double OldTemperature = Temperature;
@ -689,8 +689,8 @@ FGBallonet::~FGBallonet()
void FGBallonet::Calculate(double dt)
{
const double ParentPressure = Parent->GetPressure(); // [lbs/ft²]
const double AirPressure = Pressure; // [lbs/ft²]
const double ParentPressure = Parent->GetPressure(); // [lbs/ft^2]
const double AirPressure = in.Pressure; // [lbs/ft^2]
const double OldTemperature = Temperature;
const double OldPressure = Pressure;

View file

@ -5,7 +5,7 @@
#include <simgear/compiler.h>
#include <plib/puAux.h>
#include "dialog.hxx"
#include "FGPUIDialog.hxx"
class FGAirportList;

View file

@ -6,14 +6,18 @@ set(SOURCES
SafeTexFont.cxx
WaypointList.cxx
dialog.cxx
FGPUIDialog.cxx
fonts.cxx
gui.cxx
gui_funcs.cxx
layout-props.cxx
layout.cxx
menubar.cxx
FGPUIMenuBar.cxx
new_gui.cxx
property_list.cxx
FGFontCache.cxx
FGColor.cxx
)
set(HEADERS
@ -22,11 +26,20 @@ set(HEADERS
SafeTexFont.hxx
WaypointList.hxx
dialog.hxx
FGPUIDialog.hxx
gui.h
layout.hxx
menubar.hxx
FGPUIMenuBar.hxx
new_gui.hxx
property_list.hxx
FGFontCache.hxx
FGColor.hxx
)
if (APPLE)
list(APPEND HEADERS FGCocoaMenuBar.hxx)
list(APPEND SOURCES FGCocoaMenuBar.mm)
endif()
flightgear_component(GUI "${SOURCES}" "${HEADERS}")

View file

@ -0,0 +1,65 @@
// menubar.hxx - XML-configured menu bar.
#ifndef FG_COCOA_MENUBAR_HXX
#define FG_COCOA_MENUBAR_HXX 1
#include <GUI/menubar.hxx>
#include <memory>
/**
* XML-configured Cocoa menu bar.
*
* This class creates a menu bar from a tree of XML properties. These
* properties are not part of the main FlightGear property tree, but
* are read from a separate file ($FG_ROOT/gui/menubar.xml).
*
* WARNING: because PUI provides no easy way to attach user data to a
* menu item, all menu item strings must be unique; otherwise, this
* class will always use the first binding with any given name.
*/
class FGCocoaMenuBar : public FGMenuBar
{
public:
/**
* Constructor.
*/
FGCocoaMenuBar ();
/**
* Destructor.
*/
virtual ~FGCocoaMenuBar ();
/**
* Initialize the menu bar from $FG_ROOT/gui/menubar.xml
*/
virtual void init ();
/**
* Make the menu bar visible.
*/
virtual void show ();
/**
* Make the menu bar invisible.
*/
virtual void hide ();
/**
* Test whether the menu bar is visible.
*/
virtual bool isVisible () const;
class CocoaMenuBarPrivate;
private:
std::auto_ptr<CocoaMenuBarPrivate> p;
};
#endif // __MENUBAR_HXX

231
src/GUI/FGCocoaMenuBar.mm Normal file
View file

@ -0,0 +1,231 @@
#include "FGCocoaMenuBar.hxx"
#include <Cocoa/Cocoa.h>
#include <boost/foreach.hpp>
#include <simgear/props/props.hxx>
#include <simgear/props/props_io.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/structure/SGBinding.hxx>
#include <Main/fg_props.hxx>
#include <iostream>
using std::string;
using std::map;
using std::cout;
typedef std::map<NSMenuItem*, SGBindingList> MenuItemBindings;
@class CocoaMenuDelegate;
class FGCocoaMenuBar::CocoaMenuBarPrivate
{
public:
CocoaMenuBarPrivate();
~CocoaMenuBarPrivate();
bool labelIsSeparator(const std::string& s) const;
void menuFromProps(NSMenu* menu, SGPropertyNode* menuNode);
void fireBindingsForItem(NSMenuItem* item);
public:
CocoaMenuDelegate* delegate;
MenuItemBindings itemBindings;
};
@interface CocoaMenuDelegate : NSObject <NSMenuDelegate> {
@private
FGCocoaMenuBar::CocoaMenuBarPrivate* peer;
}
@property (nonatomic, assign) FGCocoaMenuBar::CocoaMenuBarPrivate* peer;
@end
@implementation CocoaMenuDelegate
@synthesize peer;
- (void) itemAction:(id) sender
{
peer->fireBindingsForItem((NSMenuItem*) sender);
}
@end
static NSString* stdStringToCocoa(const string& s)
{
return [NSString stringWithUTF8String:s.c_str()];
}
class EnabledListener : public SGPropertyChangeListener
{
public:
EnabledListener(NSMenuItem* i) :
item(i)
{}
virtual void valueChanged(SGPropertyNode *node)
{
BOOL b = node->getBoolValue();
[item setEnabled:b];
}
private:
NSMenuItem* item;
};
FGCocoaMenuBar::CocoaMenuBarPrivate::CocoaMenuBarPrivate()
{
delegate = [[CocoaMenuDelegate alloc] init];
delegate.peer = this;
}
FGCocoaMenuBar::CocoaMenuBarPrivate::~CocoaMenuBarPrivate()
{
[delegate release];
}
bool FGCocoaMenuBar::CocoaMenuBarPrivate::labelIsSeparator(const std::string& s) const
{
for (unsigned int i=0; i<s.size(); ++i) {
if (s[i] != '-') {
return false;
}
}
return true;
}
void FGCocoaMenuBar::CocoaMenuBarPrivate::menuFromProps(NSMenu* menu, SGPropertyNode* menuNode)
{
int index = 0;
BOOST_FOREACH(SGPropertyNode_ptr n, menuNode->getChildren("item")) {
if (!n->hasValue("enabled")) {
n->setBoolValue("enabled", true);
}
string l = n->getStringValue("label");
string::size_type pos = l.find("(");
if (pos != string::npos) {
l = l.substr(0, pos);
}
NSString* label = stdStringToCocoa(l);
NSString* shortcut = @"";
NSMenuItem* item;
if (index >= [menu numberOfItems]) {
if (labelIsSeparator(l)) {
item = [NSMenuItem separatorItem];
[menu addItem:item];
} else {
item = [menu addItemWithTitle:label action:nil keyEquivalent:shortcut];
n->getNode("enabled")->addChangeListener(new EnabledListener(item));
[item setTarget:delegate];
[item setAction:@selector(itemAction:)];
}
} else {
item = [menu itemAtIndex:index];
[item setTitle:label];
}
BOOL enabled = n->getBoolValue("enabled");
[item setEnabled:enabled];
SGBindingList bl;
BOOST_FOREACH(SGPropertyNode_ptr binding, n->getChildren("binding")) {
// have to clone the bindings, since SGBinding takes ownership of the
// passed in node. Seems like something is wrong here, but following the
// PUI code for the moment.
SGPropertyNode* cloned(new SGPropertyNode);
copyProperties(binding, cloned);
bl.push_back(new SGBinding(cloned, globals->get_props()));
}
itemBindings[item] = bl;
++index;
} // of item iteration
}
void FGCocoaMenuBar::CocoaMenuBarPrivate::fireBindingsForItem(NSMenuItem *item)
{
MenuItemBindings::iterator it = itemBindings.find(item);
if (it == itemBindings.end()) {
return;
}
BOOST_FOREACH(SGSharedPtr<SGBinding> b, it->second) {
b->fire();
}
}
FGCocoaMenuBar::FGCocoaMenuBar() :
p(new CocoaMenuBarPrivate)
{
}
FGCocoaMenuBar::~FGCocoaMenuBar()
{
}
void FGCocoaMenuBar::init()
{
NSMenu* mainBar = [[NSApplication sharedApplication] mainMenu];
SGPropertyNode_ptr props = fgGetNode("/sim/menubar/default",true);
int index = 0;
NSMenuItem* previousMenu = [mainBar itemAtIndex:0];
if (![[previousMenu title] isEqualToString:@"FlightGear"]) {
[previousMenu setTitle:@"FlightGear"];
}
BOOST_FOREACH(SGPropertyNode_ptr n, props->getChildren("menu")) {
NSString* label = stdStringToCocoa(n->getStringValue("label"));
NSMenuItem* item = [mainBar itemWithTitle:label];
NSMenu* menu;
if (!item) {
NSInteger insertIndex = [mainBar indexOfItem:previousMenu] + 1;
item = [mainBar insertItemWithTitle:label action:nil keyEquivalent:@"" atIndex:insertIndex];
item.tag = index + 400;
menu = [[NSMenu alloc] init];
menu.title = label;
[menu setAutoenablesItems:NO];
[mainBar setSubmenu:menu forItem:item];
[menu autorelease];
} else {
menu = item.submenu;
}
// synchronise menu with properties
p->menuFromProps(menu, n);
++index;
previousMenu = item;
}
}
bool FGCocoaMenuBar::isVisible() const
{
return true;
}
void FGCocoaMenuBar::show()
{
// no-op
}
void FGCocoaMenuBar::hide()
{
// no-op
}

55
src/GUI/FGColor.cxx Normal file
View file

@ -0,0 +1,55 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "FGColor.hxx"
#include <iostream>
#include <simgear/props/props.hxx>
#include <simgear/math/SGMath.hxx>
////////////////////////////////////////////////////////////////////////
// FGColor class.
////////////////////////////////////////////////////////////////////////
void
FGColor::print() const {
std::cerr << "red=" << _red << ", green=" << _green
<< ", blue=" << _blue << ", alpha=" << _alpha << std::endl;
}
bool
FGColor::merge(const SGPropertyNode *node)
{
if (!node)
return false;
bool dirty = false;
const SGPropertyNode * n;
if ((n = node->getNode("red")))
_red = n->getFloatValue(), dirty = true;
if ((n = node->getNode("green")))
_green = n->getFloatValue(), dirty = true;
if ((n = node->getNode("blue")))
_blue = n->getFloatValue(), dirty = true;
if ((n = node->getNode("alpha")))
_alpha = n->getFloatValue(), dirty = true;
return dirty;
}
bool
FGColor::merge(const FGColor *color)
{
bool dirty = false;
if (color && color->_red >= 0.0)
_red = color->_red, dirty = true;
if (color && color->_green >= 0.0)
_green = color->_green, dirty = true;
if (color && color->_blue >= 0.0)
_blue = color->_blue, dirty = true;
if (color && color->_alpha >= 0.0)
_alpha = color->_alpha, dirty = true;
return dirty;
}

49
src/GUI/FGColor.hxx Normal file
View file

@ -0,0 +1,49 @@
#ifndef FG_GUI_COLOR_HXX
#define FG_GUI_COLOR_HXX
// forward decls
class SGPropertyNode;
class FGColor {
public:
FGColor() { clear(); }
FGColor(float r, float g, float b, float a = 1.0f) { set(r, g, b, a); }
FGColor(const SGPropertyNode *prop) { set(prop); }
FGColor(FGColor *c) {
if (c) set(c->_red, c->_green, c->_blue, c->_alpha);
}
inline void clear() { _red = _green = _blue = _alpha = -1.0f; }
// merges in non-negative components from property with children <red> etc.
bool merge(const SGPropertyNode *prop);
bool merge(const FGColor *color);
bool set(const SGPropertyNode *prop) { clear(); return merge(prop); };
bool set(const FGColor *color) { clear(); return merge(color); }
bool set(float r, float g, float b, float a = 1.0f) {
_red = r, _green = g, _blue = b, _alpha = a;
return true;
}
bool isValid() const {
return _red >= 0.0 && _green >= 0.0 && _blue >= 0.0;
}
void print() const;
inline void setRed(float red) { _red = red; }
inline void setGreen(float green) { _green = green; }
inline void setBlue(float blue) { _blue = blue; }
inline void setAlpha(float alpha) { _alpha = alpha; }
inline float red() const { return clamp(_red); }
inline float green() const { return clamp(_green); }
inline float blue() const { return clamp(_blue); }
inline float alpha() const { return _alpha < 0.0 ? 1.0 : clamp(_alpha); }
protected:
float _red, _green, _blue, _alpha;
private:
float clamp(float f) const { return f < 0.0 ? 0.0 : f > 1.0 ? 1.0 : f; }
};
#endif

223
src/GUI/FGFontCache.cxx Normal file
View file

@ -0,0 +1,223 @@
//
// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif
#include "FGFontCache.hxx"
#include <plib/fnt.h>
#include <plib/pu.h>
#include <simgear/props/props.hxx>
#include <Main/globals.hxx>
////////////////////////////////////////////////////////////////////////
// FGFontCache class.
////////////////////////////////////////////////////////////////////////
extern puFont FONT_HELVETICA_14;
extern puFont FONT_SANS_12B;
namespace
{
struct GuiFont
{
const char *name;
puFont *font;
struct Predicate
: public std::unary_function<const GuiFont, bool>
{
Predicate(const char* name_) : name(name_) {}
bool operator() (const GuiFont& f1) const
{
return ::strcmp(f1.name, name) == 0;
}
const char* name;
};
};
const GuiFont guifonts[] = {
{ "default", &PUFONT_HELVETICA_12 },
{ "FIXED_8x13", &PUFONT_8_BY_13 },
{ "FIXED_9x15", &PUFONT_9_BY_15 },
{ "TIMES_10", &PUFONT_TIMES_ROMAN_10 },
{ "TIMES_24", &PUFONT_TIMES_ROMAN_24 },
{ "HELVETICA_10", &PUFONT_HELVETICA_10 },
{ "HELVETICA_12", &PUFONT_HELVETICA_12 },
{ "HELVETICA_14", &FONT_HELVETICA_14 },
{ "HELVETICA_18", &PUFONT_HELVETICA_18 },
{ "SANS_12B", &FONT_SANS_12B }
};
const GuiFont* guifontsEnd = &guifonts[sizeof(guifonts)/ sizeof(guifonts[0])];
}
FGFontCache::FGFontCache() :
_initialized(false)
{
}
FGFontCache::~FGFontCache()
{
PuFontMap::iterator it, end = _puFonts.end();
for (it = _puFonts.begin(); it != end; ++it)
delete it->second;
}
inline bool FGFontCache::FntParamsLess::operator()(const FntParams& f1,
const FntParams& f2) const
{
int comp = f1.name.compare(f2.name);
if (comp < 0)
return true;
else if (comp > 0)
return false;
if (f1.size < f2.size)
return true;
else if (f1.size > f2.size)
return false;
return f1.slant < f2.slant;
}
struct FGFontCache::fnt *
FGFontCache::getfnt(const char *name, float size, float slant)
{
std::string fontName(name);
FntParams fntParams(fontName, size, slant);
PuFontMap::iterator i = _puFonts.find(fntParams);
if (i != _puFonts.end())
return i->second;
// fntTexFont s are all preloaded into the _texFonts map
TexFontMap::iterator texi = _texFonts.find(fontName);
fntTexFont* texfont = 0;
puFont* pufont = 0;
if (texi != _texFonts.end()) {
texfont = texi->second;
} else {
const GuiFont* guifont = std::find_if(&guifonts[0], guifontsEnd,
GuiFont::Predicate(name));
if (guifont != guifontsEnd) {
pufont = guifont->font;
}
}
fnt* f = new fnt;
if (pufont) {
f->pufont = pufont;
} else if (texfont) {
f->texfont = texfont;
f->pufont = new puFont;
f->pufont->initialize(static_cast<fntFont *>(f->texfont), size, slant);
} else {
f->pufont = guifonts[0].font;
}
_puFonts[fntParams] = f;
return f;
}
puFont *
FGFontCache::get(const char *name, float size, float slant)
{
return getfnt(name, size, slant)->pufont;
}
fntTexFont *
FGFontCache::getTexFont(const char *name, float size, float slant)
{
init();
return getfnt(name, size, slant)->texfont;
}
puFont *
FGFontCache::get(SGPropertyNode *node)
{
if (!node)
return get("Helvetica.txf", 15.0, 0.0);
const char *name = node->getStringValue("name", "Helvetica.txf");
float size = node->getFloatValue("size", 15.0);
float slant = node->getFloatValue("slant", 0.0);
return get(name, size, slant);
}
void FGFontCache::init()
{
if (!_initialized) {
char *envp = ::getenv("FG_FONTS");
if (envp != NULL) {
_path.set(envp);
} else {
_path.set(globals->get_fg_root());
_path.append("Fonts");
}
_initialized = true;
}
}
SGPath
FGFontCache::getfntpath(const char *name)
{
init();
SGPath path(_path);
if (name && std::string(name) != "") {
path.append(name);
if (path.exists())
return path;
}
path = SGPath(_path);
path.append("Helvetica.txf");
return path;
}
bool FGFontCache::initializeFonts()
{
static std::string fontext("txf");
init();
ulDir* fontdir = ulOpenDir(_path.c_str());
if (!fontdir)
return false;
const ulDirEnt *dirEntry;
while ((dirEntry = ulReadDir(fontdir)) != 0) {
SGPath path(_path);
path.append(dirEntry->d_name);
if (path.extension() == fontext) {
fntTexFont* f = new fntTexFont;
if (f->load((char *)path.c_str()))
_texFonts[std::string(dirEntry->d_name)] = f;
else
delete f;
}
}
ulCloseDir(fontdir);
return true;
}
FGFontCache::fnt::~fnt()
{
if (texfont) {
delete pufont;
delete texfont;
}
}

96
src/GUI/FGFontCache.hxx Normal file
View file

@ -0,0 +1,96 @@
// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#ifndef __FGFONTCACHE_HXX
#define __FGFONTCACHE_HXX
#include <simgear/math/SGMath.hxx>
#include <simgear/misc/sg_path.hxx>
#include <map>
#include <algorithm>
// forward decls
class SGPropertyNode;
class puFont;
class fntTexFont;
/**
* A class to keep all fonts available for future use.
* This also assures a font isn't resident more than once.
*/
class FGFontCache {
private:
// The parameters of a request to the cache.
struct FntParams
{
const std::string name;
const float size;
const float slant;
FntParams() : size(0.0f), slant(0.0f) {}
FntParams(const FntParams& rhs)
: name(rhs.name), size(rhs.size), slant(rhs.slant)
{
}
FntParams(const std::string& name_, float size_, float slant_)
: name(name_), size(size_), slant(slant_)
{
}
};
struct FntParamsLess
: public std::binary_function<const FntParams, const FntParams, bool>
{
bool operator() (const FntParams& f1, const FntParams& f2) const;
};
struct fnt {
fnt(puFont *pu = 0) : pufont(pu), texfont(0) {}
~fnt();
// Font used by plib GUI code
puFont *pufont;
// TXF font
fntTexFont *texfont;
};
// Path to the font directory
SGPath _path;
typedef std::map<const std::string, fntTexFont*> TexFontMap;
typedef std::map<const FntParams, fnt*, FntParamsLess> PuFontMap;
TexFontMap _texFonts;
PuFontMap _puFonts;
bool _initialized;
struct fnt *getfnt(const char *name, float size, float slant);
void init();
public:
FGFontCache();
~FGFontCache();
puFont *get(const char *name, float size=15.0, float slant=0.0);
puFont *get(SGPropertyNode *node);
fntTexFont *getTexFont(const char *name, float size=15.0, float slant=0.0);
SGPath getfntpath(const char *name);
/**
* Preload all the fonts in the FlightGear font directory. It is
* important to load the font textures early, with the proper
* graphics context current, so that no plib (or our own) code
* tries to load a font from disk when there's no current graphics
* context.
*/
bool initializeFonts();
};
#endif

1418
src/GUI/FGPUIDialog.cxx Normal file

File diff suppressed because it is too large Load diff

277
src/GUI/FGPUIDialog.hxx Normal file
View file

@ -0,0 +1,277 @@
// FGPUIDialog.hxx - XML-configured dialog box.
#ifndef FG_PUI_DIALOG_HXX
#define FG_PUI_DIALOG_HXX 1
#include "dialog.hxx"
#include <plib/puAux.h>
#include <simgear/props/props.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/condition.hxx>
#include <vector>
// ugly temporary workaround for plib's lack of user defined class ids FIXME
#define FGCLASS_LIST 0x00000001
#define FGCLASS_AIRPORTLIST 0x00000002
#define FGCLASS_PROPERTYLIST 0x00000004
#define FGCLASS_WAYPOINTLIST 0x00000008
class GUI_ID { public: GUI_ID(int id) : id(id) {} virtual ~GUI_ID() {} int id; };
class NewGUI;
class FGColor;
class puObject;
class puFont;
/**
* An XML-configured dialog box.
*
* The GUI manager stores only the property tree for the dialog
* boxes. This class creates a PUI dialog box on demand from
* the properties in that tree. The manager recreates the dialog
* every time it needs to show it.
*/
class FGPUIDialog : public FGDialog
{
public:
/**
* Construct a new GUI widget configured by a property tree.
*
* The configuration properties are not part of the main
* FlightGear property tree; the GUI manager reads them
* from individual configuration files.
*
* @param props A property tree describing the dialog.
*/
FGPUIDialog (SGPropertyNode * props);
/**
* Destructor.
*/
virtual ~FGPUIDialog ();
/**
* Update the values of all GUI objects with a specific name,
* or all if name is 0 (default).
*
* This method copies values from the FlightGear property tree to
* the GUI object(s).
*
* @param objectName The name of the GUI object(s) to update.
* Use the empty name for all unnamed objects.
*/
virtual void updateValues (const char * objectName = 0);
/**
* Apply the values of all GUI objects with a specific name,
* or all if name is 0 (default)
*
* This method copies values from the GUI object(s) to the
* FlightGear property tree.
*
* @param objectName The name of the GUI object(s) to update.
* Use the empty name for all unnamed objects.
*/
virtual void applyValues (const char * objectName = 0);
/**
* Update state. Called on active dialogs before rendering.
*/
virtual void update ();
/**
* Recompute the dialog's layout
*/
void relayout();
void setNeedsLayout() {
_needsRelayout = true;
}
private:
enum {
BACKGROUND = 0x01,
FOREGROUND = 0x02,
HIGHLIGHT = 0x04,
LABEL = 0x08,
LEGEND = 0x10,
MISC = 0x20,
EDITFIELD = 0x40
};
// Show the dialog.
void display (SGPropertyNode * props);
// Build the dialog or a subobject of it.
puObject * makeObject (SGPropertyNode * props,
int parentWidth, int parentHeight);
// Common configuration for all GUI objects.
void setupObject (puObject * object, SGPropertyNode * props);
// Common configuration for all GUI group objects.
void setupGroup (puGroup * group, SGPropertyNode * props,
int width, int height, bool makeFrame = false);
// Set object colors: the "which" argument defines which color qualities
// (PUCOL_LABEL, etc.) should pick up the <color> property.
void setColor(puObject * object, SGPropertyNode * props, int which = 0);
// return key code number for keystring
int getKeyCode(const char *keystring);
/**
* Apply layout sizes to a tree of puObjects
*/
void applySize(puObject *object);
// The top-level PUI object.
puObject * _object;
// The GUI subsystem.
NewGUI * _gui;
// The dialog font. Defaults to the global gui font, but can get
// overridden by a top level font definition.
puFont * _font;
// The source xml tree, so that we can pass data back, such as the
// last position.
SGPropertyNode_ptr _props;
bool _needsRelayout;
// Nasal module.
std::string _module;
SGPropertyNode_ptr _nasal_close;
// PUI provides no way for userdata to be deleted automatically
// with a GUI object, so we have to keep track of all the special
// data we allocated and then free it manually when the dialog
// closes.
std::vector<void *> _info;
struct PropertyObject {
PropertyObject (const char * name,
puObject * object,
SGPropertyNode_ptr node);
std::string name;
puObject * object;
SGPropertyNode_ptr node;
};
std::vector<PropertyObject *> _propertyObjects;
std::vector<PropertyObject *> _liveObjects;
class ConditionalObject : public SGConditional
{
public:
ConditionalObject(const std::string& aName, puObject* aPu) :
_name(aName),
_pu(aPu)
{ ; }
void update(FGPUIDialog* aDlg);
private:
const std::string _name;
puObject* _pu;
};
typedef SGSharedPtr<ConditionalObject> ConditionalObjectRef;
std::vector<ConditionalObjectRef> _conditionalObjects;
};
//
// Custom subclass of puPopup to implement "draggable" windows in the
// interface. Note that this is a subclass of puPopup, not
// puDialogBox. Sadly, PUI (mis)uses subclassing to implement a
// boolean property: modality. That means that we can't implement
// dragging of both puPopup windows and puDialogBoxes with the same
// code. Rather than duplicate code, I've chosen to implement only
// "non-modal dragability" here. Modal dialog boxes (like the exit
// confirmation) are not draggable.
//
class fgPopup : public puPopup {
public:
fgPopup(int x, int y, bool r = true, bool d = true) :
puPopup(x, y), _draggable(d), _resizable(r), _dragging(false)
{}
int checkHit(int b, int up, int x, int y);
int checkKey(int key, int updown);
int getHitObjects(puObject *, int x, int y);
puObject *getKeyObject(puObject *, int key);
puObject *getActiveInputField(puObject *);
void applySize(puObject *);
private:
enum { LEFT = 1, RIGHT = 2, TOP = 4, BOTTOM = 8 };
bool _draggable;
bool _resizable;
bool _dragging;
int _resizing;
int _start_cursor;
int _cursor;
int _dlgX, _dlgY, _dlgW, _dlgH;
int _startX, _startY;
};
class fgValueList {
public:
fgValueList(SGPropertyNode *p);
virtual ~fgValueList();
virtual void update();
protected:
char **_list;
private:
void make_list();
void destroy_list();
SGPropertyNode_ptr _props;
};
class fgList : public fgValueList, public puaList, public GUI_ID {
public:
fgList(int x1, int y1, int x2, int y2, SGPropertyNode *p, int sw) :
fgValueList(p), puaList(x1, y1, x2, y2, _list, sw), GUI_ID(FGCLASS_LIST) {}
void update();
};
class fgComboBox : public fgValueList, public puaComboBox {
public:
fgComboBox(int x1, int y1, int x2, int y2, SGPropertyNode *p, bool editable) :
fgValueList(p),
puaComboBox(x1, y1, x2, y2, _list, editable),
_inHit(false)
{}
void update();
virtual void setSize(int w, int h);
virtual int checkHit(int b, int up, int x, int y);
virtual void recalc_bbox();
private:
bool _inHit;
};
class fgSelectBox : public fgValueList, public puaSelectBox {
public:
fgSelectBox(int x1, int y1, int x2, int y2, SGPropertyNode *p) :
fgValueList(p), puaSelectBox(x1, y1, x2, y2, _list) {}
};
#endif // __DIALOG_HXX

376
src/GUI/FGPUIMenuBar.cxx Normal file
View file

@ -0,0 +1,376 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <string.h>
#include <iostream>
#include <plib/pu.h>
#include <simgear/debug/logstream.hxx>
#include <simgear/structure/SGBinding.hxx>
#include <simgear/props/props_io.hxx>
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
#include "new_gui.hxx"
#include "FGPUIMenuBar.hxx"
using std::vector;
using std::string;
using std::map;
////////////////////////////////////////////////////////////////////////
// FIXME!!
//
// Deprecated wrappers for old menu commands.
//
// DO NOT ADD TO THESE. THEY WILL BE DELETED SOON!
//
// These are defined in gui_funcs.cxx. They should be replaced with
// user-configured dialogs and new commands where necessary.
////////////////////////////////////////////////////////////////////////
#if defined(TR_HIRES_SNAP)
extern void dumpHiResSnapShot ();
static bool
do_hires_snapshot_dialog (const SGPropertyNode * arg)
{
dumpHiResSnapShot();
return true;
}
#endif // TR_HIRES_SNAP
static struct {
const char * name;
SGCommandMgr::command_t command;
} deprecated_dialogs [] = {
#if defined(TR_HIRES_SNAP)
{ "old-hires-snapshot-dialog", do_hires_snapshot_dialog },
#endif
{ 0, 0 }
};
static void
add_deprecated_dialogs ()
{
SG_LOG(SG_GENERAL, SG_INFO, "Initializing old dialog commands:");
for (int i = 0; deprecated_dialogs[i].name != 0; i++) {
SG_LOG(SG_GENERAL, SG_INFO, " " << deprecated_dialogs[i].name);
globals->get_commands()->addCommand(deprecated_dialogs[i].name,
deprecated_dialogs[i].command);
}
}
////////////////////////////////////////////////////////////////////////
// Static functions.
////////////////////////////////////////////////////////////////////////
static void
menu_callback (puObject * object)
{
NewGUI * gui = (NewGUI *)globals->get_subsystem("gui");
FGPUIMenuBar* mb = static_cast<FGPUIMenuBar*>(gui->getMenuBar());
mb->fireItem(object);
}
////////////////////////////////////////////////////////////////////////
// Implementation of FGPUIMenuBar.
////////////////////////////////////////////////////////////////////////
FGPUIMenuBar::FGPUIMenuBar ()
: _visible(false),
_menuBar(0)
{
}
FGPUIMenuBar::~FGPUIMenuBar ()
{
destroy_menubar();
}
void
FGPUIMenuBar::init ()
{
delete _menuBar; // FIXME: check if PUI owns the pointer
make_menubar();
// FIXME: temporary commands to get at
// old, hard-coded dialogs.
add_deprecated_dialogs();
}
void
FGPUIMenuBar::show ()
{
if (_menuBar != 0)
_menuBar->reveal();
_visible = true;
}
void
FGPUIMenuBar::hide ()
{
if (_menuBar != 0)
_menuBar->hide();
_visible = false;
}
bool
FGPUIMenuBar::isVisible () const
{
return _visible;
}
void
FGPUIMenuBar::fireItem (puObject * item)
{
const char * name = item->getLegend();
vector<SGBinding *> &bindings = _bindings[name];
int nBindings = bindings.size();
for (int i = 0; i < nBindings; i++)
bindings[i]->fire();
}
void
FGPUIMenuBar::make_menu (SGPropertyNode * node)
{
const char * name = strdup(node->getStringValue("label"));
vector<SGPropertyNode_ptr> item_nodes = node->getChildren("item");
int array_size = item_nodes.size();
char ** items = make_char_array(array_size);
puCallback * callbacks = make_callback_array(array_size);
for (unsigned int i = 0, j = item_nodes.size() - 1;
i < item_nodes.size();
i++, j--) {
// Set up the PUI entries for this item
items[j] = strdup((char *)item_nodes[i]->getStringValue("label"));
callbacks[j] = menu_callback;
// Load all the bindings for this item
vector<SGPropertyNode_ptr> bindings = item_nodes[i]->getChildren("binding");
SGPropertyNode * dest = fgGetNode("/sim/bindings/menu", true);
for (unsigned int k = 0; k < bindings.size(); k++) {
unsigned int m = 0;
SGPropertyNode_ptr binding;
while (dest->getChild("binding", m))
m++;
binding = dest->getChild("binding", m, true);
copyProperties(bindings[k], binding);
_bindings[items[j]].push_back(new SGBinding(binding, globals->get_props()));
}
}
_menuBar->add_submenu(name, items, callbacks);
}
void
FGPUIMenuBar::make_menubar ()
{
SGPropertyNode *targetpath;
targetpath = fgGetNode("/sim/menubar/default",true);
// fgLoadProps("gui/menubar.xml", targetpath);
/* NOTE: there is no check to see whether there's any usable data at all
*
* This would also have the advantage of being able to create some kind of
* 'fallback' menu - just in case that either menubar.xml is empty OR that
* its XML data is not valid, that way we would avoid displaying an
* unusable menubar without any functionality - if we decided to add another
* char * element to the commands structure in
* $FG_SRC/src/Main/fgcommands.cxx
* we could additionally save each function's (short) description and use
* this as label for the fallback PUI menubar item labels - as a workaround
* one might simply use the internal fgcommands and put them into the
* fallback menu, so that the user is at least able to re-init the menu
* loading - just in case there was some malformed XML in it
* (it happend to me ...)
*/
make_menubar(targetpath);
}
/* WARNING: We aren't yet doing any validation of what's found - but since
* this isn't done with menubar.xml either, it should not really matter
* right now. Although one should later on consider to validate the
* contents, whether they are representing a 'legal' menubar structure.
*/
void
FGPUIMenuBar::make_menubar(SGPropertyNode * props)
{
// Just in case.
destroy_menubar();
_menuBar = new puMenuBar;
vector<SGPropertyNode_ptr> menu_nodes = props->getChildren("menu");
for (unsigned int i = 0; i < menu_nodes.size(); i++)
make_menu(menu_nodes[i]);
_menuBar->close();
make_object_map(props);
if (_visible)
_menuBar->reveal();
else
_menuBar->hide();
}
void
FGPUIMenuBar::destroy_menubar ()
{
if ( _menuBar == 0 )
return;
hide();
puDeleteObject(_menuBar);
unsigned int i;
// Delete all the character arrays
// we were forced to keep around for
// plib.
SG_LOG(SG_GENERAL, SG_BULK, "Deleting char arrays");
for (i = 0; i < _char_arrays.size(); i++) {
for (int j = 0; _char_arrays[i][j] != 0; j++)
free(_char_arrays[i][j]); // added with strdup
delete[] _char_arrays[i];
}
// Delete all the callback arrays
// we were forced to keep around for
// plib.
SG_LOG(SG_GENERAL, SG_BULK, "Deleting callback arrays");
for (i = 0; i < _callback_arrays.size(); i++)
delete[] _callback_arrays[i];
// Delete all those bindings
SG_LOG(SG_GENERAL, SG_BULK, "Deleting bindings");
map<string,vector<SGBinding *> >::iterator it;
for (it = _bindings.begin(); it != _bindings.end(); it++) {
SG_LOG(SG_GENERAL, SG_BULK, "Deleting bindings for " << it->first);
for ( i = 0; i < it->second.size(); i++ )
delete it->second[i];
}
SG_LOG(SG_GENERAL, SG_BULK, "Done.");
}
void
FGPUIMenuBar::make_object_map(SGPropertyNode * node)
{
unsigned int menu_index = 0;
vector<SGPropertyNode_ptr> menus = node->getChildren("menu");
for (puObject *obj = ((puGroup *)_menuBar)->getFirstChild();
obj; obj = obj->getNextObject()) {
// skip puPopupMenus. They are also children of _menuBar,
// but we access them via getUserData() (see below)
if (!(obj->getType() & PUCLASS_ONESHOT))
continue;
if (menu_index >= menus.size()) {
SG_LOG(SG_GENERAL, SG_WARN, "'menu' object without node: "
<< node->getPath() << "/menu[" << menu_index << ']');
return;
}
SGPropertyNode *menu = menus.at(menu_index);
_objects[menu->getPath()] = obj;
add_enabled_listener(menu);
puGroup *popup = (puGroup *)obj->getUserData();
if (!popup)
continue;
// the entries are for some reason reversed (last first), and we
// don't know yet how many there will be; so we collect first
vector<puObject *> e;
for (puObject *me = popup->getFirstChild(); me; me = me->getNextObject())
e.push_back(me);
vector<SGPropertyNode_ptr> items = menu->getChildren("item");
for (unsigned int i = 0; i < e.size(); i++) {
if (i >= items.size()) {
SG_LOG(SG_GENERAL, SG_WARN, "'item' object without node: "
<< menu->getPath() << "/item[" << i << ']');
break;
}
SGPropertyNode *item = items.at(e.size() - i - 1);
_objects[item->getPath()] = e[i];
add_enabled_listener(item);
}
menu_index++;
}
}
struct EnabledListener : SGPropertyChangeListener {
void valueChanged(SGPropertyNode *node) {
NewGUI * gui = (NewGUI *)globals->get_subsystem("gui");
if (!gui)
return;
FGPUIMenuBar* menubar = static_cast<FGPUIMenuBar*>(gui->getMenuBar());
if (menubar)
menubar->enable_item(node->getParent(), node->getBoolValue());
}
};
void
FGPUIMenuBar::add_enabled_listener(SGPropertyNode * node)
{
if (!node->hasValue("enabled"))
node->setBoolValue("enabled", true);
enable_item(node, node->getBoolValue("enabled"));
node->getNode("enabled")->addChangeListener(new EnabledListener());
}
bool
FGPUIMenuBar::enable_item(const SGPropertyNode * node, bool state)
{
string path = node->getPath();
if (_objects.find(path) == _objects.end()) {
SG_LOG(SG_GENERAL, SG_ALERT, "Trying to enable/disable "
"non-existent menu item for node `" << path << '\'');
return false;
}
puObject *object = _objects[path];
if (state)
object->activate();
else
object->greyOut();
return true;
}
char **
FGPUIMenuBar::make_char_array (int size)
{
char ** list = new char*[size+1];
for (int i = 0; i <= size; i++)
list[i] = 0;
_char_arrays.push_back(list);
return list;
}
puCallback *
FGPUIMenuBar::make_callback_array (int size)
{
puCallback * list = new puCallback[size+1];
for (int i = 0; i <= size; i++)
list[i] = 0;
_callback_arrays.push_back(list);
return list;
}
// end of menubar.cxx

138
src/GUI/FGPUIMenuBar.hxx Normal file
View file

@ -0,0 +1,138 @@
// menubar.hxx - XML-configured menu bar.
#ifndef FG_PUI_MENUBAR_HXX
#define FG_PUI_MENUBAR_HXX 1
#ifndef __cplusplus
# error This library requires C++
#endif
#include <GUI/menubar.hxx>
#include <map>
#include <vector>
// forward decls, avoid pulling in PLIB headers here
class puMenuBar;
class puObject;
class SGPropertyNode;
class SGBinding;
typedef void (*puCallback)(class puObject *) ;
/**
* XML-configured PUI menu bar.
*
* This class creates a menu bar from a tree of XML properties. These
* properties are not part of the main FlightGear property tree, but
* are read from a separate file ($FG_ROOT/gui/menubar.xml).
*
* WARNING: because PUI provides no easy way to attach user data to a
* menu item, all menu item strings must be unique; otherwise, this
* class will always use the first binding with any given name.
*/
class FGPUIMenuBar : public FGMenuBar
{
public:
/**
* Constructor.
*/
FGPUIMenuBar ();
/**
* Destructor.
*/
virtual ~FGPUIMenuBar ();
/**
* Initialize the menu bar from $FG_ROOT/gui/menubar.xml
*/
virtual void init ();
/**
* Make the menu bar visible.
*/
virtual void show ();
/**
* Make the menu bar invisible.
*/
virtual void hide ();
/**
* Test whether the menu bar is visible.
*/
virtual bool isVisible () const;
/**
* IGNORE THIS METHOD!!!
*
* This is necessary only because plib does not provide any easy
* way to attach user data to a menu item. FlightGear should not
* have to know about PUI internals, but this method allows the
* callback to pass the menu item one-shot on to the current menu.
*/
virtual void fireItem (puObject * item);
/**
* create a menubar based on a PropertyList within the PropertyTree
*/
void make_menubar (SGPropertyNode * props);
/**
* destroy a menubar based on a PropertyList within the PropertyTree
*/
void destroy_menubar ();
/**
* Disable/enable menu titles and entries
*/
bool enable_item (const SGPropertyNode * item, bool state);
private:
// Make a single menu.
void make_menu (SGPropertyNode * node);
// Make the top-level menubar.
void make_menubar ();
// Create a property-path -> puObject map for menu node
void make_object_map(SGPropertyNode * node);
// Add <enabled> listener that enables/disables menu entries.
void add_enabled_listener(SGPropertyNode * node);
// Is the menu visible?
bool _visible;
// The top-level menubar itself.
puMenuBar * _menuBar;
// A map of bindings for the menubar.
std::map<std::string,std::vector<SGBinding *> > _bindings;
// These are hoops that we have to jump through because PUI doesn't
// do memory management for lists. We have to allocate the arrays,
// hang onto pointers, and then delete them when the menubar is
// freed.
char ** make_char_array (int size);
puCallback * make_callback_array (int size);
std::vector<char **> _char_arrays;
std::vector<puCallback *> _callback_arrays;
// A map for {menu node path}->puObject translation.
std::map<std::string, puObject *> _objects;
};
#endif // __MENUBAR_HXX

View file

@ -10,7 +10,7 @@
#include <plib/pu.h>
#include "dialog.hxx" // for GUI_ID
#include "FGPUIDialog.hxx" // for GUI_ID
// forward decls
class puaScrollBar;

File diff suppressed because it is too large Load diff

View file

@ -7,31 +7,8 @@
# error This library requires C++
#endif
#include <plib/puAux.h>
#include <simgear/compiler.h> // for SG_USING_STD
#include <simgear/props/props.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/condition.hxx>
#include <vector>
using std::vector;
// ugly temporary workaround for plib's lack of user defined class ids FIXME
#define FGCLASS_LIST 0x00000001
#define FGCLASS_AIRPORTLIST 0x00000002
#define FGCLASS_PROPERTYLIST 0x00000004
#define FGCLASS_WAYPOINTLIST 0x00000008
class GUI_ID { public: GUI_ID(int id) : id(id) {} virtual ~GUI_ID() {} int id; };
class FGDialog;
class NewGUI;
class FGColor;
// forward decls
class SGPropertyNode;
/**
* An XML-configured dialog box.
@ -45,16 +22,6 @@ class FGDialog
{
public:
/**
* Construct a new GUI widget configured by a property tree.
*
* The configuration properties are not part of the main
* FlightGear property tree; the GUI manager reads them
* from individual configuration files.
*
* @param props A property tree describing the dialog.
*/
FGDialog (SGPropertyNode * props);
/**
@ -73,7 +40,7 @@ public:
* @param objectName The name of the GUI object(s) to update.
* Use the empty name for all unnamed objects.
*/
virtual void updateValues (const char * objectName = 0);
virtual void updateValues (const char * objectName = 0) = 0;
/**
@ -86,199 +53,28 @@ public:
* @param objectName The name of the GUI object(s) to update.
* Use the empty name for all unnamed objects.
*/
virtual void applyValues (const char * objectName = 0);
virtual void applyValues (const char * objectName = 0) = 0;
/**
* Update state. Called on active dialogs before rendering.
*/
virtual void update ();
/**
* Recompute the dialog's layout
*/
void relayout();
void setNeedsLayout() {
_needsRelayout = true;
}
private:
enum {
BACKGROUND = 0x01,
FOREGROUND = 0x02,
HIGHLIGHT = 0x04,
LABEL = 0x08,
LEGEND = 0x10,
MISC = 0x20,
EDITFIELD = 0x40
};
// Private copy constructor to avoid unpleasant surprises.
FGDialog (const FGDialog &);
// Show the dialog.
void display (SGPropertyNode * props);
// Build the dialog or a subobject of it.
puObject * makeObject (SGPropertyNode * props,
int parentWidth, int parentHeight);
// Common configuration for all GUI objects.
void setupObject (puObject * object, SGPropertyNode * props);
// Common configuration for all GUI group objects.
void setupGroup (puGroup * group, SGPropertyNode * props,
int width, int height, bool makeFrame = false);
// Set object colors: the "which" argument defines which color qualities
// (PUCOL_LABEL, etc.) should pick up the <color> property.
void setColor(puObject * object, SGPropertyNode * props, int which = 0);
// return key code number for keystring
int getKeyCode(const char *keystring);
/**
* Apply layout sizes to a tree of puObjects
*/
void applySize(puObject *object);
// The top-level PUI object.
puObject * _object;
// The GUI subsystem.
NewGUI * _gui;
// The dialog font. Defaults to the global gui font, but can get
// overridden by a top level font definition.
puFont * _font;
// The source xml tree, so that we can pass data back, such as the
// last position.
SGPropertyNode_ptr _props;
bool _needsRelayout;
// Nasal module.
std::string _module;
SGPropertyNode_ptr _nasal_close;
// PUI provides no way for userdata to be deleted automatically
// with a GUI object, so we have to keep track of all the special
// data we allocated and then free it manually when the dialog
// closes.
vector<void *> _info;
struct PropertyObject {
PropertyObject (const char * name,
puObject * object,
SGPropertyNode_ptr node);
std::string name;
puObject * object;
SGPropertyNode_ptr node;
};
vector<PropertyObject *> _propertyObjects;
vector<PropertyObject *> _liveObjects;
class ConditionalObject : public SGConditional
{
public:
ConditionalObject(const std::string& aName, puObject* aPu) :
_name(aName),
_pu(aPu)
{ ; }
void update(FGDialog* aDlg);
private:
const std::string _name;
puObject* _pu;
};
typedef SGSharedPtr<ConditionalObject> ConditionalObjectRef;
vector<ConditionalObjectRef> _conditionalObjects;
};
//
// Custom subclass of puPopup to implement "draggable" windows in the
// interface. Note that this is a subclass of puPopup, not
// puDialogBox. Sadly, PUI (mis)uses subclassing to implement a
// boolean property: modality. That means that we can't implement
// dragging of both puPopup windows and puDialogBoxes with the same
// code. Rather than duplicate code, I've chosen to implement only
// "non-modal dragability" here. Modal dialog boxes (like the exit
// confirmation) are not draggable.
//
class fgPopup : public puPopup {
public:
fgPopup(int x, int y, bool r = true, bool d = true) :
puPopup(x, y), _draggable(d), _resizable(r), _dragging(false)
{}
int checkHit(int b, int up, int x, int y);
int checkKey(int key, int updown);
int getHitObjects(puObject *, int x, int y);
puObject *getKeyObject(puObject *, int key);
puObject *getActiveInputField(puObject *);
void applySize(puObject *);
private:
enum { LEFT = 1, RIGHT = 2, TOP = 4, BOTTOM = 8 };
bool _draggable;
bool _resizable;
bool _dragging;
int _resizing;
int _start_cursor;
int _cursor;
int _dlgX, _dlgY, _dlgW, _dlgH;
int _startX, _startY;
};
class fgValueList {
public:
fgValueList(SGPropertyNode *p);
virtual ~fgValueList();
virtual void update();
virtual void update () = 0;
protected:
char **_list;
/**
* Construct a new GUI widget configured by a property tree.
*
* The configuration properties are not part of the main
* FlightGear property tree; the GUI manager reads them
* from individual configuration files.
*
* @param props A property tree describing the dialog.
*/
FGDialog (SGPropertyNode * props);
private:
void make_list();
void destroy_list();
SGPropertyNode_ptr _props;
};
class fgList : public fgValueList, public puaList, public GUI_ID {
public:
fgList(int x1, int y1, int x2, int y2, SGPropertyNode *p, int sw) :
fgValueList(p), puaList(x1, y1, x2, y2, _list, sw), GUI_ID(FGCLASS_LIST) {}
void update();
};
class fgComboBox : public fgValueList, public puaComboBox {
public:
fgComboBox(int x1, int y1, int x2, int y2, SGPropertyNode *p, bool editable) :
fgValueList(p),
puaComboBox(x1, y1, x2, y2, _list, editable),
_inHit(false)
{}
void update();
virtual void setSize(int w, int h);
virtual int checkHit(int b, int up, int x, int y);
virtual void recalc_bbox();
private:
bool _inHit;
};
class fgSelectBox : public fgValueList, public puaSelectBox {
public:
fgSelectBox(int x1, int y1, int x2, int y2, SGPropertyNode *p) :
fgValueList(p), puaSelectBox(x1, y1, x2, y2, _list) {}
};
#endif // __DIALOG_HXX

View file

@ -44,6 +44,7 @@
#include <Main/fg_props.hxx>
#include <Main/WindowSystemAdapter.hxx>
#include <GUI/new_gui.hxx>
#include <GUI/FGFontCache.hxx>
#include "gui.h"
#include "layout.hxx"

View file

@ -2,373 +2,11 @@
# include <config.h>
#endif
#include <string.h>
#include <iostream>
#include <plib/pu.h>
#include <simgear/debug/logstream.hxx>
#include <simgear/structure/SGBinding.hxx>
#include <simgear/props/props_io.hxx>
#include <Main/globals.hxx>
#include "new_gui.hxx"
#include "menubar.hxx"
using std::vector;
using std::string;
using std::map;
////////////////////////////////////////////////////////////////////////
// FIXME!!
//
// Deprecated wrappers for old menu commands.
//
// DO NOT ADD TO THESE. THEY WILL BE DELETED SOON!
//
// These are defined in gui_funcs.cxx. They should be replaced with
// user-configured dialogs and new commands where necessary.
////////////////////////////////////////////////////////////////////////
#if defined(TR_HIRES_SNAP)
extern void dumpHiResSnapShot ();
static bool
do_hires_snapshot_dialog (const SGPropertyNode * arg)
{
dumpHiResSnapShot();
return true;
}
#endif // TR_HIRES_SNAP
static struct {
const char * name;
SGCommandMgr::command_t command;
} deprecated_dialogs [] = {
#if defined(TR_HIRES_SNAP)
{ "old-hires-snapshot-dialog", do_hires_snapshot_dialog },
#endif
{ 0, 0 }
};
static void
add_deprecated_dialogs ()
{
SG_LOG(SG_GENERAL, SG_INFO, "Initializing old dialog commands:");
for (int i = 0; deprecated_dialogs[i].name != 0; i++) {
SG_LOG(SG_GENERAL, SG_INFO, " " << deprecated_dialogs[i].name);
globals->get_commands()->addCommand(deprecated_dialogs[i].name,
deprecated_dialogs[i].command);
}
}
////////////////////////////////////////////////////////////////////////
// Static functions.
////////////////////////////////////////////////////////////////////////
static void
menu_callback (puObject * object)
{
NewGUI * gui = (NewGUI *)globals->get_subsystem("gui");
gui->getMenuBar()->fireItem(object);
}
////////////////////////////////////////////////////////////////////////
// Implementation of FGMenuBar.
////////////////////////////////////////////////////////////////////////
FGMenuBar::FGMenuBar ()
: _visible(false),
_menuBar(0)
{
}
FGMenuBar::~FGMenuBar ()
{
destroy_menubar();
}
void
FGMenuBar::init ()
{
delete _menuBar; // FIXME: check if PUI owns the pointer
make_menubar();
// FIXME: temporary commands to get at
// old, hard-coded dialogs.
add_deprecated_dialogs();
}
void
FGMenuBar::show ()
{
if (_menuBar != 0)
_menuBar->reveal();
_visible = true;
}
void
FGMenuBar::hide ()
{
if (_menuBar != 0)
_menuBar->hide();
_visible = false;
}
bool
FGMenuBar::isVisible () const
{
return _visible;
}
void
FGMenuBar::fireItem (puObject * item)
{
const char * name = item->getLegend();
vector<SGBinding *> &bindings = _bindings[name];
int nBindings = bindings.size();
for (int i = 0; i < nBindings; i++)
bindings[i]->fire();
}
void
FGMenuBar::make_menu (SGPropertyNode * node)
{
const char * name = strdup(node->getStringValue("label"));
vector<SGPropertyNode_ptr> item_nodes = node->getChildren("item");
int array_size = item_nodes.size();
char ** items = make_char_array(array_size);
puCallback * callbacks = make_callback_array(array_size);
for (unsigned int i = 0, j = item_nodes.size() - 1;
i < item_nodes.size();
i++, j--) {
// Set up the PUI entries for this item
items[j] = strdup((char *)item_nodes[i]->getStringValue("label"));
callbacks[j] = menu_callback;
// Load all the bindings for this item
vector<SGPropertyNode_ptr> bindings = item_nodes[i]->getChildren("binding");
SGPropertyNode * dest = fgGetNode("/sim/bindings/menu", true);
for (unsigned int k = 0; k < bindings.size(); k++) {
unsigned int m = 0;
SGPropertyNode_ptr binding;
while (dest->getChild("binding", m))
m++;
binding = dest->getChild("binding", m, true);
copyProperties(bindings[k], binding);
_bindings[items[j]].push_back(new SGBinding(binding, globals->get_props()));
}
}
_menuBar->add_submenu(name, items, callbacks);
}
void
FGMenuBar::make_menubar ()
{
SGPropertyNode *targetpath;
targetpath = fgGetNode("/sim/menubar/default",true);
// fgLoadProps("gui/menubar.xml", targetpath);
/* NOTE: there is no check to see whether there's any usable data at all
*
* This would also have the advantage of being able to create some kind of
* 'fallback' menu - just in case that either menubar.xml is empty OR that
* its XML data is not valid, that way we would avoid displaying an
* unusable menubar without any functionality - if we decided to add another
* char * element to the commands structure in
* $FG_SRC/src/Main/fgcommands.cxx
* we could additionally save each function's (short) description and use
* this as label for the fallback PUI menubar item labels - as a workaround
* one might simply use the internal fgcommands and put them into the
* fallback menu, so that the user is at least able to re-init the menu
* loading - just in case there was some malformed XML in it
* (it happend to me ...)
*/
make_menubar(targetpath);
}
/* WARNING: We aren't yet doing any validation of what's found - but since
* this isn't done with menubar.xml either, it should not really matter
* right now. Although one should later on consider to validate the
* contents, whether they are representing a 'legal' menubar structure.
*/
void
FGMenuBar::make_menubar(SGPropertyNode * props)
{
// Just in case.
destroy_menubar();
_menuBar = new puMenuBar;
vector<SGPropertyNode_ptr> menu_nodes = props->getChildren("menu");
for (unsigned int i = 0; i < menu_nodes.size(); i++)
make_menu(menu_nodes[i]);
_menuBar->close();
make_object_map(props);
if (_visible)
_menuBar->reveal();
else
_menuBar->hide();
}
void
FGMenuBar::destroy_menubar ()
{
if ( _menuBar == 0 )
return;
hide();
puDeleteObject(_menuBar);
unsigned int i;
// Delete all the character arrays
// we were forced to keep around for
// plib.
SG_LOG(SG_GENERAL, SG_BULK, "Deleting char arrays");
for (i = 0; i < _char_arrays.size(); i++) {
for (int j = 0; _char_arrays[i][j] != 0; j++)
free(_char_arrays[i][j]); // added with strdup
delete[] _char_arrays[i];
}
// Delete all the callback arrays
// we were forced to keep around for
// plib.
SG_LOG(SG_GENERAL, SG_BULK, "Deleting callback arrays");
for (i = 0; i < _callback_arrays.size(); i++)
delete[] _callback_arrays[i];
// Delete all those bindings
SG_LOG(SG_GENERAL, SG_BULK, "Deleting bindings");
map<string,vector<SGBinding *> >::iterator it;
for (it = _bindings.begin(); it != _bindings.end(); it++) {
SG_LOG(SG_GENERAL, SG_BULK, "Deleting bindings for " << it->first);
for ( i = 0; i < it->second.size(); i++ )
delete it->second[i];
}
SG_LOG(SG_GENERAL, SG_BULK, "Done.");
}
void
FGMenuBar::make_object_map(SGPropertyNode * node)
{
unsigned int menu_index = 0;
vector<SGPropertyNode_ptr> menus = node->getChildren("menu");
for (puObject *obj = ((puGroup *)_menuBar)->getFirstChild();
obj; obj = obj->getNextObject()) {
// skip puPopupMenus. They are also children of _menuBar,
// but we access them via getUserData() (see below)
if (!(obj->getType() & PUCLASS_ONESHOT))
continue;
if (menu_index >= menus.size()) {
SG_LOG(SG_GENERAL, SG_WARN, "'menu' object without node: "
<< node->getPath() << "/menu[" << menu_index << ']');
return;
}
SGPropertyNode *menu = menus.at(menu_index);
_objects[menu->getPath()] = obj;
add_enabled_listener(menu);
puGroup *popup = (puGroup *)obj->getUserData();
if (!popup)
continue;
// the entries are for some reason reversed (last first), and we
// don't know yet how many there will be; so we collect first
vector<puObject *> e;
for (puObject *me = popup->getFirstChild(); me; me = me->getNextObject())
e.push_back(me);
vector<SGPropertyNode_ptr> items = menu->getChildren("item");
for (unsigned int i = 0; i < e.size(); i++) {
if (i >= items.size()) {
SG_LOG(SG_GENERAL, SG_WARN, "'item' object without node: "
<< menu->getPath() << "/item[" << i << ']');
break;
}
SGPropertyNode *item = items.at(e.size() - i - 1);
_objects[item->getPath()] = e[i];
add_enabled_listener(item);
}
menu_index++;
}
}
struct EnabledListener : SGPropertyChangeListener {
void valueChanged(SGPropertyNode *node) {
NewGUI * gui = (NewGUI *)globals->get_subsystem("gui");
if (!gui)
return;
FGMenuBar *menubar = gui->getMenuBar();
if (menubar)
menubar->enable_item(node->getParent(), node->getBoolValue());
}
};
void
FGMenuBar::add_enabled_listener(SGPropertyNode * node)
{
if (!node->hasValue("enabled"))
node->setBoolValue("enabled", true);
enable_item(node, node->getBoolValue("enabled"));
node->getNode("enabled")->addChangeListener(new EnabledListener());
}
bool
FGMenuBar::enable_item(const SGPropertyNode * node, bool state)
{
string path = node->getPath();
if (_objects.find(path) == _objects.end()) {
SG_LOG(SG_GENERAL, SG_ALERT, "Trying to enable/disable "
"non-existent menu item for node `" << path << '\'');
return false;
}
puObject *object = _objects[path];
if (state)
object->activate();
else
object->greyOut();
return true;
}
char **
FGMenuBar::make_char_array (int size)
{
char ** list = new char*[size+1];
for (int i = 0; i <= size; i++)
list[i] = 0;
_char_arrays.push_back(list);
return list;
}
puCallback *
FGMenuBar::make_callback_array (int size)
{
puCallback * list = new puCallback[size+1];
for (int i = 0; i <= size; i++)
list[i] = 0;
_callback_arrays.push_back(list);
return list;
}
// end of menubar.cxx

View file

@ -3,42 +3,19 @@
#ifndef __MENUBAR_HXX
#define __MENUBAR_HXX 1
#ifndef __cplusplus
# error This library requires C++
#endif
#include <Main/fg_props.hxx>
#include <plib/pu.h>
#include <map>
#include <vector>
class puMenuBar;
class puObject;
class SGBinding;
/**
* XML-configured PUI menu bar.
* XML-configured menu bar interface
*
* This class creates a menu bar from a tree of XML properties. These
* properties are not part of the main FlightGear property tree, but
* are read from a separate file ($FG_ROOT/gui/menubar.xml).
*
* WARNING: because PUI provides no easy way to attach user data to a
* menu item, all menu item strings must be unique; otherwise, this
* class will always use the first binding with any given name.
*/
class FGMenuBar
{
public:
/**
* Constructor.
*/
FGMenuBar ();
/**
* Destructor.
@ -49,89 +26,25 @@ public:
/**
* Initialize the menu bar from $FG_ROOT/gui/menubar.xml
*/
virtual void init ();
virtual void init () = 0;
/**
* Make the menu bar visible.
*/
virtual void show ();
virtual void show () = 0;
/**
* Make the menu bar invisible.
*/
virtual void hide ();
virtual void hide () = 0;
/**
* Test whether the menu bar is visible.
*/
virtual bool isVisible () const;
virtual bool isVisible () const = 0;
/**
* IGNORE THIS METHOD!!!
*
* This is necessary only because plib does not provide any easy
* way to attach user data to a menu item. FlightGear should not
* have to know about PUI internals, but this method allows the
* callback to pass the menu item one-shot on to the current menu.
*/
virtual void fireItem (puObject * item);
/**
* create a menubar based on a PropertyList within the PropertyTree
*/
void make_menubar (SGPropertyNode * props);
/**
* destroy a menubar based on a PropertyList within the PropertyTree
*/
void destroy_menubar ();
/**
* Disable/enable menu titles and entries
*/
bool enable_item (const SGPropertyNode * item, bool state);
private:
// Make a single menu.
void make_menu (SGPropertyNode * node);
// Make the top-level menubar.
void make_menubar ();
// Create a property-path -> puObject map for menu node
void make_object_map(SGPropertyNode * node);
// Add <enabled> listener that enables/disables menu entries.
void add_enabled_listener(SGPropertyNode * node);
// Is the menu visible?
bool _visible;
// The top-level menubar itself.
puMenuBar * _menuBar;
// A map of bindings for the menubar.
std::map<std::string,std::vector<SGBinding *> > _bindings;
// These are hoops that we have to jump through because PUI doesn't
// do memory management for lists. We have to allocate the arrays,
// hang onto pointers, and then delete them when the menubar is
// freed.
char ** make_char_array (int size);
puCallback * make_callback_array (int size);
std::vector<char **> _char_arrays;
std::vector<puCallback *> _callback_arrays;
// A map for {menu node path}->puObject translation.
std::map<std::string, puObject *> _objects;
};
#endif // __MENUBAR_HXX

View file

@ -26,11 +26,15 @@
#include "GL/glx.h"
#endif
#include "menubar.hxx"
#include "dialog.hxx"
#include "FGPUIMenuBar.hxx"
extern puFont FONT_HELVETICA_14;
extern puFont FONT_SANS_12B;
#if defined(SG_MAC)
#include "FGCocoaMenuBar.hxx"
#endif
#include "FGPUIDialog.hxx"
#include "FGFontCache.hxx"
#include "FGColor.hxx"
using std::map;
using std::string;
@ -41,15 +45,18 @@ using std::string;
NewGUI::NewGUI ()
: _menubar(new FGMenuBar),
_active_dialog(0)
NewGUI::NewGUI () :
_active_dialog(0)
{
#if defined(SG_MAC)
_menubar.reset(new FGCocoaMenuBar);
#else
_menubar.reset(new FGPUIMenuBar);
#endif
}
NewGUI::~NewGUI ()
{
delete _menubar;
_dialog_props.clear();
for (_itt_t it = _colors.begin(); it != _colors.end(); ++it)
delete it->second;
@ -81,7 +88,7 @@ void
NewGUI::reset (bool reload)
{
map<string,FGDialog *>::iterator iter;
vector<string> dlg;
std::vector<string> dlg;
// close all open dialogs and remember them ...
for (iter = _active_dialogs.begin(); iter != _active_dialogs.end(); ++iter)
dlg.push_back(iter->first);
@ -93,8 +100,9 @@ NewGUI::reset (bool reload)
setStyle();
unbind();
delete _menubar;
_menubar = new FGMenuBar;
#if !defined(SG_MAC)
_menubar.reset(new FGPUIMenuBar);
#endif
if (reload) {
_dialog_props.clear();
@ -139,7 +147,7 @@ NewGUI::showDialog (const string &name)
return false;
} else {
if(!_active_dialogs[name])
_active_dialogs[name] = new FGDialog(_dialog_props[name]);
_active_dialogs[name] = new FGPUIDialog(_dialog_props[name]);
return true;
}
}
@ -215,7 +223,7 @@ NewGUI::getActiveDialog ()
FGMenuBar *
NewGUI::getMenuBar ()
{
return _menubar;
return _menubar.get();
}
bool
@ -326,247 +334,4 @@ NewGUI::setupFont (SGPropertyNode *node)
return;
}
////////////////////////////////////////////////////////////////////////
// FGColor class.
////////////////////////////////////////////////////////////////////////
void
FGColor::print() const {
std::cerr << "red=" << _red << ", green=" << _green
<< ", blue=" << _blue << ", alpha=" << _alpha << std::endl;
}
bool
FGColor::merge(const SGPropertyNode *node)
{
if (!node)
return false;
bool dirty = false;
const SGPropertyNode * n;
if ((n = node->getNode("red")))
_red = n->getFloatValue(), dirty = true;
if ((n = node->getNode("green")))
_green = n->getFloatValue(), dirty = true;
if ((n = node->getNode("blue")))
_blue = n->getFloatValue(), dirty = true;
if ((n = node->getNode("alpha")))
_alpha = n->getFloatValue(), dirty = true;
return dirty;
}
bool
FGColor::merge(const FGColor *color)
{
bool dirty = false;
if (color && color->_red >= 0.0)
_red = color->_red, dirty = true;
if (color && color->_green >= 0.0)
_green = color->_green, dirty = true;
if (color && color->_blue >= 0.0)
_blue = color->_blue, dirty = true;
if (color && color->_alpha >= 0.0)
_alpha = color->_alpha, dirty = true;
return dirty;
}
////////////////////////////////////////////////////////////////////////
// FGFontCache class.
////////////////////////////////////////////////////////////////////////
namespace
{
struct GuiFont
{
const char *name;
puFont *font;
struct Predicate
: public std::unary_function<const GuiFont, bool>
{
Predicate(const char* name_) : name(name_) {}
bool operator() (const GuiFont& f1) const
{
return std::strcmp(f1.name, name) == 0;
}
const char* name;
};
};
const GuiFont guifonts[] = {
{ "default", &FONT_HELVETICA_14 },
{ "FIXED_8x13", &PUFONT_8_BY_13 },
{ "FIXED_9x15", &PUFONT_9_BY_15 },
{ "TIMES_10", &PUFONT_TIMES_ROMAN_10 },
{ "TIMES_24", &PUFONT_TIMES_ROMAN_24 },
{ "HELVETICA_10", &PUFONT_HELVETICA_10 },
{ "HELVETICA_12", &PUFONT_HELVETICA_12 },
{ "HELVETICA_14", &FONT_HELVETICA_14 },
{ "HELVETICA_18", &PUFONT_HELVETICA_18 },
{ "SANS_12B", &FONT_SANS_12B }
};
const GuiFont* guifontsEnd = &guifonts[sizeof(guifonts)/ sizeof(guifonts[0])];
}
FGFontCache::FGFontCache() :
_initialized(false)
{
}
FGFontCache::~FGFontCache()
{
#if defined(SG_UNIX) && !defined(SG_MAC)
// Ugly workaround for a crash on exit with multiple screens configured
if (!glXGetCurrentContext())
return;
#endif
PuFontMap::iterator it, end = _puFonts.end();
for (it = _puFonts.begin(); it != end; ++it)
delete it->second;
}
inline bool FGFontCache::FntParamsLess::operator()(const FntParams& f1,
const FntParams& f2) const
{
int comp = f1.name.compare(f2.name);
if (comp < 0)
return true;
else if (comp > 0)
return false;
if (f1.size < f2.size)
return true;
else if (f1.size > f2.size)
return false;
return f1.slant < f2.slant;
}
struct FGFontCache::fnt *
FGFontCache::getfnt(const char *name, float size, float slant)
{
string fontName = boost::to_lower_copy(string(name));
FntParams fntParams(fontName, size, slant);
PuFontMap::iterator i = _puFonts.find(fntParams);
if (i != _puFonts.end()) {
// found in the puFonts map, all done
return i->second;
}
// fntTexFont s are all preloaded into the _texFonts map
TexFontMap::iterator texi = _texFonts.find(fontName);
fntTexFont* texfont = NULL;
puFont* pufont = NULL;
if (texi != _texFonts.end()) {
texfont = texi->second;
} else {
// check the built-in PUI fonts (in guifonts array)
const GuiFont* guifont = std::find_if(&guifonts[0], guifontsEnd,
GuiFont::Predicate(name));
if (guifont != guifontsEnd) {
pufont = guifont->font;
}
}
fnt* f = new fnt;
if (pufont) {
f->pufont = pufont;
} else if (texfont) {
f->texfont = texfont;
f->pufont = new puFont;
f->pufont->initialize(static_cast<fntFont *>(f->texfont), size, slant);
} else {
f->pufont = guifonts[0].font;
}
_puFonts[fntParams] = f;
return f;
}
puFont *
FGFontCache::get(const char *name, float size, float slant)
{
return getfnt(name, size, slant)->pufont;
}
fntTexFont *
FGFontCache::getTexFont(const char *name, float size, float slant)
{
return getfnt(name, size, slant)->texfont;
}
puFont *
FGFontCache::get(SGPropertyNode *node)
{
if (!node)
return get("Helvetica.txf", 15.0, 0.0);
const char *name = node->getStringValue("name", "Helvetica.txf");
float size = node->getFloatValue("size", 15.0);
float slant = node->getFloatValue("slant", 0.0);
return get(name, size, slant);
}
void FGFontCache::init()
{
if (_initialized) {
return;
}
char *envp = ::getenv("FG_FONTS");
if (envp != NULL) {
_path.set(envp);
} else {
_path.set(globals->get_fg_root());
_path.append("Fonts");
}
_initialized = true;
}
SGPath
FGFontCache::getfntpath(const char *name)
{
init();
SGPath path(_path);
if (name && std::string(name) != "") {
path.append(name);
if (path.exists())
return path;
}
path = SGPath(_path);
path.append("Helvetica.txf");
SG_LOG(SG_GENERAL, SG_WARN, "Unknown font name '" << name << "', defaulting to Helvetica");
return path;
}
bool FGFontCache::initializeFonts()
{
static string fontext("txf");
init();
ulDir* fontdir = ulOpenDir(_path.c_str());
if (!fontdir)
return false;
const ulDirEnt *dirEntry;
while ((dirEntry = ulReadDir(fontdir)) != 0) {
SGPath path(_path);
path.append(dirEntry->d_name);
if (path.extension() == fontext) {
fntTexFont* f = new fntTexFont;
if (f->load((char *)path.c_str())) {
// convert font names in the map to lowercase for matching
string fontName = boost::to_lower_copy(string(dirEntry->d_name));
_texFonts[fontName] = f;
} else
delete f;
}
}
ulCloseDir(fontdir);
return true;
}
// end of new_gui.cxx

View file

@ -3,17 +3,15 @@
#ifndef __NEW_GUI_HXX
#define __NEW_GUI_HXX 1
#include <plib/pu.h>
#include <simgear/props/props.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/misc/sg_path.hxx>
#include <string.h>
#include <functional>
#include <vector>
#include <map>
#include <Main/fg_props.hxx>
#include <memory> // for auto_ptr on some systems
class SGBinding;
@ -21,7 +19,7 @@ class FGMenuBar;
class FGDialog;
class FGColor;
class FGFontCache;
class puFont;
/**
* XML-configured GUI subsystem.
@ -222,7 +220,7 @@ private:
// Read all the configuration files in a directory.
void readDir (const SGPath& path);
FGMenuBar * _menubar;
std::auto_ptr<FGMenuBar> _menubar;
FGDialog * _active_dialog;
std::map<std::string,FGDialog *> _active_dialogs;
std::map<std::string,SGPropertyNode_ptr> _dialog_props;
@ -230,117 +228,5 @@ private:
};
class FGColor {
public:
FGColor() { clear(); }
FGColor(float r, float g, float b, float a = 1.0f) { set(r, g, b, a); }
FGColor(const SGPropertyNode *prop) { set(prop); }
FGColor(FGColor *c) {
if (c) set(c->_red, c->_green, c->_blue, c->_alpha);
}
inline void clear() { _red = _green = _blue = _alpha = -1.0f; }
// merges in non-negative components from property with children <red> etc.
bool merge(const SGPropertyNode *prop);
bool merge(const FGColor *color);
bool set(const SGPropertyNode *prop) { clear(); return merge(prop); };
bool set(const FGColor *color) { clear(); return merge(color); }
bool set(float r, float g, float b, float a = 1.0f) {
_red = r, _green = g, _blue = b, _alpha = a;
return true;
}
bool isValid() const {
return _red >= 0.0 && _green >= 0.0 && _blue >= 0.0;
}
void print() const;
inline void setRed(float red) { _red = red; }
inline void setGreen(float green) { _green = green; }
inline void setBlue(float blue) { _blue = blue; }
inline void setAlpha(float alpha) { _alpha = alpha; }
inline float red() const { return clamp(_red); }
inline float green() const { return clamp(_green); }
inline float blue() const { return clamp(_blue); }
inline float alpha() const { return _alpha < 0.0 ? 1.0 : clamp(_alpha); }
protected:
float _red, _green, _blue, _alpha;
private:
float clamp(float f) const { return f < 0.0 ? 0.0 : f > 1.0 ? 1.0 : f; }
};
/**
* A class to keep all fonts available for future use.
* This also assures a font isn't resident more than once.
*/
class FGFontCache {
private:
// The parameters of a request to the cache.
struct FntParams
{
const std::string name;
const float size;
const float slant;
FntParams() : size(0.0f), slant(0.0f) {}
FntParams(const FntParams& rhs)
: name(rhs.name), size(rhs.size), slant(rhs.slant)
{
}
FntParams(const std::string& name_, float size_, float slant_)
: name(name_), size(size_), slant(slant_)
{
}
};
struct FntParamsLess
: public std::binary_function<const FntParams, const FntParams, bool>
{
bool operator() (const FntParams& f1, const FntParams& f2) const;
};
struct fnt {
fnt(puFont *pu = 0) : pufont(pu), texfont(0) {}
~fnt() { if (texfont) { delete pufont; delete texfont; } }
// Font used by plib GUI code
puFont *pufont;
// TXF font
fntTexFont *texfont;
};
// Path to the font directory
SGPath _path;
typedef std::map<const std::string, fntTexFont*> TexFontMap;
typedef std::map<const FntParams, fnt*, FntParamsLess> PuFontMap;
TexFontMap _texFonts;
PuFontMap _puFonts;
bool _initialized;
struct fnt *getfnt(const char *name, float size, float slant);
void init();
public:
FGFontCache();
~FGFontCache();
puFont *get(const char *name, float size=15.0, float slant=0.0);
puFont *get(SGPropertyNode *node);
fntTexFont *getTexFont(const char *name, float size=15.0, float slant=0.0);
SGPath getfntpath(const char *name);
/**
* Preload all the fonts in the FlightGear font directory. It is
* important to load the font textures early, with the proper
* graphics context current, so that no plib (or our own) code
* tries to load a font from disk when there's no current graphics
* context.
*/
bool initializeFonts();
};
#endif // __NEW_GUI_HXX

View file

@ -27,7 +27,7 @@
#include <plib/puAux.h>
#include <simgear/props/props.hxx>
#include "dialog.hxx"
#include "FGPUIDialog.hxx"
class PropertyList : public puaList, public SGPropertyChangeListener, public GUI_ID {

View file

@ -34,9 +34,12 @@
#include <simgear/props/props_io.hxx>
#include <osg/GLU>
#include <plib/fnt.h>
#include <Main/globals.hxx>
#include <Main/viewmgr.hxx>
#include <Main/viewer.hxx>
#include <GUI/FGFontCache.hxx>
#include "HUD.hxx"

View file

@ -56,6 +56,7 @@
#include <simgear/debug/logstream.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/structure/event_mgr.hxx>
#include <simgear/structure/SGPerfMon.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/misc/sg_dir.hxx>
#include <simgear/misc/sgstream.hxx>
@ -1180,6 +1181,15 @@ bool fgInitSubsystems() {
SG_LOG( SG_GENERAL, SG_INFO, "Initialize Subsystems");
SG_LOG( SG_GENERAL, SG_INFO, "========== ==========");
////////////////////////////////////////////////////////////////////
// Initialize the sound subsystem.
////////////////////////////////////////////////////////////////////
// Sound manager uses an own subsystem group "SOUND" which is the last
// to be updated in every loop.
// Sound manager is updated last so it can use the CPU while the GPU
// is processing the scenery (doubled the frame-rate for me) -EMH-
globals->add_subsystem("sound", new SGSoundMgr, SGSubsystemMgr::SOUND);
////////////////////////////////////////////////////////////////////
// Initialize the event manager subsystem.
////////////////////////////////////////////////////////////////////
@ -1199,6 +1209,14 @@ bool fgInitSubsystems() {
////////////////////////////////////////////////////////////////////
globals->add_subsystem("properties", new FGProperties);
////////////////////////////////////////////////////////////////////
// Add the performance monitoring system.
////////////////////////////////////////////////////////////////////
globals->add_subsystem("performance-mon",
new SGPerformanceMonitor(globals->get_subsystem_mgr(),
fgGetNode("/sim/performance-monitor", true)));
////////////////////////////////////////////////////////////////////
// Initialize the material property subsystem.
////////////////////////////////////////////////////////////////////
@ -1282,7 +1300,7 @@ bool fgInitSubsystems() {
// sub system infrastructure.
////////////////////////////////////////////////////////////////////
globals->add_subsystem("Old ATC", new FGATCMgr, SGSubsystemMgr::INIT);
globals->add_subsystem("ATC-old", new FGATCMgr, SGSubsystemMgr::INIT);
////////////////////////////////////////////////////////////////////
// Initialize the ATC subsystem
@ -1304,14 +1322,14 @@ bool fgInitSubsystems() {
// Initialise the AI Model Manager
////////////////////////////////////////////////////////////////////
SG_LOG(SG_GENERAL, SG_INFO, " AI Model Manager");
globals->add_subsystem("ai_model", new FGAIManager, SGSubsystemMgr::POST_FDM);
globals->add_subsystem("submodel_mgr", new FGSubmodelMgr, SGSubsystemMgr::POST_FDM);
globals->add_subsystem("ai-model", new FGAIManager, SGSubsystemMgr::POST_FDM);
globals->add_subsystem("submodel-mgr", new FGSubmodelMgr, SGSubsystemMgr::POST_FDM);
// It's probably a good idea to initialize the top level traffic manager
// After the AI and ATC systems have been initialized properly.
// AI Traffic manager
globals->add_subsystem("Traffic Manager", new FGTrafficManager, SGSubsystemMgr::POST_FDM);
globals->add_subsystem("traffic-manager", new FGTrafficManager, SGSubsystemMgr::POST_FDM);
////////////////////////////////////////////////////////////////////
// Add a new 2D panel.
@ -1446,7 +1464,7 @@ void fgReInitSubsystems()
// Force reupdating the positions of the ai 3d models. They are used for
// initializing ground level for the FDM.
globals->get_subsystem("ai_model")->reinit();
globals->get_subsystem("ai-model")->reinit();
// Initialize the FDM
globals->get_subsystem("flight")->reinit();

View file

@ -47,7 +47,7 @@
#include <ATCDCL/ATCmgr.hxx>
#include <Autopilot/route_mgr.hxx>
#include <Cockpit/panel.hxx>
#include <GUI/new_gui.hxx>
#include <GUI/FGFontCache.hxx>
#include <Model/acmodel.hxx>
#include <Model/modelmgr.hxx>
#include <MultiPlayer/multiplaymgr.hxx>
@ -125,7 +125,6 @@ FGGlobals::FGGlobals() :
renderer( new FGRenderer ),
subsystem_mgr( new SGSubsystemMgr ),
event_mgr( new SGEventMgr ),
soundmgr( new SGSoundMgr ),
sim_time_sec( 0.0 ),
fg_root( "" ),
time_params( NULL ),
@ -151,7 +150,7 @@ FGGlobals::FGGlobals() :
dmelist( NULL ),
tacanlist( NULL ),
carrierlist( NULL ),
channellist( NULL )
channellist( NULL )
{
simgear::ResourceManager::instance()->addProvider(new AircraftResourceProvider());
simgear::PropertyObjectBase::setDefaultRoot(props);
@ -167,7 +166,7 @@ FGGlobals::~FGGlobals()
// deallocation of AIModel objects. To ensure we can safely
// shut down all subsystems, make sure we take down the
// AIModels system first.
SGSubsystem* ai = subsystem_mgr->remove("ai_model");
SGSubsystem* ai = subsystem_mgr->remove("ai-model");
if (ai) {
ai->unbind();
delete ai;
@ -206,9 +205,6 @@ FGGlobals::~FGGlobals()
delete tacanlist;
delete carrierlist;
delete channellist;
soundmgr->unbind();
delete soundmgr;
}
@ -220,7 +216,7 @@ void FGGlobals::set_fg_root (const string &root) {
SGPath tmp( fg_root );
tmp.append( "data" );
tmp.append( "version" );
if ( ulFileExists( tmp.c_str() ) ) {
if ( tmp.exists() ) {
fgGetNode("BAD_FG_ROOT", true)->setStringValue(fg_root);
fg_root += "/data";
fgGetNode("GOOD_FG_ROOT", true)->setStringValue(fg_root);
@ -360,7 +356,10 @@ FGGlobals::add_subsystem (const char * name,
SGSoundMgr *
FGGlobals::get_soundmgr () const
{
return soundmgr;
if (subsystem_mgr)
return (SGSoundMgr*) subsystem_mgr->get_subsystem("sound");
return NULL;
}
SGEventMgr *

View file

@ -91,7 +91,6 @@ private:
FGRenderer *renderer;
SGSubsystemMgr *subsystem_mgr;
SGEventMgr *event_mgr;
SGSoundMgr *soundmgr;
// Number of milliseconds elapsed since the start of the program.
double sim_time_sec;

View file

@ -82,7 +82,7 @@
#include "fg_os.hxx"
#include "WindowSystemAdapter.hxx"
#include <Main/viewer.hxx>
#include <Main/fg_props.hxx>
using namespace flightgear;
@ -93,135 +93,10 @@ using std::cerr;
// splash screen up and running right away.
int idle_state = 0;
void fgInitSoundManager();
void fgSetNewSoundDevice(const char *);
// The atexit() function handler should know when the graphical subsystem
// is initialized.
extern int _bootstrap_OSInit;
// What should we do when we have nothing else to do? Let's get ready
// for the next move and update the display?
static void fgMainLoop( void )
{
static SGPropertyNode_ptr frame_signal
= fgGetNode("/sim/signals/frame", true);
static SGPropertyNode_ptr _statisticsFlag
= fgGetNode("/sim/timing-statistics/enabled", true);
static SGPropertyNode_ptr _statisticsInterval
= fgGetNode("/sim/timing-statistics/interval-s", true);
static SGPropertyNode_ptr _statiticsMinJitter
= fgGetNode("/sim/timing-statistics/min-jitter-ms", true);
static SGPropertyNode_ptr _statiticsMinTime
= fgGetNode("/sim/timing-statistics/min-time-ms", true);
frame_signal->fireValueChanged();
SG_LOG( SG_GENERAL, SG_DEBUG, "Running Main Loop");
SG_LOG( SG_GENERAL, SG_DEBUG, "======= ==== ====");
// update "time"
double sim_dt, real_dt;
TimeManager* timeMgr = (TimeManager*) globals->get_subsystem("time");
// compute simulated time (allowing for pause, warp, etc) and
// real elapsed time
timeMgr->computeTimeDeltas(sim_dt, real_dt);
// update magvar model
globals->get_mag()->update( globals->get_aircraft_position(),
globals->get_time_params()->getJD() );
globals->get_subsystem_mgr()->update(sim_dt);
// Update the sound manager last so it can use the CPU while the GPU
// is processing the scenery (doubled the frame-rate for me) -EMH-
#ifdef ENABLE_AUDIO_SUPPORT
static bool smgr_init = true;
static SGPropertyNode *sound_working = fgGetNode("/sim/sound/working");
if (smgr_init == true) {
if (sound_working->getBoolValue() == true) {
fgInitSoundManager();
smgr_init = false;
}
} else {
static SGPropertyNode *sound_enabled = fgGetNode("/sim/sound/enabled");
static SGSoundMgr *smgr = globals->get_soundmgr();
static bool smgr_enabled = true;
if (sound_working->getBoolValue() == false) { // request to reinit
smgr->reinit();
smgr->resume();
sound_working->setBoolValue(true);
}
if (smgr_enabled != sound_enabled->getBoolValue()) {
if (smgr_enabled == true) { // request to suspend
smgr->suspend();
smgr_enabled = false;
} else {
smgr->resume();
smgr_enabled = true;
}
}
if (smgr_enabled == true) {
static SGPropertyNode *volume = fgGetNode("/sim/sound/volume");
smgr->set_volume(volume->getFloatValue());
smgr->update(sim_dt);
}
}
#endif
// END Tile Manager updates
bool scenery_loaded = fgGetBool("sim/sceneryloaded");
if (!scenery_loaded)
{
if (globals->get_tile_mgr()->isSceneryLoaded()
&& fgGetBool("sim/fdm-initialized")) {
fgSetBool("sim/sceneryloaded",true);
fgSplashProgress("");
if (fgGetBool("/sim/sound/working")) {
globals->get_soundmgr()->activate();
}
globals->get_props()->tie("/sim/sound/devices/name",
SGRawValueFunctions<const char *>(0, fgSetNewSoundDevice), false);
}
else
{
fgSplashProgress("loading scenery");
// be nice to loader threads while waiting for initial scenery, reduce to 2fps
SGTimeStamp::sleepForMSec(500);
}
}
// print timing statistics
static bool _lastStatisticsFlag = false;
if (_lastStatisticsFlag != _statisticsFlag->getBoolValue())
{
// flag has changed, update subsystem manager
_lastStatisticsFlag = _statisticsFlag->getBoolValue();
globals->get_subsystem_mgr()->collectDebugTiming(_lastStatisticsFlag);
}
if (_lastStatisticsFlag)
{
static double elapsed = 0;
elapsed += real_dt;
if (elapsed >= _statisticsInterval->getDoubleValue())
{
// print and reset timing statistics
globals->get_subsystem_mgr()->printTimingStatistics(_statiticsMinTime->getDoubleValue(),
_statiticsMinJitter->getDoubleValue());
elapsed = 0;
}
}
simgear::AtomicChangeListener::fireChangeListeners();
SG_LOG( SG_GENERAL, SG_DEBUG, "" );
}
void fgInitSoundManager()
{
@ -240,10 +115,116 @@ void fgInitSoundManager()
void fgSetNewSoundDevice(const char *device)
{
globals->get_soundmgr()->suspend();
globals->get_soundmgr()->stop();
globals->get_soundmgr()->init(device);
globals->get_soundmgr()->resume();
SGSoundMgr *smgr = globals->get_soundmgr();
smgr->suspend();
smgr->stop();
smgr->init(device);
smgr->resume();
}
// Update sound manager state (init/suspend/resume) and propagate property values,
// since the sound manager doesn't read any properties itself.
// Actual sound update is triggered by the subsystem manager.
static void fgUpdateSound(double dt)
{
#ifdef ENABLE_AUDIO_SUPPORT
static bool smgr_init = true;
static SGPropertyNode *sound_working = fgGetNode("/sim/sound/working");
if (smgr_init == true) {
if (sound_working->getBoolValue() == true) {
fgInitSoundManager();
smgr_init = false;
}
} else {
static SGPropertyNode *sound_enabled = fgGetNode("/sim/sound/enabled");
static SGSoundMgr *smgr = globals->get_soundmgr();
static bool smgr_enabled = true;
if (sound_working->getBoolValue() == false) { // request to reinit
smgr->reinit();
smgr->resume();
sound_working->setBoolValue(true);
}
if (smgr_enabled != sound_enabled->getBoolValue()) {
if (smgr_enabled == true) { // request to suspend
smgr->suspend();
smgr_enabled = false;
} else {
smgr->resume();
smgr_enabled = true;
}
}
if (smgr_enabled == true) {
static SGPropertyNode *volume = fgGetNode("/sim/sound/volume");
smgr->set_volume(volume->getFloatValue());
}
}
#endif
}
static void fgLoadInitialScenery()
{
static SGPropertyNode_ptr scenery_loaded
= fgGetNode("sim/sceneryloaded", true);
if (!scenery_loaded->getBoolValue())
{
if (globals->get_tile_mgr()->isSceneryLoaded()
&& fgGetBool("sim/fdm-initialized")) {
fgSetBool("sim/sceneryloaded",true);
fgSplashProgress("");
if (fgGetBool("/sim/sound/working")) {
globals->get_soundmgr()->activate();
}
globals->get_props()->tie("/sim/sound/devices/name",
SGRawValueFunctions<const char *>(0, fgSetNewSoundDevice), false);
}
else
{
fgSplashProgress("loading scenery");
// be nice to loader threads while waiting for initial scenery, reduce to 2fps
SGTimeStamp::sleepForMSec(500);
}
}
}
// What should we do when we have nothing else to do? Let's get ready
// for the next move and update the display?
static void fgMainLoop( void )
{
static SGPropertyNode_ptr frame_signal
= fgGetNode("/sim/signals/frame", true);
frame_signal->fireValueChanged();
SG_LOG( SG_GENERAL, SG_DEBUG, "Running Main Loop");
SG_LOG( SG_GENERAL, SG_DEBUG, "======= ==== ====");
// compute simulated time (allowing for pause, warp, etc) and
// real elapsed time
double sim_dt, real_dt;
TimeManager* timeMgr = (TimeManager*) globals->get_subsystem("time");
timeMgr->computeTimeDeltas(sim_dt, real_dt);
// update magvar model
globals->get_mag()->update( globals->get_aircraft_position(),
globals->get_time_params()->getJD() );
// Propagate sound manager properties (note: actual update is triggered
// by the subsystem manager).
fgUpdateSound(sim_dt);
// update all subsystems
globals->get_subsystem_mgr()->update(sim_dt);
// END Tile Manager updates
fgLoadInitialScenery();
simgear::AtomicChangeListener::fireChangeListeners();
SG_LOG( SG_GENERAL, SG_DEBUG, "" );
}
// Operation for querying OpenGL parameters. This must be done in a

View file

@ -46,7 +46,10 @@
#include <simgear/math/sg_random.h>
#include <simgear/misc/sg_path.hxx>
#include <GUI/new_gui.hxx>
#include <plib/fnt.h>
#include "GUI/FGFontCache.hxx"
#include "GUI/FGColor.hxx"
#include "globals.hxx"
#include "fg_props.hxx"

View file

@ -1309,7 +1309,7 @@ FGMultiplayMgr::addMultiplayer(const std::string& callsign,
mp->setCallSign(callsign);
mMultiPlayerMap[callsign] = mp;
FGAIManager *aiMgr = (FGAIManager*)globals->get_subsystem("ai_model");
FGAIManager *aiMgr = (FGAIManager*)globals->get_subsystem("ai-model");
if (aiMgr) {
aiMgr->attach(mp);

View file

@ -701,7 +701,7 @@ public:
if (modelPath.empty())
return;
FGAIManager *aiMgr;
aiMgr = static_cast<FGAIManager*>(globals->get_subsystem("ai_model"));
aiMgr = static_cast<FGAIManager*>(globals->get_subsystem("ai-model"));
if (!aiMgr)
return;

View file

@ -39,19 +39,27 @@
#include <simgear/sound/soundmgr_openal.hxx>
#include <simgear/sound/xmlsound.hxx>
FGFX::FGFX ( SGSoundMgr *smgr, const string &refname ) :
FGFX::FGFX ( SGSoundMgr *smgr, const string &refname, SGPropertyNode *props ) :
_props( props ),
_enabled( fgGetNode("/sim/sound/effects/enabled", true) ),
_volume( fgGetNode("/sim/sound/effects/volume", true) ),
_avionics_enabled( fgGetNode("/sim/sound/avionics/enabled", true) ),
_avionics_volume( fgGetNode("/sim/sound/avionics/volume", true) ),
_avionics_external( fgGetNode("/sim/sound/avionics/external-view", true) ),
_internal( fgGetNode("/sim/current-view/internal", true) )
_volume( fgGetNode("/sim/sound/effects/volume", true) )
{
if (!props) _props = globals->get_props();
_avionics_enabled = _props->getNode("sim/sound/avionics/enabled", true);
_avionics_volume = _props->getNode("sim/sound/avionics/volume", true);
_avionics_ext = _props->getNode("sim/sound/avionics/external-view", true);
_internal = _props->getNode("sim/current-view/internal", true);
SGSampleGroup::_smgr = smgr;
SGSampleGroup::_refname = refname;
SGSampleGroup::_smgr->add(this, refname);
_avionics = _smgr->find("avionics", true);
_avionics->tie_to_listener();
if (_avionics_enabled->getBoolValue())
{
_avionics = _smgr->find("avionics", true);
_avionics->tie_to_listener();
}
}
@ -67,7 +75,7 @@ FGFX::~FGFX ()
void
FGFX::init()
{
SGPropertyNode *node = fgGetNode("/sim/sound", true);
SGPropertyNode *node = _props->getNode("sim/sound", true);
string path_str = node->getStringValue("path");
if (path_str.empty()) {
@ -121,14 +129,21 @@ FGFX::reinit()
void
FGFX::update (double dt)
{
bool active = _avionics_external->getBoolValue() ||
bool active = _avionics_ext->getBoolValue() ||
_internal->getBoolValue();
if ( active && _avionics_enabled->getBoolValue() )
_avionics->resume(); // no-op if already in resumed state
else
_avionics->suspend();
_avionics->set_volume( _avionics_volume->getFloatValue() );
if (_avionics_enabled->getBoolValue()) {
if (!_avionics) {
_avionics = _smgr->find("avionics", true);
_avionics->tie_to_listener();
}
if ( active )
_avionics->resume(); // no-op if already in resumed state
else
_avionics->suspend();
_avionics->set_volume( _avionics_volume->getFloatValue() );
}
if ( _enabled->getBoolValue() ) {
set_volume( _volume->getDoubleValue() );

View file

@ -49,7 +49,7 @@ class FGFX : public SGSampleGroup
public:
FGFX ( SGSoundMgr *smgr, const string &refname );
FGFX ( SGSoundMgr *smgr, const string &refname, SGPropertyNode *props = 0 );
virtual ~FGFX ();
virtual void init ();
@ -61,11 +61,12 @@ private:
SGSharedPtr<SGSampleGroup> _avionics;
std::vector<SGXmlSound *> _sound;
SGPropertyNode_ptr _props;
SGPropertyNode_ptr _enabled;
SGPropertyNode_ptr _volume;
SGPropertyNode_ptr _avionics_enabled;
SGPropertyNode_ptr _avionics_volume;
SGPropertyNode_ptr _avionics_external;
SGPropertyNode_ptr _avionics_ext;
SGPropertyNode_ptr _internal;
};

View file

@ -53,7 +53,12 @@ static bool do_timeofday (const SGPropertyNode * arg)
TimeManager::TimeManager() :
_inited(false),
_impl(NULL)
_impl(NULL),
_sceneryLoaded("sim/sceneryloaded"),
_sceneryLoadOverride("sim/sceneryloaded-override"),
_modelHz("sim/model-hz"),
_timeDelta("sim/time/delta-realtime-sec"),
_simTimeDelta("sim/time/delta-sec")
{
SGCommandMgr::instance()->addCommand("timeofday", do_timeofday);
}
@ -102,6 +107,7 @@ void TimeManager::init()
// frame-rate / worst-case latency / update-rate counters
_frameRate = fgGetNode("/sim/frame-rate", true);
_frameLatency = fgGetNode("/sim/frame-latency-max-ms", true);
_frameRateWorst = fgGetNode("/sim/frame-rate-worst", true);
_lastFrameTime = 0;
_frameLatencyMax = 0.0;
_frameCount = 0;
@ -157,9 +163,7 @@ void TimeManager::computeTimeDeltas(double& simDt, double& realDt)
_lastClockFreeze = _clockFreeze->getBoolValue();
}
bool scenery_loaded = fgGetBool("sim/sceneryloaded");
bool wait_for_scenery = !(scenery_loaded || fgGetBool("sim/sceneryloaded-override"));
bool wait_for_scenery = !(_sceneryLoaded || _sceneryLoadOverride);
if (!wait_for_scenery) {
throttleUpdateRate();
}
@ -189,20 +193,18 @@ void TimeManager::computeTimeDeltas(double& simDt, double& realDt)
if (0 < dtMax && dtMax < dt) {
dt = dtMax;
}
int model_hz = fgGetInt("/sim/model-hz");
SGSubsystemGroup* fdmGroup =
globals->get_subsystem_mgr()->get_group(SGSubsystemMgr::FDM);
fdmGroup->set_fixed_update_time(1.0 / model_hz);
fdmGroup->set_fixed_update_time(1.0 / _modelHz);
// round the real time down to a multiple of 1/model-hz.
// this way all systems are updated the _same_ amount of dt.
dt += _dtRemainder;
int multiLoop = long(floor(dt * model_hz));
int multiLoop = long(floor(dt * _modelHz));
multiLoop = SGMisc<long>::max(0, multiLoop);
_dtRemainder = dt - double(multiLoop)/double(model_hz);
dt = double(multiLoop)/double(model_hz);
_dtRemainder = dt - double(multiLoop)/double(_modelHz);
dt = double(multiLoop)/double(_modelHz);
realDt = dt;
if (_clockFreeze->getBoolValue() || wait_for_scenery) {
@ -215,8 +217,8 @@ void TimeManager::computeTimeDeltas(double& simDt, double& realDt)
globals->inc_sim_time_sec(simDt);
// These are useful, especially for Nasal scripts.
fgSetDouble("/sim/time/delta-realtime-sec", realDt);
fgSetDouble("/sim/time/delta-sec", simDt);
_timeDelta = realDt;
_simTimeDelta = simDt;
}
void TimeManager::update(double dt)
@ -267,6 +269,8 @@ void TimeManager::computeFrameRate()
if ((_impl->get_cur_time() != _lastFrameTime)) {
_frameRate->setIntValue(_frameCount);
_frameLatency->setDoubleValue(_frameLatencyMax*1000);
if (_frameLatencyMax>0)
_frameRateWorst->setIntValue(1/_frameLatencyMax);
_frameCount = 0;
_frameLatencyMax = 0.0;
}

View file

@ -23,6 +23,7 @@
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/props/props.hxx>
#include <simgear/props/propertyObject.hxx>
// forward decls
class SGTime;
@ -82,10 +83,16 @@ private:
// frame-rate / worst-case latency / update-rate counters
SGPropertyNode_ptr _frameRate;
SGPropertyNode_ptr _frameRateWorst;
SGPropertyNode_ptr _frameLatency;
time_t _lastFrameTime;
double _frameLatencyMax;
int _frameCount;
SGPropObjBool _sceneryLoaded,
_sceneryLoadOverride;
SGPropObjInt _modelHz;
SGPropObjDouble _timeDelta, _simTimeDelta;
};
#endif // of FG_TIME_TIMEMANAGER_HXX

View file

@ -228,7 +228,7 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
if (AIManagerRef) {
// Check if this aircraft has been released.
FGTrafficManager *tmgr = (FGTrafficManager *) globals->get_subsystem("Traffic Manager");
FGTrafficManager *tmgr = (FGTrafficManager *) globals->get_subsystem("traffic-manager");
if (tmgr->isReleased(AIManagerRef)) {
AIManagerRef = 0;
} else {
@ -347,7 +347,7 @@ bool FGAISchedule::createAIAircraft(FGScheduledFlight* flight, double speedKnots
airline);
if (fp->isValidPlan()) {
aircraft->SetFlightPlan(fp);
FGAIManager* aimgr = (FGAIManager *) globals-> get_subsystem("ai_model");
FGAIManager* aimgr = (FGAIManager *) globals-> get_subsystem("ai-model");
aimgr->attach(aircraft);
AIManagerRef = aircraft->getID();
return true;
@ -465,7 +465,7 @@ FGScheduledFlight* FGAISchedule::findAvailableFlight (const string &currentDesti
{
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
FGTrafficManager *tmgr = (FGTrafficManager *) globals->get_subsystem("Traffic Manager");
FGTrafficManager *tmgr = (FGTrafficManager *) globals->get_subsystem("traffic-manager");
FGScheduledFlightVecIterator fltBegin, fltEnd;
fltBegin = tmgr->getFirstFlight(req);
fltEnd = tmgr->getLastFlight(req);

View file

@ -22,11 +22,16 @@
#include <windows.h>
#endif
#include <map>
#include <algorithm>
#include <plib/fnt.h>
#include <plib/pu.h>
#include "ApplicationProperties.hxx"
#include "FGFontCache.hxx"
////////////////////////////////////////////////////////////////////////
// FGFontCache class.
////////////////////////////////////////////////////////////////////////
@ -68,6 +73,14 @@ const GuiFont guifonts[] = {
const GuiFont* guifontsEnd = &guifonts[sizeof(guifonts)/ sizeof(guifonts[0])];
}
FGFontCache::fnt::~fnt()
{
if (texfont) {
delete pufont;
delete texfont;
}
}
FGFontCache::FGFontCache() :
_initialized(false)
{

View file

@ -14,10 +14,16 @@
//
#ifndef __FGFONTCACHE_HXX
#define __FGFONTCACHE_HXX
#include <simgear/math/SGMath.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/props/props.hxx>
#include <plib/pu.h>
// forward declare only!
class puFont;
class fntTexFont;
/**
* A class to keep all fonts available for future use.
* This also assures a font isn't resident more than once.
@ -47,7 +53,7 @@ private:
};
struct fnt {
fnt(puFont *pu = 0) : pufont(pu), texfont(0) {}
~fnt() { if (texfont) { delete pufont; delete texfont; } }
~fnt();
// Font used by plib GUI code
puFont *pufont;
// TXF font