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
|
#packaging
|
||||||
|
|
||||||
# split version string into components, note CMAKE_MATCH_0 is the entire regexp match
|
# 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} )
|
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_MAJOR ${CMAKE_MATCH_1})
|
||||||
set(CPACK_PACKAGE_VERSION_MINOR ${CMAKE_MATCH_2})
|
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_GENERATOR TBZ2 ZIP)
|
||||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME "flightgear-${FLIGHTGEAR_VERSION}" CACHE INTERNAL "tarball basename")
|
set(CPACK_SOURCE_PACKAGE_FILE_NAME "flightgear-${FLIGHTGEAR_VERSION}" CACHE INTERNAL "tarball basename")
|
||||||
set(CPACK_SOURCE_IGNORE_FILES
|
#set(CPACK_SOURCE_IGNORE_FILES
|
||||||
"^${PROJECT_SOURCE_DIR}/.git;\\\\.gitignore;Makefile.am;~$;${CPACK_SOURCE_IGNORE_FILES}")
|
# "^${PROJECT_SOURCE_DIR}/.git;\\\\.gitignore;Makefile.am;~$;${CPACK_SOURCE_IGNORE_FILES}")
|
||||||
|
|
||||||
include (CPack)
|
include (CPack)
|
||||||
|
|
||||||
|
@ -64,7 +65,8 @@ IF(APPLE)
|
||||||
set(EVENT_INPUT_DEFAULT 1)
|
set(EVENT_INPUT_DEFAULT 1)
|
||||||
|
|
||||||
find_library(CORESERVICES_LIBRARY CoreServices)
|
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")
|
elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||||
# disabled while DBus / HAL / udev issues are decided
|
# disabled while DBus / HAL / udev issues are decided
|
||||||
|
|
|
@ -385,14 +385,6 @@
|
||||||
RelativePath="..\..\..\src\Aircraft\controls.hxx"
|
RelativePath="..\..\..\src\Aircraft\controls.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\..\src\Aircraft\replay.cxx"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\..\src\Aircraft\replay.hxx"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\..\src\Aircraft\flightrecorder.cxx"
|
RelativePath="..\..\..\src\Aircraft\flightrecorder.cxx"
|
||||||
>
|
>
|
||||||
|
@ -401,6 +393,14 @@
|
||||||
RelativePath="..\..\..\src\Aircraft\flightrecorder.hxx"
|
RelativePath="..\..\..\src\Aircraft\flightrecorder.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\Aircraft\replay.cxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\Aircraft\replay.hxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="Lib_Airports"
|
Name="Lib_Airports"
|
||||||
|
@ -2525,6 +2525,38 @@
|
||||||
RelativePath="..\..\..\src\GUI\dialog.hxx"
|
RelativePath="..\..\..\src\GUI\dialog.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</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
|
<File
|
||||||
RelativePath="..\..\..\src\Gui\fonts.cxx"
|
RelativePath="..\..\..\src\Gui\fonts.cxx"
|
||||||
>
|
>
|
||||||
|
@ -3753,6 +3785,14 @@
|
||||||
RelativePath="..\..\..\src\Instrumentation\mrg.hxx"
|
RelativePath="..\..\..\src\Instrumentation\mrg.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\Instrumentation\NavDisplay.cxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\..\src\Instrumentation\NavDisplay.hxx"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\..\src\Instrumentation\navradio.cxx"
|
RelativePath="..\..\..\src\Instrumentation\navradio.cxx"
|
||||||
>
|
>
|
||||||
|
@ -3777,14 +3817,6 @@
|
||||||
RelativePath="..\..\..\src\Instrumentation\od_gauge.hxx"
|
RelativePath="..\..\..\src\Instrumentation\od_gauge.hxx"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\..\..\src\Instrumentation\NavDisplay.cxx"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\..\src\Instrumentation\NavDisplay.hxx"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\..\src\Instrumentation\rad_alt.cxx"
|
RelativePath="..\..\..\src\Instrumentation\rad_alt.cxx"
|
||||||
>
|
>
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
#include <Scenery/scenery.hxx>
|
#include <Scenery/scenery.hxx>
|
||||||
#include <Scripting/NasalSys.hxx>
|
#include <Scripting/NasalSys.hxx>
|
||||||
|
#include <Sound/fg_fx.hxx>
|
||||||
|
|
||||||
#include "AIBase.hxx"
|
#include "AIBase.hxx"
|
||||||
#include "AIManager.hxx"
|
#include "AIManager.hxx"
|
||||||
|
@ -70,7 +71,8 @@ FGAIBase::FGAIBase(object_type ot, bool enableHot) :
|
||||||
_impact_speed(0),
|
_impact_speed(0),
|
||||||
_refID( _newAIModelID() ),
|
_refID( _newAIModelID() ),
|
||||||
_otype(ot),
|
_otype(ot),
|
||||||
_initialized(false)
|
_initialized(false),
|
||||||
|
_fx(0)
|
||||||
|
|
||||||
{
|
{
|
||||||
tgt_heading = hdg = tgt_altitude_ft = tgt_speed = 0.0;
|
tgt_heading = hdg = tgt_altitude_ft = tgt_speed = 0.0;
|
||||||
|
@ -137,6 +139,9 @@ FGAIBase::~FGAIBase() {
|
||||||
if (parent)
|
if (parent)
|
||||||
model_removed->setStringValue(props->getPath());
|
model_removed->setStringValue(props->getPath());
|
||||||
}
|
}
|
||||||
|
delete _fx;
|
||||||
|
_fx = 0;
|
||||||
|
|
||||||
delete fp;
|
delete fp;
|
||||||
fp = 0;
|
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_lat = 366468.96 - 3717.12 * cos(pos.getLatitudeRad());
|
||||||
ft_per_deg_lon = 365228.16 * 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 */
|
/** update LOD properties of the model */
|
||||||
|
@ -293,6 +311,20 @@ bool FGAIBase::init(bool search_in_AI_path) {
|
||||||
aip.setVisible(true);
|
aip.setVisible(true);
|
||||||
invisible = false;
|
invisible = false;
|
||||||
globals->get_scenery()->get_scene_graph()->addChild(aip.getSceneGraph());
|
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;
|
_initialized = true;
|
||||||
|
|
||||||
} else if (!model_path.empty()) {
|
} 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-alt", altitude_ft);
|
||||||
props->setDoubleValue("controls/flight/target-pitch", pitch);
|
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 SGMaterial;
|
||||||
class FGAIManager;
|
class FGAIManager;
|
||||||
class FGAIFlightPlan;
|
class FGAIFlightPlan;
|
||||||
|
class FGFX;
|
||||||
|
|
||||||
class FGAIBase : public SGReferenced {
|
class FGAIBase : public SGReferenced {
|
||||||
|
|
||||||
|
@ -225,6 +226,7 @@ private:
|
||||||
object_type _otype;
|
object_type _otype;
|
||||||
bool _initialized;
|
bool _initialized;
|
||||||
osg::ref_ptr<osg::LOD> _model; //The 3D model LOD object
|
osg::ref_ptr<osg::LOD> _model; //The 3D model LOD object
|
||||||
|
SGSharedPtr<FGFX> _fx;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
object_type getType();
|
object_type getType();
|
||||||
|
|
|
@ -146,7 +146,7 @@ FGAIManager::update(double dt) {
|
||||||
if (!enabled)
|
if (!enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
FGTrafficManager *tmgr = (FGTrafficManager*) globals->get_subsystem("Traffic Manager");
|
FGTrafficManager *tmgr = (FGTrafficManager*) globals->get_subsystem("traffic-manager");
|
||||||
_dt = dt;
|
_dt = dt;
|
||||||
|
|
||||||
ai_list_iterator ai_list_itr = ai_list.begin();
|
ai_list_iterator ai_list_itr = ai_list.begin();
|
||||||
|
|
|
@ -45,7 +45,7 @@ FGSubmodelMgr::~FGSubmodelMgr()
|
||||||
|
|
||||||
FGAIManager* FGSubmodelMgr::aiManager()
|
FGAIManager* FGSubmodelMgr::aiManager()
|
||||||
{
|
{
|
||||||
return (FGAIManager*)globals->get_subsystem("ai_model");
|
return (FGAIManager*)globals->get_subsystem("ai-model");
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGSubmodelMgr::init()
|
void FGSubmodelMgr::init()
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#include <Main/fg_commands.hxx>
|
#include <Main/fg_commands.hxx>
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
|
#include <Main/fg_props.hxx>
|
||||||
|
|
||||||
#include <simgear/constants.h>
|
#include <simgear/constants.h>
|
||||||
#include <simgear/structure/commands.hxx>
|
#include <simgear/structure/commands.hxx>
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
#include <GUI/gui.h> // mkDialog
|
#include <GUI/gui.h> // mkDialog
|
||||||
#include <GUI/new_gui.hxx>
|
#include <GUI/new_gui.hxx>
|
||||||
|
#include <Main/fg_props.hxx>
|
||||||
|
|
||||||
#include "ATCDialogOld.hxx"
|
#include "ATCDialogOld.hxx"
|
||||||
#include "ATC.hxx"
|
#include "ATC.hxx"
|
||||||
|
|
|
@ -57,7 +57,7 @@
|
||||||
#include <Main/fg_props.hxx>
|
#include <Main/fg_props.hxx>
|
||||||
#include <Main/viewmgr.hxx>
|
#include <Main/viewmgr.hxx>
|
||||||
#include <Time/light.hxx>
|
#include <Time/light.hxx>
|
||||||
#include <GUI/new_gui.hxx> // FGFontCache
|
#include <GUI/FGFontCache.hxx>
|
||||||
#include <Main/viewer.hxx>
|
#include <Main/viewer.hxx>
|
||||||
#include <Instrumentation/dclgps.hxx>
|
#include <Instrumentation/dclgps.hxx>
|
||||||
|
|
||||||
|
|
|
@ -261,8 +261,8 @@ FGGasCell::~FGGasCell()
|
||||||
void FGGasCell::Calculate(double dt)
|
void FGGasCell::Calculate(double dt)
|
||||||
{
|
{
|
||||||
const double AirTemperature = in.Temperature; // [Rankine]
|
const double AirTemperature = in.Temperature; // [Rankine]
|
||||||
const double AirPressure = in.Pressure; // [lbs/ft²]
|
const double AirPressure = in.Pressure; // [lbs/ft^2]
|
||||||
const double AirDensity = in.Density; // [slug/ft³]
|
const double AirDensity = in.Density; // [slug/ft^3]
|
||||||
const double g = in.gravity; // [lbs/slug]
|
const double g = in.gravity; // [lbs/slug]
|
||||||
|
|
||||||
const double OldTemperature = Temperature;
|
const double OldTemperature = Temperature;
|
||||||
|
@ -689,8 +689,8 @@ FGBallonet::~FGBallonet()
|
||||||
|
|
||||||
void FGBallonet::Calculate(double dt)
|
void FGBallonet::Calculate(double dt)
|
||||||
{
|
{
|
||||||
const double ParentPressure = Parent->GetPressure(); // [lbs/ft²]
|
const double ParentPressure = Parent->GetPressure(); // [lbs/ft^2]
|
||||||
const double AirPressure = Pressure; // [lbs/ft²]
|
const double AirPressure = in.Pressure; // [lbs/ft^2]
|
||||||
|
|
||||||
const double OldTemperature = Temperature;
|
const double OldTemperature = Temperature;
|
||||||
const double OldPressure = Pressure;
|
const double OldPressure = Pressure;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
#include <plib/puAux.h>
|
#include <plib/puAux.h>
|
||||||
#include "dialog.hxx"
|
#include "FGPUIDialog.hxx"
|
||||||
|
|
||||||
class FGAirportList;
|
class FGAirportList;
|
||||||
|
|
||||||
|
|
|
@ -6,14 +6,18 @@ set(SOURCES
|
||||||
SafeTexFont.cxx
|
SafeTexFont.cxx
|
||||||
WaypointList.cxx
|
WaypointList.cxx
|
||||||
dialog.cxx
|
dialog.cxx
|
||||||
|
FGPUIDialog.cxx
|
||||||
fonts.cxx
|
fonts.cxx
|
||||||
gui.cxx
|
gui.cxx
|
||||||
gui_funcs.cxx
|
gui_funcs.cxx
|
||||||
layout-props.cxx
|
layout-props.cxx
|
||||||
layout.cxx
|
layout.cxx
|
||||||
menubar.cxx
|
menubar.cxx
|
||||||
|
FGPUIMenuBar.cxx
|
||||||
new_gui.cxx
|
new_gui.cxx
|
||||||
property_list.cxx
|
property_list.cxx
|
||||||
|
FGFontCache.cxx
|
||||||
|
FGColor.cxx
|
||||||
)
|
)
|
||||||
|
|
||||||
set(HEADERS
|
set(HEADERS
|
||||||
|
@ -22,11 +26,20 @@ set(HEADERS
|
||||||
SafeTexFont.hxx
|
SafeTexFont.hxx
|
||||||
WaypointList.hxx
|
WaypointList.hxx
|
||||||
dialog.hxx
|
dialog.hxx
|
||||||
|
FGPUIDialog.hxx
|
||||||
gui.h
|
gui.h
|
||||||
layout.hxx
|
layout.hxx
|
||||||
menubar.hxx
|
menubar.hxx
|
||||||
|
FGPUIMenuBar.hxx
|
||||||
new_gui.hxx
|
new_gui.hxx
|
||||||
property_list.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}")
|
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 <plib/pu.h>
|
||||||
|
|
||||||
#include "dialog.hxx" // for GUI_ID
|
#include "FGPUIDialog.hxx" // for GUI_ID
|
||||||
|
|
||||||
// forward decls
|
// forward decls
|
||||||
class puaScrollBar;
|
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++
|
# error This library requires C++
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <plib/puAux.h>
|
// forward decls
|
||||||
|
class SGPropertyNode;
|
||||||
#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;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An XML-configured dialog box.
|
* An XML-configured dialog box.
|
||||||
|
@ -45,16 +22,6 @@ class FGDialog
|
||||||
{
|
{
|
||||||
public:
|
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.
|
* @param objectName The name of the GUI object(s) to update.
|
||||||
* Use the empty name for all unnamed objects.
|
* 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.
|
* @param objectName The name of the GUI object(s) to update.
|
||||||
* Use the empty name for all unnamed objects.
|
* 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.
|
* Update state. Called on active dialogs before rendering.
|
||||||
*/
|
*/
|
||||||
virtual void update ();
|
virtual void update () = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* 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();
|
|
||||||
|
|
||||||
protected:
|
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:
|
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
|
#endif // __DIALOG_HXX
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include <Main/fg_props.hxx>
|
#include <Main/fg_props.hxx>
|
||||||
#include <Main/WindowSystemAdapter.hxx>
|
#include <Main/WindowSystemAdapter.hxx>
|
||||||
#include <GUI/new_gui.hxx>
|
#include <GUI/new_gui.hxx>
|
||||||
|
#include <GUI/FGFontCache.hxx>
|
||||||
|
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
#include "layout.hxx"
|
#include "layout.hxx"
|
||||||
|
|
|
@ -2,373 +2,11 @@
|
||||||
# include <config.h>
|
# include <config.h>
|
||||||
#endif
|
#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"
|
#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 ()
|
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
|
// end of menubar.cxx
|
||||||
|
|
|
@ -3,42 +3,19 @@
|
||||||
#ifndef __MENUBAR_HXX
|
#ifndef __MENUBAR_HXX
|
||||||
#define __MENUBAR_HXX 1
|
#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
|
* This class creates a menu bar from a tree of XML properties. These
|
||||||
* properties are not part of the main FlightGear property tree, but
|
* properties are not part of the main FlightGear property tree, but
|
||||||
* are read from a separate file ($FG_ROOT/gui/menubar.xml).
|
* 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
|
class FGMenuBar
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor.
|
|
||||||
*/
|
|
||||||
FGMenuBar ();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destructor.
|
* Destructor.
|
||||||
|
@ -49,89 +26,25 @@ public:
|
||||||
/**
|
/**
|
||||||
* Initialize the menu bar from $FG_ROOT/gui/menubar.xml
|
* Initialize the menu bar from $FG_ROOT/gui/menubar.xml
|
||||||
*/
|
*/
|
||||||
virtual void init ();
|
virtual void init () = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make the menu bar visible.
|
* Make the menu bar visible.
|
||||||
*/
|
*/
|
||||||
virtual void show ();
|
virtual void show () = 0;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make the menu bar invisible.
|
* Make the menu bar invisible.
|
||||||
*/
|
*/
|
||||||
virtual void hide ();
|
virtual void hide () = 0;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test whether the menu bar is visible.
|
* 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
|
#endif // __MENUBAR_HXX
|
||||||
|
|
|
@ -26,11 +26,15 @@
|
||||||
#include "GL/glx.h"
|
#include "GL/glx.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "menubar.hxx"
|
#include "FGPUIMenuBar.hxx"
|
||||||
#include "dialog.hxx"
|
|
||||||
|
|
||||||
extern puFont FONT_HELVETICA_14;
|
#if defined(SG_MAC)
|
||||||
extern puFont FONT_SANS_12B;
|
#include "FGCocoaMenuBar.hxx"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "FGPUIDialog.hxx"
|
||||||
|
#include "FGFontCache.hxx"
|
||||||
|
#include "FGColor.hxx"
|
||||||
|
|
||||||
using std::map;
|
using std::map;
|
||||||
using std::string;
|
using std::string;
|
||||||
|
@ -41,15 +45,18 @@ using std::string;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
NewGUI::NewGUI ()
|
NewGUI::NewGUI () :
|
||||||
: _menubar(new FGMenuBar),
|
_active_dialog(0)
|
||||||
_active_dialog(0)
|
|
||||||
{
|
{
|
||||||
|
#if defined(SG_MAC)
|
||||||
|
_menubar.reset(new FGCocoaMenuBar);
|
||||||
|
#else
|
||||||
|
_menubar.reset(new FGPUIMenuBar);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
NewGUI::~NewGUI ()
|
NewGUI::~NewGUI ()
|
||||||
{
|
{
|
||||||
delete _menubar;
|
|
||||||
_dialog_props.clear();
|
_dialog_props.clear();
|
||||||
for (_itt_t it = _colors.begin(); it != _colors.end(); ++it)
|
for (_itt_t it = _colors.begin(); it != _colors.end(); ++it)
|
||||||
delete it->second;
|
delete it->second;
|
||||||
|
@ -81,7 +88,7 @@ void
|
||||||
NewGUI::reset (bool reload)
|
NewGUI::reset (bool reload)
|
||||||
{
|
{
|
||||||
map<string,FGDialog *>::iterator iter;
|
map<string,FGDialog *>::iterator iter;
|
||||||
vector<string> dlg;
|
std::vector<string> dlg;
|
||||||
// close all open dialogs and remember them ...
|
// close all open dialogs and remember them ...
|
||||||
for (iter = _active_dialogs.begin(); iter != _active_dialogs.end(); ++iter)
|
for (iter = _active_dialogs.begin(); iter != _active_dialogs.end(); ++iter)
|
||||||
dlg.push_back(iter->first);
|
dlg.push_back(iter->first);
|
||||||
|
@ -93,8 +100,9 @@ NewGUI::reset (bool reload)
|
||||||
setStyle();
|
setStyle();
|
||||||
|
|
||||||
unbind();
|
unbind();
|
||||||
delete _menubar;
|
#if !defined(SG_MAC)
|
||||||
_menubar = new FGMenuBar;
|
_menubar.reset(new FGPUIMenuBar);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (reload) {
|
if (reload) {
|
||||||
_dialog_props.clear();
|
_dialog_props.clear();
|
||||||
|
@ -139,7 +147,7 @@ NewGUI::showDialog (const string &name)
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
if(!_active_dialogs[name])
|
if(!_active_dialogs[name])
|
||||||
_active_dialogs[name] = new FGDialog(_dialog_props[name]);
|
_active_dialogs[name] = new FGPUIDialog(_dialog_props[name]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,7 +223,7 @@ NewGUI::getActiveDialog ()
|
||||||
FGMenuBar *
|
FGMenuBar *
|
||||||
NewGUI::getMenuBar ()
|
NewGUI::getMenuBar ()
|
||||||
{
|
{
|
||||||
return _menubar;
|
return _menubar.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -326,247 +334,4 @@ NewGUI::setupFont (SGPropertyNode *node)
|
||||||
return;
|
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
|
// end of new_gui.cxx
|
||||||
|
|
|
@ -3,17 +3,15 @@
|
||||||
#ifndef __NEW_GUI_HXX
|
#ifndef __NEW_GUI_HXX
|
||||||
#define __NEW_GUI_HXX 1
|
#define __NEW_GUI_HXX 1
|
||||||
|
|
||||||
#include <plib/pu.h>
|
|
||||||
|
|
||||||
#include <simgear/props/props.hxx>
|
#include <simgear/props/props.hxx>
|
||||||
#include <simgear/structure/subsystem_mgr.hxx>
|
#include <simgear/structure/subsystem_mgr.hxx>
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory> // for auto_ptr on some systems
|
||||||
#include <Main/fg_props.hxx>
|
|
||||||
|
|
||||||
class SGBinding;
|
class SGBinding;
|
||||||
|
|
||||||
|
@ -21,7 +19,7 @@ class FGMenuBar;
|
||||||
class FGDialog;
|
class FGDialog;
|
||||||
class FGColor;
|
class FGColor;
|
||||||
class FGFontCache;
|
class FGFontCache;
|
||||||
|
class puFont;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* XML-configured GUI subsystem.
|
* XML-configured GUI subsystem.
|
||||||
|
@ -222,7 +220,7 @@ private:
|
||||||
// Read all the configuration files in a directory.
|
// Read all the configuration files in a directory.
|
||||||
void readDir (const SGPath& path);
|
void readDir (const SGPath& path);
|
||||||
|
|
||||||
FGMenuBar * _menubar;
|
std::auto_ptr<FGMenuBar> _menubar;
|
||||||
FGDialog * _active_dialog;
|
FGDialog * _active_dialog;
|
||||||
std::map<std::string,FGDialog *> _active_dialogs;
|
std::map<std::string,FGDialog *> _active_dialogs;
|
||||||
std::map<std::string,SGPropertyNode_ptr> _dialog_props;
|
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
|
#endif // __NEW_GUI_HXX
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
#include <plib/puAux.h>
|
#include <plib/puAux.h>
|
||||||
#include <simgear/props/props.hxx>
|
#include <simgear/props/props.hxx>
|
||||||
#include "dialog.hxx"
|
#include "FGPUIDialog.hxx"
|
||||||
|
|
||||||
|
|
||||||
class PropertyList : public puaList, public SGPropertyChangeListener, public GUI_ID {
|
class PropertyList : public puaList, public SGPropertyChangeListener, public GUI_ID {
|
||||||
|
|
|
@ -34,9 +34,12 @@
|
||||||
#include <simgear/props/props_io.hxx>
|
#include <simgear/props/props_io.hxx>
|
||||||
#include <osg/GLU>
|
#include <osg/GLU>
|
||||||
|
|
||||||
|
#include <plib/fnt.h>
|
||||||
|
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
#include <Main/viewmgr.hxx>
|
#include <Main/viewmgr.hxx>
|
||||||
#include <Main/viewer.hxx>
|
#include <Main/viewer.hxx>
|
||||||
|
#include <GUI/FGFontCache.hxx>
|
||||||
|
|
||||||
#include "HUD.hxx"
|
#include "HUD.hxx"
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
#include <simgear/structure/exception.hxx>
|
#include <simgear/structure/exception.hxx>
|
||||||
#include <simgear/structure/event_mgr.hxx>
|
#include <simgear/structure/event_mgr.hxx>
|
||||||
|
#include <simgear/structure/SGPerfMon.hxx>
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
#include <simgear/misc/sg_dir.hxx>
|
#include <simgear/misc/sg_dir.hxx>
|
||||||
#include <simgear/misc/sgstream.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 Subsystems");
|
||||||
SG_LOG( SG_GENERAL, SG_INFO, "========== ==========");
|
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.
|
// Initialize the event manager subsystem.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1199,6 +1209,14 @@ bool fgInitSubsystems() {
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
globals->add_subsystem("properties", new FGProperties);
|
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.
|
// Initialize the material property subsystem.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1282,7 +1300,7 @@ bool fgInitSubsystems() {
|
||||||
// sub system infrastructure.
|
// 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
|
// Initialize the ATC subsystem
|
||||||
|
@ -1304,14 +1322,14 @@ bool fgInitSubsystems() {
|
||||||
// Initialise the AI Model Manager
|
// Initialise the AI Model Manager
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
SG_LOG(SG_GENERAL, SG_INFO, " 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("ai-model", new FGAIManager, SGSubsystemMgr::POST_FDM);
|
||||||
globals->add_subsystem("submodel_mgr", new FGSubmodelMgr, 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
|
// It's probably a good idea to initialize the top level traffic manager
|
||||||
// After the AI and ATC systems have been initialized properly.
|
// After the AI and ATC systems have been initialized properly.
|
||||||
// AI Traffic manager
|
// 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.
|
// Add a new 2D panel.
|
||||||
|
@ -1446,7 +1464,7 @@ void fgReInitSubsystems()
|
||||||
|
|
||||||
// Force reupdating the positions of the ai 3d models. They are used for
|
// Force reupdating the positions of the ai 3d models. They are used for
|
||||||
// initializing ground level for the FDM.
|
// initializing ground level for the FDM.
|
||||||
globals->get_subsystem("ai_model")->reinit();
|
globals->get_subsystem("ai-model")->reinit();
|
||||||
|
|
||||||
// Initialize the FDM
|
// Initialize the FDM
|
||||||
globals->get_subsystem("flight")->reinit();
|
globals->get_subsystem("flight")->reinit();
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
#include <ATCDCL/ATCmgr.hxx>
|
#include <ATCDCL/ATCmgr.hxx>
|
||||||
#include <Autopilot/route_mgr.hxx>
|
#include <Autopilot/route_mgr.hxx>
|
||||||
#include <Cockpit/panel.hxx>
|
#include <Cockpit/panel.hxx>
|
||||||
#include <GUI/new_gui.hxx>
|
#include <GUI/FGFontCache.hxx>
|
||||||
#include <Model/acmodel.hxx>
|
#include <Model/acmodel.hxx>
|
||||||
#include <Model/modelmgr.hxx>
|
#include <Model/modelmgr.hxx>
|
||||||
#include <MultiPlayer/multiplaymgr.hxx>
|
#include <MultiPlayer/multiplaymgr.hxx>
|
||||||
|
@ -125,7 +125,6 @@ FGGlobals::FGGlobals() :
|
||||||
renderer( new FGRenderer ),
|
renderer( new FGRenderer ),
|
||||||
subsystem_mgr( new SGSubsystemMgr ),
|
subsystem_mgr( new SGSubsystemMgr ),
|
||||||
event_mgr( new SGEventMgr ),
|
event_mgr( new SGEventMgr ),
|
||||||
soundmgr( new SGSoundMgr ),
|
|
||||||
sim_time_sec( 0.0 ),
|
sim_time_sec( 0.0 ),
|
||||||
fg_root( "" ),
|
fg_root( "" ),
|
||||||
time_params( NULL ),
|
time_params( NULL ),
|
||||||
|
@ -151,7 +150,7 @@ FGGlobals::FGGlobals() :
|
||||||
dmelist( NULL ),
|
dmelist( NULL ),
|
||||||
tacanlist( NULL ),
|
tacanlist( NULL ),
|
||||||
carrierlist( NULL ),
|
carrierlist( NULL ),
|
||||||
channellist( NULL )
|
channellist( NULL )
|
||||||
{
|
{
|
||||||
simgear::ResourceManager::instance()->addProvider(new AircraftResourceProvider());
|
simgear::ResourceManager::instance()->addProvider(new AircraftResourceProvider());
|
||||||
simgear::PropertyObjectBase::setDefaultRoot(props);
|
simgear::PropertyObjectBase::setDefaultRoot(props);
|
||||||
|
@ -167,7 +166,7 @@ FGGlobals::~FGGlobals()
|
||||||
// deallocation of AIModel objects. To ensure we can safely
|
// deallocation of AIModel objects. To ensure we can safely
|
||||||
// shut down all subsystems, make sure we take down the
|
// shut down all subsystems, make sure we take down the
|
||||||
// AIModels system first.
|
// AIModels system first.
|
||||||
SGSubsystem* ai = subsystem_mgr->remove("ai_model");
|
SGSubsystem* ai = subsystem_mgr->remove("ai-model");
|
||||||
if (ai) {
|
if (ai) {
|
||||||
ai->unbind();
|
ai->unbind();
|
||||||
delete ai;
|
delete ai;
|
||||||
|
@ -206,9 +205,6 @@ FGGlobals::~FGGlobals()
|
||||||
delete tacanlist;
|
delete tacanlist;
|
||||||
delete carrierlist;
|
delete carrierlist;
|
||||||
delete channellist;
|
delete channellist;
|
||||||
|
|
||||||
soundmgr->unbind();
|
|
||||||
delete soundmgr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -220,7 +216,7 @@ void FGGlobals::set_fg_root (const string &root) {
|
||||||
SGPath tmp( fg_root );
|
SGPath tmp( fg_root );
|
||||||
tmp.append( "data" );
|
tmp.append( "data" );
|
||||||
tmp.append( "version" );
|
tmp.append( "version" );
|
||||||
if ( ulFileExists( tmp.c_str() ) ) {
|
if ( tmp.exists() ) {
|
||||||
fgGetNode("BAD_FG_ROOT", true)->setStringValue(fg_root);
|
fgGetNode("BAD_FG_ROOT", true)->setStringValue(fg_root);
|
||||||
fg_root += "/data";
|
fg_root += "/data";
|
||||||
fgGetNode("GOOD_FG_ROOT", true)->setStringValue(fg_root);
|
fgGetNode("GOOD_FG_ROOT", true)->setStringValue(fg_root);
|
||||||
|
@ -360,7 +356,10 @@ FGGlobals::add_subsystem (const char * name,
|
||||||
SGSoundMgr *
|
SGSoundMgr *
|
||||||
FGGlobals::get_soundmgr () const
|
FGGlobals::get_soundmgr () const
|
||||||
{
|
{
|
||||||
return soundmgr;
|
if (subsystem_mgr)
|
||||||
|
return (SGSoundMgr*) subsystem_mgr->get_subsystem("sound");
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SGEventMgr *
|
SGEventMgr *
|
||||||
|
|
|
@ -91,7 +91,6 @@ private:
|
||||||
FGRenderer *renderer;
|
FGRenderer *renderer;
|
||||||
SGSubsystemMgr *subsystem_mgr;
|
SGSubsystemMgr *subsystem_mgr;
|
||||||
SGEventMgr *event_mgr;
|
SGEventMgr *event_mgr;
|
||||||
SGSoundMgr *soundmgr;
|
|
||||||
|
|
||||||
// Number of milliseconds elapsed since the start of the program.
|
// Number of milliseconds elapsed since the start of the program.
|
||||||
double sim_time_sec;
|
double sim_time_sec;
|
||||||
|
|
|
@ -82,7 +82,7 @@
|
||||||
#include "fg_os.hxx"
|
#include "fg_os.hxx"
|
||||||
#include "WindowSystemAdapter.hxx"
|
#include "WindowSystemAdapter.hxx"
|
||||||
#include <Main/viewer.hxx>
|
#include <Main/viewer.hxx>
|
||||||
|
#include <Main/fg_props.hxx>
|
||||||
|
|
||||||
using namespace flightgear;
|
using namespace flightgear;
|
||||||
|
|
||||||
|
@ -93,135 +93,10 @@ using std::cerr;
|
||||||
// splash screen up and running right away.
|
// splash screen up and running right away.
|
||||||
int idle_state = 0;
|
int idle_state = 0;
|
||||||
|
|
||||||
|
|
||||||
void fgInitSoundManager();
|
|
||||||
void fgSetNewSoundDevice(const char *);
|
|
||||||
|
|
||||||
// The atexit() function handler should know when the graphical subsystem
|
// The atexit() function handler should know when the graphical subsystem
|
||||||
// is initialized.
|
// is initialized.
|
||||||
extern int _bootstrap_OSInit;
|
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()
|
void fgInitSoundManager()
|
||||||
{
|
{
|
||||||
|
@ -240,10 +115,116 @@ void fgInitSoundManager()
|
||||||
|
|
||||||
void fgSetNewSoundDevice(const char *device)
|
void fgSetNewSoundDevice(const char *device)
|
||||||
{
|
{
|
||||||
globals->get_soundmgr()->suspend();
|
SGSoundMgr *smgr = globals->get_soundmgr();
|
||||||
globals->get_soundmgr()->stop();
|
smgr->suspend();
|
||||||
globals->get_soundmgr()->init(device);
|
smgr->stop();
|
||||||
globals->get_soundmgr()->resume();
|
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
|
// Operation for querying OpenGL parameters. This must be done in a
|
||||||
|
|
|
@ -46,7 +46,10 @@
|
||||||
#include <simgear/math/sg_random.h>
|
#include <simgear/math/sg_random.h>
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#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 "globals.hxx"
|
||||||
#include "fg_props.hxx"
|
#include "fg_props.hxx"
|
||||||
|
|
|
@ -1309,7 +1309,7 @@ FGMultiplayMgr::addMultiplayer(const std::string& callsign,
|
||||||
mp->setCallSign(callsign);
|
mp->setCallSign(callsign);
|
||||||
mMultiPlayerMap[callsign] = mp;
|
mMultiPlayerMap[callsign] = mp;
|
||||||
|
|
||||||
FGAIManager *aiMgr = (FGAIManager*)globals->get_subsystem("ai_model");
|
FGAIManager *aiMgr = (FGAIManager*)globals->get_subsystem("ai-model");
|
||||||
if (aiMgr) {
|
if (aiMgr) {
|
||||||
aiMgr->attach(mp);
|
aiMgr->attach(mp);
|
||||||
|
|
||||||
|
|
|
@ -701,7 +701,7 @@ public:
|
||||||
if (modelPath.empty())
|
if (modelPath.empty())
|
||||||
return;
|
return;
|
||||||
FGAIManager *aiMgr;
|
FGAIManager *aiMgr;
|
||||||
aiMgr = static_cast<FGAIManager*>(globals->get_subsystem("ai_model"));
|
aiMgr = static_cast<FGAIManager*>(globals->get_subsystem("ai-model"));
|
||||||
if (!aiMgr)
|
if (!aiMgr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -39,19 +39,27 @@
|
||||||
#include <simgear/sound/soundmgr_openal.hxx>
|
#include <simgear/sound/soundmgr_openal.hxx>
|
||||||
#include <simgear/sound/xmlsound.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) ),
|
_enabled( fgGetNode("/sim/sound/effects/enabled", true) ),
|
||||||
_volume( fgGetNode("/sim/sound/effects/volume", 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) )
|
|
||||||
{
|
{
|
||||||
|
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::_smgr = smgr;
|
||||||
SGSampleGroup::_refname = refname;
|
SGSampleGroup::_refname = refname;
|
||||||
SGSampleGroup::_smgr->add(this, 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
|
void
|
||||||
FGFX::init()
|
FGFX::init()
|
||||||
{
|
{
|
||||||
SGPropertyNode *node = fgGetNode("/sim/sound", true);
|
SGPropertyNode *node = _props->getNode("sim/sound", true);
|
||||||
|
|
||||||
string path_str = node->getStringValue("path");
|
string path_str = node->getStringValue("path");
|
||||||
if (path_str.empty()) {
|
if (path_str.empty()) {
|
||||||
|
@ -121,14 +129,21 @@ FGFX::reinit()
|
||||||
void
|
void
|
||||||
FGFX::update (double dt)
|
FGFX::update (double dt)
|
||||||
{
|
{
|
||||||
bool active = _avionics_external->getBoolValue() ||
|
bool active = _avionics_ext->getBoolValue() ||
|
||||||
_internal->getBoolValue();
|
_internal->getBoolValue();
|
||||||
|
|
||||||
if ( active && _avionics_enabled->getBoolValue() )
|
if (_avionics_enabled->getBoolValue()) {
|
||||||
_avionics->resume(); // no-op if already in resumed state
|
if (!_avionics) {
|
||||||
else
|
_avionics = _smgr->find("avionics", true);
|
||||||
_avionics->suspend();
|
_avionics->tie_to_listener();
|
||||||
_avionics->set_volume( _avionics_volume->getFloatValue() );
|
}
|
||||||
|
|
||||||
|
if ( active )
|
||||||
|
_avionics->resume(); // no-op if already in resumed state
|
||||||
|
else
|
||||||
|
_avionics->suspend();
|
||||||
|
_avionics->set_volume( _avionics_volume->getFloatValue() );
|
||||||
|
}
|
||||||
|
|
||||||
if ( _enabled->getBoolValue() ) {
|
if ( _enabled->getBoolValue() ) {
|
||||||
set_volume( _volume->getDoubleValue() );
|
set_volume( _volume->getDoubleValue() );
|
||||||
|
|
|
@ -49,7 +49,7 @@ class FGFX : public SGSampleGroup
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
FGFX ( SGSoundMgr *smgr, const string &refname );
|
FGFX ( SGSoundMgr *smgr, const string &refname, SGPropertyNode *props = 0 );
|
||||||
virtual ~FGFX ();
|
virtual ~FGFX ();
|
||||||
|
|
||||||
virtual void init ();
|
virtual void init ();
|
||||||
|
@ -61,11 +61,12 @@ private:
|
||||||
SGSharedPtr<SGSampleGroup> _avionics;
|
SGSharedPtr<SGSampleGroup> _avionics;
|
||||||
std::vector<SGXmlSound *> _sound;
|
std::vector<SGXmlSound *> _sound;
|
||||||
|
|
||||||
|
SGPropertyNode_ptr _props;
|
||||||
SGPropertyNode_ptr _enabled;
|
SGPropertyNode_ptr _enabled;
|
||||||
SGPropertyNode_ptr _volume;
|
SGPropertyNode_ptr _volume;
|
||||||
SGPropertyNode_ptr _avionics_enabled;
|
SGPropertyNode_ptr _avionics_enabled;
|
||||||
SGPropertyNode_ptr _avionics_volume;
|
SGPropertyNode_ptr _avionics_volume;
|
||||||
SGPropertyNode_ptr _avionics_external;
|
SGPropertyNode_ptr _avionics_ext;
|
||||||
SGPropertyNode_ptr _internal;
|
SGPropertyNode_ptr _internal;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,12 @@ static bool do_timeofday (const SGPropertyNode * arg)
|
||||||
|
|
||||||
TimeManager::TimeManager() :
|
TimeManager::TimeManager() :
|
||||||
_inited(false),
|
_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);
|
SGCommandMgr::instance()->addCommand("timeofday", do_timeofday);
|
||||||
}
|
}
|
||||||
|
@ -102,6 +107,7 @@ void TimeManager::init()
|
||||||
// frame-rate / worst-case latency / update-rate counters
|
// frame-rate / worst-case latency / update-rate counters
|
||||||
_frameRate = fgGetNode("/sim/frame-rate", true);
|
_frameRate = fgGetNode("/sim/frame-rate", true);
|
||||||
_frameLatency = fgGetNode("/sim/frame-latency-max-ms", true);
|
_frameLatency = fgGetNode("/sim/frame-latency-max-ms", true);
|
||||||
|
_frameRateWorst = fgGetNode("/sim/frame-rate-worst", true);
|
||||||
_lastFrameTime = 0;
|
_lastFrameTime = 0;
|
||||||
_frameLatencyMax = 0.0;
|
_frameLatencyMax = 0.0;
|
||||||
_frameCount = 0;
|
_frameCount = 0;
|
||||||
|
@ -157,9 +163,7 @@ void TimeManager::computeTimeDeltas(double& simDt, double& realDt)
|
||||||
_lastClockFreeze = _clockFreeze->getBoolValue();
|
_lastClockFreeze = _clockFreeze->getBoolValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool scenery_loaded = fgGetBool("sim/sceneryloaded");
|
bool wait_for_scenery = !(_sceneryLoaded || _sceneryLoadOverride);
|
||||||
bool wait_for_scenery = !(scenery_loaded || fgGetBool("sim/sceneryloaded-override"));
|
|
||||||
|
|
||||||
if (!wait_for_scenery) {
|
if (!wait_for_scenery) {
|
||||||
throttleUpdateRate();
|
throttleUpdateRate();
|
||||||
}
|
}
|
||||||
|
@ -189,20 +193,18 @@ void TimeManager::computeTimeDeltas(double& simDt, double& realDt)
|
||||||
if (0 < dtMax && dtMax < dt) {
|
if (0 < dtMax && dtMax < dt) {
|
||||||
dt = dtMax;
|
dt = dtMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
int model_hz = fgGetInt("/sim/model-hz");
|
|
||||||
|
|
||||||
SGSubsystemGroup* fdmGroup =
|
SGSubsystemGroup* fdmGroup =
|
||||||
globals->get_subsystem_mgr()->get_group(SGSubsystemMgr::FDM);
|
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.
|
// round the real time down to a multiple of 1/model-hz.
|
||||||
// this way all systems are updated the _same_ amount of dt.
|
// this way all systems are updated the _same_ amount of dt.
|
||||||
dt += _dtRemainder;
|
dt += _dtRemainder;
|
||||||
int multiLoop = long(floor(dt * model_hz));
|
int multiLoop = long(floor(dt * _modelHz));
|
||||||
multiLoop = SGMisc<long>::max(0, multiLoop);
|
multiLoop = SGMisc<long>::max(0, multiLoop);
|
||||||
_dtRemainder = dt - double(multiLoop)/double(model_hz);
|
_dtRemainder = dt - double(multiLoop)/double(_modelHz);
|
||||||
dt = double(multiLoop)/double(model_hz);
|
dt = double(multiLoop)/double(_modelHz);
|
||||||
|
|
||||||
realDt = dt;
|
realDt = dt;
|
||||||
if (_clockFreeze->getBoolValue() || wait_for_scenery) {
|
if (_clockFreeze->getBoolValue() || wait_for_scenery) {
|
||||||
|
@ -215,8 +217,8 @@ void TimeManager::computeTimeDeltas(double& simDt, double& realDt)
|
||||||
globals->inc_sim_time_sec(simDt);
|
globals->inc_sim_time_sec(simDt);
|
||||||
|
|
||||||
// These are useful, especially for Nasal scripts.
|
// These are useful, especially for Nasal scripts.
|
||||||
fgSetDouble("/sim/time/delta-realtime-sec", realDt);
|
_timeDelta = realDt;
|
||||||
fgSetDouble("/sim/time/delta-sec", simDt);
|
_simTimeDelta = simDt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimeManager::update(double dt)
|
void TimeManager::update(double dt)
|
||||||
|
@ -267,6 +269,8 @@ void TimeManager::computeFrameRate()
|
||||||
if ((_impl->get_cur_time() != _lastFrameTime)) {
|
if ((_impl->get_cur_time() != _lastFrameTime)) {
|
||||||
_frameRate->setIntValue(_frameCount);
|
_frameRate->setIntValue(_frameCount);
|
||||||
_frameLatency->setDoubleValue(_frameLatencyMax*1000);
|
_frameLatency->setDoubleValue(_frameLatencyMax*1000);
|
||||||
|
if (_frameLatencyMax>0)
|
||||||
|
_frameRateWorst->setIntValue(1/_frameLatencyMax);
|
||||||
_frameCount = 0;
|
_frameCount = 0;
|
||||||
_frameLatencyMax = 0.0;
|
_frameLatencyMax = 0.0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
#include <simgear/structure/subsystem_mgr.hxx>
|
#include <simgear/structure/subsystem_mgr.hxx>
|
||||||
#include <simgear/props/props.hxx>
|
#include <simgear/props/props.hxx>
|
||||||
|
#include <simgear/props/propertyObject.hxx>
|
||||||
|
|
||||||
// forward decls
|
// forward decls
|
||||||
class SGTime;
|
class SGTime;
|
||||||
|
@ -82,10 +83,16 @@ private:
|
||||||
|
|
||||||
// frame-rate / worst-case latency / update-rate counters
|
// frame-rate / worst-case latency / update-rate counters
|
||||||
SGPropertyNode_ptr _frameRate;
|
SGPropertyNode_ptr _frameRate;
|
||||||
|
SGPropertyNode_ptr _frameRateWorst;
|
||||||
SGPropertyNode_ptr _frameLatency;
|
SGPropertyNode_ptr _frameLatency;
|
||||||
time_t _lastFrameTime;
|
time_t _lastFrameTime;
|
||||||
double _frameLatencyMax;
|
double _frameLatencyMax;
|
||||||
int _frameCount;
|
int _frameCount;
|
||||||
|
|
||||||
|
SGPropObjBool _sceneryLoaded,
|
||||||
|
_sceneryLoadOverride;
|
||||||
|
SGPropObjInt _modelHz;
|
||||||
|
SGPropObjDouble _timeDelta, _simTimeDelta;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // of FG_TIME_TIMEMANAGER_HXX
|
#endif // of FG_TIME_TIMEMANAGER_HXX
|
||||||
|
|
|
@ -228,7 +228,7 @@ bool FGAISchedule::update(time_t now, const SGVec3d& userCart)
|
||||||
|
|
||||||
if (AIManagerRef) {
|
if (AIManagerRef) {
|
||||||
// Check if this aircraft has been released.
|
// 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)) {
|
if (tmgr->isReleased(AIManagerRef)) {
|
||||||
AIManagerRef = 0;
|
AIManagerRef = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -347,7 +347,7 @@ bool FGAISchedule::createAIAircraft(FGScheduledFlight* flight, double speedKnots
|
||||||
airline);
|
airline);
|
||||||
if (fp->isValidPlan()) {
|
if (fp->isValidPlan()) {
|
||||||
aircraft->SetFlightPlan(fp);
|
aircraft->SetFlightPlan(fp);
|
||||||
FGAIManager* aimgr = (FGAIManager *) globals-> get_subsystem("ai_model");
|
FGAIManager* aimgr = (FGAIManager *) globals-> get_subsystem("ai-model");
|
||||||
aimgr->attach(aircraft);
|
aimgr->attach(aircraft);
|
||||||
AIManagerRef = aircraft->getID();
|
AIManagerRef = aircraft->getID();
|
||||||
return true;
|
return true;
|
||||||
|
@ -465,7 +465,7 @@ FGScheduledFlight* FGAISchedule::findAvailableFlight (const string ¤tDesti
|
||||||
{
|
{
|
||||||
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
|
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;
|
FGScheduledFlightVecIterator fltBegin, fltEnd;
|
||||||
fltBegin = tmgr->getFirstFlight(req);
|
fltBegin = tmgr->getFirstFlight(req);
|
||||||
fltEnd = tmgr->getLastFlight(req);
|
fltEnd = tmgr->getLastFlight(req);
|
||||||
|
|
|
@ -22,11 +22,16 @@
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <plib/fnt.h>
|
||||||
|
#include <plib/pu.h>
|
||||||
|
|
||||||
#include "ApplicationProperties.hxx"
|
#include "ApplicationProperties.hxx"
|
||||||
#include "FGFontCache.hxx"
|
#include "FGFontCache.hxx"
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
// FGFontCache class.
|
// FGFontCache class.
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -68,6 +73,14 @@ const GuiFont guifonts[] = {
|
||||||
const GuiFont* guifontsEnd = &guifonts[sizeof(guifonts)/ sizeof(guifonts[0])];
|
const GuiFont* guifontsEnd = &guifonts[sizeof(guifonts)/ sizeof(guifonts[0])];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FGFontCache::fnt::~fnt()
|
||||||
|
{
|
||||||
|
if (texfont) {
|
||||||
|
delete pufont;
|
||||||
|
delete texfont;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FGFontCache::FGFontCache() :
|
FGFontCache::FGFontCache() :
|
||||||
_initialized(false)
|
_initialized(false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,10 +14,16 @@
|
||||||
//
|
//
|
||||||
#ifndef __FGFONTCACHE_HXX
|
#ifndef __FGFONTCACHE_HXX
|
||||||
#define __FGFONTCACHE_HXX
|
#define __FGFONTCACHE_HXX
|
||||||
|
|
||||||
#include <simgear/math/SGMath.hxx>
|
#include <simgear/math/SGMath.hxx>
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
#include <simgear/props/props.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.
|
* A class to keep all fonts available for future use.
|
||||||
* This also assures a font isn't resident more than once.
|
* This also assures a font isn't resident more than once.
|
||||||
|
@ -47,7 +53,7 @@ private:
|
||||||
};
|
};
|
||||||
struct fnt {
|
struct fnt {
|
||||||
fnt(puFont *pu = 0) : pufont(pu), texfont(0) {}
|
fnt(puFont *pu = 0) : pufont(pu), texfont(0) {}
|
||||||
~fnt() { if (texfont) { delete pufont; delete texfont; } }
|
~fnt();
|
||||||
// Font used by plib GUI code
|
// Font used by plib GUI code
|
||||||
puFont *pufont;
|
puFont *pufont;
|
||||||
// TXF font
|
// TXF font
|
||||||
|
|
Loading…
Add table
Reference in a new issue