Merge branch 'next' into comm-subsystem
This commit is contained in:
commit
0025dfb9bc
46 changed files with 3332 additions and 2662 deletions
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
>
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include <simgear/compiler.h>
|
||||
#include <plib/puAux.h>
|
||||
#include "dialog.hxx"
|
||||
#include "FGPUIDialog.hxx"
|
||||
|
||||
class FGAirportList;
|
||||
|
||||
|
|
|
@ -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}")
|
||||
|
|
65
src/GUI/FGCocoaMenuBar.hxx
Normal file
65
src/GUI/FGCocoaMenuBar.hxx
Normal 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
231
src/GUI/FGCocoaMenuBar.mm
Normal 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
55
src/GUI/FGColor.cxx
Normal 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
49
src/GUI/FGColor.hxx
Normal 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
223
src/GUI/FGFontCache.cxx
Normal 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
96
src/GUI/FGFontCache.hxx
Normal 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
1418
src/GUI/FGPUIDialog.cxx
Normal file
File diff suppressed because it is too large
Load diff
277
src/GUI/FGPUIDialog.hxx
Normal file
277
src/GUI/FGPUIDialog.hxx
Normal 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
376
src/GUI/FGPUIMenuBar.cxx
Normal 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
138
src/GUI/FGPUIMenuBar.hxx
Normal 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
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
#include <plib/pu.h>
|
||||
|
||||
#include "dialog.hxx" // for GUI_ID
|
||||
#include "FGPUIDialog.hxx" // for GUI_ID
|
||||
|
||||
// forward decls
|
||||
class puaScrollBar;
|
||||
|
|
1404
src/GUI/dialog.cxx
1404
src/GUI/dialog.cxx
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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() );
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ¤tDesti
|
|||
{
|
||||
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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue