1
0
Fork 0

Canvas: First version of new Canvas GUI system.

- Refactor CanvasMgr into PropertyBasedMgr to be also used
   for the Canvas GUI system.
 - Get rid of tied properties in the Canvas system.
 - Add new placement type 'window' for placing canvases onto
   windows
 - Pass mouse events to Window class (only if cursor is over
   window)
 - Refactor canvas placement clean up
This commit is contained in:
Thomas Geymayer 2012-07-27 13:17:42 +02:00
parent 5f08e10c0a
commit 8a6a234653
25 changed files with 1477 additions and 464 deletions

View file

@ -8,7 +8,12 @@ set(SOURCES
elements/map.cxx
elements/path.cxx
elements/text.cxx
gui_mgr.cxx
placement.cxx
property_based_element.cxx
property_based_mgr.cxx
property_helper.cxx
window.cxx
)
set(HEADERS
@ -19,7 +24,12 @@ set(HEADERS
elements/map.hxx
elements/path.hxx
elements/text.hxx
gui_mgr.hxx
placement.hxx
property_based_element.hxx
property_based_mgr.hxx
property_helper.hxx
window.hxx
)
flightgear_component(Canvas "${SOURCES}" "${HEADERS}")

View file

@ -18,6 +18,7 @@
#include "canvas.hxx"
#include "elements/group.hxx"
#include "mouse_event.hxx"
#include <Canvas/property_helper.hxx>
#include <Main/globals.hxx>
@ -31,172 +32,95 @@
#include <osgText/Text>
#include <osgViewer/Viewer>
#include <boost/algorithm/string/predicate.hpp>
#include <iostream>
//------------------------------------------------------------------------------
/**
* Callback used to disable/enable rendering to the texture if it is not
* visible
*/
class CameraCullCallback:
public osg::NodeCallback
//----------------------------------------------------------------------------
Canvas::CameraCullCallback::CameraCullCallback():
_render( true ),
_render_frame( 0 )
{
public:
CameraCullCallback():
_render( true ),
_render_frame( 0 )
{}
}
/**
* Enable rendering for the next frame
*/
void enableRendering()
{
_render = true;
}
private:
bool _render;
unsigned int _render_frame;
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if( !_render && nv->getTraversalNumber() != _render_frame )
return;
traverse(node, nv);
_render = false;
_render_frame = nv->getTraversalNumber();
}
};
/**
* This callback is installed on every placement of the canvas in the scene to
* only render the canvas if at least one placement is visible
*/
class PlacementCullCallback:
public osg::NodeCallback
//----------------------------------------------------------------------------
void Canvas::CameraCullCallback::enableRendering()
{
public:
_render = true;
}
PlacementCullCallback(Canvas* canvas, CameraCullCallback* camera_cull):
_canvas( canvas ),
_camera_cull( camera_cull )
{}
//----------------------------------------------------------------------------
void Canvas::CameraCullCallback::operator()( osg::Node* node,
osg::NodeVisitor* nv )
{
if( !_render && nv->getTraversalNumber() != _render_frame )
return;
private:
traverse(node, nv);
Canvas *_canvas;
CameraCullCallback *_camera_cull;
_render = false;
_render_frame = nv->getTraversalNumber();
}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if( nv->getTraversalMask() & simgear::MODEL_BIT )
_camera_cull->enableRendering();
//----------------------------------------------------------------------------
Canvas::CullCallback::CullCallback(CameraCullCallback* camera_cull):
_camera_cull( camera_cull )
{
traverse(node, nv);
}
};
}
//----------------------------------------------------------------------------
void Canvas::CullCallback::operator()( osg::Node* node,
osg::NodeVisitor* nv )
{
if( nv->getTraversalMask() & simgear::MODEL_BIT )
_camera_cull->enableRendering();
traverse(node, nv);
}
//------------------------------------------------------------------------------
Canvas::Canvas():
Canvas::Canvas(SGPropertyNode* node):
PropertyBasedElement(node),
_size_x(-1),
_size_y(-1),
_view_width(-1),
_view_height(-1),
_status(0),
_status(node, "status"),
_status_msg(node, "status-msg"),
_mouse_x(node, "mouse/x"),
_mouse_y(node, "mouse/y"),
_mouse_dx(node, "mouse/dx"),
_mouse_dy(node, "mouse/dy"),
_mouse_button(node, "mouse/button"),
_mouse_state(node, "mouse/state"),
_mouse_mod(node, "mouse/mod"),
_mouse_scroll(node, "mouse/scroll"),
_mouse_event(node, "mouse/event"),
_sampling_dirty(false),
_color_dirty(true),
_node(0),
_root_group( new canvas::Group(node) ),
_render_always(false)
{
_status = 0;
setStatusFlags(MISSING_SIZE_X | MISSING_SIZE_Y);
_camera_callback = new CameraCullCallback;
_cull_callback = new PlacementCullCallback(this, _camera_callback);
_cull_callback = new CullCallback(_camera_callback);
canvas::linkColorNodes
(
"color-background",
_node,
_color_background,
osg::Vec4f(0,0,0,1)
);
}
//------------------------------------------------------------------------------
Canvas::~Canvas()
{
clearPlacements();
unbind();
_node = 0;
}
//------------------------------------------------------------------------------
int Canvas::getStatus() const
{
return _status;
}
//------------------------------------------------------------------------------
void Canvas::reset(SGPropertyNode* node)
{
if( node )
SG_LOG
(
SG_GL,
SG_INFO,
"Canvas::reset() texture[" << node->getIndex() << "]"
);
unbind();
_node = node;
setStatusFlags(MISSING_SIZE_X | MISSING_SIZE_Y);
if( _node )
{
_root_group.reset( new canvas::Group(_node) );
_node->tie
(
"size[0]",
SGRawValueMethods<Canvas, int>( *this, &Canvas::getSizeX,
&Canvas::setSizeX )
);
_node->tie
(
"size[1]",
SGRawValueMethods<Canvas, int>( *this, &Canvas::getSizeY,
&Canvas::setSizeY )
);
_node->tie
(
"view[0]",
SGRawValueMethods<Canvas, int>( *this, &Canvas::getViewWidth,
&Canvas::setViewWidth )
);
_node->tie
(
"view[1]",
SGRawValueMethods<Canvas, int>( *this, &Canvas::getViewHeight,
&Canvas::setViewHeight )
);
_node->tie
(
"status",
SGRawValueMethods<Canvas, int>(*this, &Canvas::getStatus)
);
_node->tie
(
"status-msg",
SGRawValueMethods<Canvas, const char*>(*this, &Canvas::getStatusMsg)
);
_node->addChangeListener(this);
canvas::linkColorNodes
(
"color-background",
_node,
_color_background,
osg::Vec4f(0,0,0,1)
);
}
}
//------------------------------------------------------------------------------
@ -257,15 +181,29 @@ void Canvas::update(double delta_time_sec)
// New placement
_placements.resize(node->getIndex() + 1);
else
// Remove maybe already existing placements
clearPlacements(node->getIndex());
// Remove possibly existing placements
_placements[ node->getIndex() ].clear();
// add new placements
_placements[node->getIndex()] = _texture.set_texture(
node,
_texture.getTexture(),
_cull_callback
);
// Get new placements
PlacementFactoryMap::const_iterator placement_factory =
_placement_factories.find( node->getStringValue("type", "object") );
if( placement_factory != _placement_factories.end() )
{
canvas::Placements& placements =
_placements[ node->getIndex() ] =
placement_factory->second
(
node,
boost::shared_static_cast<Canvas>(_self.lock())
);
node->setStringValue
(
"status-msg",
placements.empty() ? "No match" : "Ok"
);
}
else
node->setStringValue("status-msg", "Unknown placement type");
}
if( _render_always )
@ -290,12 +228,6 @@ void Canvas::setSizeX(int sx)
setStatusFlags(CREATE_FAILED, false);
}
//------------------------------------------------------------------------------
int Canvas::getSizeX() const
{
return _size_x;
}
//------------------------------------------------------------------------------
void Canvas::setSizeY(int sy)
{
@ -314,12 +246,6 @@ void Canvas::setSizeY(int sy)
setStatusFlags(CREATE_FAILED, false);
}
//------------------------------------------------------------------------------
int Canvas::getSizeY() const
{
return _size_y;
}
//------------------------------------------------------------------------------
void Canvas::setViewWidth(int w)
{
@ -330,12 +256,6 @@ void Canvas::setViewWidth(int w)
_texture.setViewSize(_view_width, _view_height);
}
//------------------------------------------------------------------------------
int Canvas::getViewWidth() const
{
return _view_width;
}
//------------------------------------------------------------------------------
void Canvas::setViewHeight(int h)
{
@ -347,15 +267,19 @@ void Canvas::setViewHeight(int h)
}
//------------------------------------------------------------------------------
int Canvas::getViewHeight() const
bool Canvas::handleMouseEvent(const canvas::MouseEvent& event)
{
return _view_height;
}
//------------------------------------------------------------------------------
const char* Canvas::getStatusMsg() const
{
return _status_msg.c_str();
_mouse_x = event.x;
_mouse_y = event.y;
_mouse_dx = event.dx;
_mouse_dy = event.dy;
_mouse_button = event.button;
_mouse_state = event.state;
_mouse_mod = event.mod;
_mouse_scroll = event.scroll;
// Always set event type last because all listeners are attached to it
_mouse_event = event.type;
return true;
}
//------------------------------------------------------------------------------
@ -380,7 +304,7 @@ void Canvas::childRemoved( SGPropertyNode * parent,
return;
if( child->getNameString() == "placement" )
clearPlacements(child->getIndex());
_placements[ child->getIndex() ].clear();
else
static_cast<canvas::Element*>(_root_group.get())
->childRemoved(parent, child);
@ -389,6 +313,9 @@ void Canvas::childRemoved( SGPropertyNode * parent,
//----------------------------------------------------------------------------
void Canvas::valueChanged(SGPropertyNode* node)
{
if( boost::starts_with(node->getNameString(), "status") )
return;
if( node->getParent()->getParent() == _node )
{
if( !_color_background.empty()
@ -416,11 +343,31 @@ void Canvas::valueChanged(SGPropertyNode* node)
_sampling_dirty = true;
else if( node->getNameString() == "render-always" )
_render_always = node->getBoolValue();
else if( node->getNameString() == "size" )
{
if( node->getIndex() == 0 )
setSizeX( node->getIntValue() );
else if( node->getIndex() == 1 )
setSizeY( node->getIntValue() );
}
else if( node->getNameString() == "view" )
{
if( node->getIndex() == 0 )
setViewWidth( node->getIntValue() );
else if( node->getIndex() == 1 )
setViewHeight( node->getIntValue() );
}
}
_root_group->valueChanged(node);
}
//------------------------------------------------------------------------------
osg::Texture2D* Canvas::getTexture() const
{
return _texture.getTexture();
}
//------------------------------------------------------------------------------
GLuint Canvas::getTexId() const
{
@ -449,13 +396,41 @@ GLuint Canvas::getTexId() const
return tobj->_id;
}
//------------------------------------------------------------------------------
Canvas::CameraCullCallbackPtr Canvas::getCameraCullCallback() const
{
return _camera_callback;
}
//----------------------------------------------------------------------------
Canvas::CullCallbackPtr Canvas::getCullCallback() const
{
return _cull_callback;
}
//------------------------------------------------------------------------------
void Canvas::addPlacementFactory( const std::string& type,
canvas::PlacementFactory factory )
{
if( _placement_factories.find(type) != _placement_factories.end() )
SG_LOG
(
SG_GENERAL,
SG_WARN,
"Canvas::addPlacementFactory: replace existing factor for type " << type
);
_placement_factories[type] = factory;
}
//------------------------------------------------------------------------------
void Canvas::setStatusFlags(unsigned int flags, bool set)
{
if( set )
_status |= flags;
_status = _status | flags;
else
_status &= ~flags;
_status = _status & ~flags;
// TODO maybe extend simgear::PropertyObject to allow |=, &= etc.
if( (_status & MISSING_SIZE_X) && (_status & MISSING_SIZE_Y) )
_status_msg = "Missing size";
@ -472,47 +447,4 @@ void Canvas::setStatusFlags(unsigned int flags, bool set)
}
//------------------------------------------------------------------------------
void Canvas::clearPlacements(int index)
{
Placements& placements = _placements.at(index);
while( !placements.empty() )
{
osg::ref_ptr<osg::Group> group = placements.back();
placements.pop_back();
assert( group->getNumChildren() == 1 );
osg::Node *child = group->getChild(0);
if( group->getNumParents() )
{
osg::Group *parent = group->getParent(0);
parent->addChild(child);
parent->removeChild(group);
}
group->removeChild(child);
}
}
//------------------------------------------------------------------------------
void Canvas::clearPlacements()
{
for(size_t i = 0; i < _placements.size(); ++i)
clearPlacements(i);
_placements.clear();
}
//------------------------------------------------------------------------------
void Canvas::unbind()
{
if( !_node )
return;
_node->untie("size[0]");
_node->untie("size[1]");
_node->untie("view[0]");
_node->untie("view[1]");
_node->untie("status");
_node->untie("status-msg");
_node->removeChangeListener(this);
}
Canvas::PlacementFactoryMap Canvas::_placement_factories;

View file

@ -19,21 +19,20 @@
#ifndef CANVAS_HXX_
#define CANVAS_HXX_
#include "placement.hxx"
#include "property_based_element.hxx"
#include <Canvas/canvas_fwd.hpp>
#include <Instrumentation/od_gauge.hxx>
#include <simgear/props/props.hxx>
#include <simgear/props/propertyObject.hxx>
#include <osg/NodeCallback>
#include <memory>
#include <string>
namespace canvas
{
class Group;
}
class CameraCullCallback;
class Canvas:
public SGPropertyChangeListener
public PropertyBasedElement
{
public:
@ -45,26 +44,58 @@ class Canvas:
CREATE_FAILED = 0x0004
};
Canvas();
/**
* Callback used to disable/enable rendering to the texture if it is not
* visible
*/
class CameraCullCallback:
public osg::NodeCallback
{
public:
CameraCullCallback();
/**
* Enable rendering for the next frame
*/
void enableRendering();
private:
bool _render;
unsigned int _render_frame;
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
};
typedef osg::ref_ptr<CameraCullCallback> CameraCullCallbackPtr;
/**
* This callback is installed on every placement of the canvas in the
* scene to only render the canvas if at least one placement is visible
*/
class CullCallback:
public osg::NodeCallback
{
public:
CullCallback(CameraCullCallback* camera_cull);
private:
CameraCullCallback *_camera_cull;
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
};
typedef osg::ref_ptr<CullCallback> CullCallbackPtr;
Canvas(SGPropertyNode* node);
virtual ~Canvas();
void reset(SGPropertyNode* node);
void update(double delta_time_sec);
void setSizeX(int sx);
int getSizeX() const;
void setSizeY(int sy);
int getSizeY() const;
void setViewWidth(int w);
int getViewWidth() const;
void setViewHeight(int h);
int getViewHeight() const;
int getStatus() const;
const char* getStatusMsg() const;
bool handleMouseEvent(const canvas::MouseEvent& event);
virtual void childAdded( SGPropertyNode * parent,
SGPropertyNode * child );
@ -72,8 +103,15 @@ class Canvas:
SGPropertyNode * child );
virtual void valueChanged (SGPropertyNode * node);
osg::Texture2D* getTexture() const;
GLuint getTexId() const;
CameraCullCallbackPtr getCameraCullCallback() const;
CullCallbackPtr getCullCallback() const;
static void addPlacementFactory( const std::string& type,
canvas::PlacementFactory factory );
private:
Canvas(const Canvas&); // = delete;
@ -84,8 +122,16 @@ class Canvas:
_view_width,
_view_height;
int _status;
std::string _status_msg;
simgear::PropertyObject<int> _status;
simgear::PropertyObject<std::string> _status_msg;
simgear::PropertyObject<int> _mouse_x, _mouse_y,
_mouse_dx, _mouse_dy,
_mouse_button,
_mouse_state,
_mouse_mod,
_mouse_scroll,
_mouse_event;
bool _sampling_dirty,
_color_dirty;
@ -93,22 +139,19 @@ class Canvas:
FGODGauge _texture;
std::auto_ptr<canvas::Group> _root_group;
SGPropertyNode_ptr _node;
std::vector<SGPropertyNode_ptr> _color_background;
osg::ref_ptr<CameraCullCallback> _camera_callback;
osg::ref_ptr<osg::NodeCallback> _cull_callback;
CameraCullCallbackPtr _camera_callback;
CullCallbackPtr _cull_callback;
bool _render_always; //<! Used to disable automatic lazy rendering (culling)
std::vector<SGPropertyNode*> _dirty_placements;
std::vector<Placements> _placements;
std::vector<canvas::Placements> _placements;
typedef std::map<std::string, canvas::PlacementFactory> PlacementFactoryMap;
static PlacementFactoryMap _placement_factories;
void setStatusFlags(unsigned int flags, bool set = true);
void clearPlacements(int index);
void clearPlacements();
void unbind();
};
#endif /* CANVAS_HXX_ */

53
src/Canvas/canvas_fwd.hpp Normal file
View file

@ -0,0 +1,53 @@
// Canvas forward declarations
//
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
//
// 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 CANVAS_FWD_HPP_
#define CANVAS_FWD_HPP_
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <vector>
class SGPropertyNode;
class Canvas;
typedef boost::shared_ptr<Canvas> CanvasPtr;
typedef boost::weak_ptr<Canvas> CanvasWeakPtr;
class PropertyBasedElement;
typedef boost::shared_ptr<PropertyBasedElement> PropertyBasedElementPtr;
typedef boost::weak_ptr<PropertyBasedElement> PropertyBasedElementWeakPtr;
namespace canvas
{
class Group;
class MouseEvent;
class Placement;
typedef boost::shared_ptr<Placement> PlacementPtr;
typedef std::vector<PlacementPtr> Placements;
typedef boost::function<Placements( const SGPropertyNode*,
CanvasPtr )> PlacementFactory;
class Window;
typedef boost::shared_ptr<Window> WindowPtr;
typedef boost::weak_ptr<Window> WindowWeakPtr;
}
#endif /* CANVAS_FWD_HPP_ */

View file

@ -19,131 +19,38 @@
#include "canvas_mgr.hxx"
#include "canvas.hxx"
#include <Main/fg_props.hxx>
#include <boost/bind.hpp>
#include <osg/Camera>
#include <osg/Texture2D>
typedef boost::shared_ptr<Canvas> CanvasPtr;
CanvasPtr canvasFactory(SGPropertyNode* node)
{
return CanvasPtr(new Canvas(node));
}
#include <stdexcept>
#include <string>
//------------------------------------------------------------------------------
CanvasMgr::CanvasMgr():
_props( fgGetNode("/canvas", true) )
PropertyBasedMgr("/canvas", "texture", &canvasFactory)
{
}
//------------------------------------------------------------------------------
CanvasMgr::~CanvasMgr()
{
}
//------------------------------------------------------------------------------
void CanvasMgr::init()
{
_props->addChangeListener(this);
triggerChangeRecursive(_props);
}
//------------------------------------------------------------------------------
void CanvasMgr::reinit()
{
}
//------------------------------------------------------------------------------
void CanvasMgr::shutdown()
{
_props->removeChangeListener(this);
}
//------------------------------------------------------------------------------
void CanvasMgr::bind()
{
}
//------------------------------------------------------------------------------
void CanvasMgr::unbind()
{
}
//------------------------------------------------------------------------------
void CanvasMgr::update(double delta_time_sec)
{
for( size_t i = 0; i < _canvases.size(); ++i )
if( _canvases[i] )
_canvases[i]->update(delta_time_sec);
}
//------------------------------------------------------------------------------
void CanvasMgr::childAdded( SGPropertyNode * parent,
SGPropertyNode * child )
{
if( parent != _props )
return;
if( child->getNameString() == "texture" )
textureAdded(child);
}
//------------------------------------------------------------------------------
void CanvasMgr::childRemoved( SGPropertyNode * parent,
SGPropertyNode * child )
{
if( parent != _props )
return;
if( child->getNameString() == "texture" )
{
size_t index = child->getIndex();
if( index >= _canvases.size() )
SG_LOG(SG_GL, SG_WARN, "can't removed unknown texture[" << index << "]!");
else
// remove the canvas...
_canvases[index].reset();
}
Canvas::addPlacementFactory
(
"object",
boost::bind
(
&FGODGauge::set_texture,
_1,
boost::bind(&Canvas::getTexture, _2),
boost::bind(&Canvas::getCullCallback, _2)
)
);
}
//------------------------------------------------------------------------------
unsigned int CanvasMgr::getCanvasTexId(size_t index) const
{
if( index >= _canvases.size()
|| !_canvases[index] )
if( index >= _elements.size()
|| !_elements[index] )
return 0;
return _canvases[index]->getTexId();
}
//------------------------------------------------------------------------------
void CanvasMgr::textureAdded(SGPropertyNode* node)
{
size_t index = node->getIndex();
if( index >= _canvases.size() )
{
if( index > _canvases.size() )
SG_LOG(SG_GL, SG_WARN, "Skipping unused texture slot(s)!");
_canvases.resize(index + 1);
}
else if( _canvases[index] )
SG_LOG(SG_GL, SG_WARN, "texture[" << index << "] already exists!");
_canvases[index].reset( new Canvas() );
_canvases[index]->reset(node);
}
//------------------------------------------------------------------------------
void CanvasMgr::triggerChangeRecursive(SGPropertyNode* node)
{
node->getParent()->fireChildAdded(node);
if( node->nChildren() == 0 && node->getType() != simgear::props::NONE )
return node->fireValueChanged();
for( int i = 0; i < node->nChildren(); ++i )
triggerChangeRecursive( node->getChild(i) );
return static_cast<Canvas*>(_elements[index].get())->getTexId();
}

View file

@ -19,36 +19,13 @@
#ifndef CANVAS_MGR_H_
#define CANVAS_MGR_H_
#include <simgear/props/props.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include <boost/shared_ptr.hpp>
#include <vector>
class Canvas;
typedef boost::shared_ptr<Canvas> CanvasPtr;
#include "property_based_mgr.hxx"
class CanvasMgr:
public SGSubsystem,
public SGPropertyChangeListener
public PropertyBasedMgr
{
public:
CanvasMgr();
virtual ~CanvasMgr();
virtual void init();
virtual void reinit();
virtual void shutdown();
virtual void bind();
virtual void unbind();
virtual void update(double delta_time_sec);
virtual void childAdded( SGPropertyNode * parent,
SGPropertyNode * child );
virtual void childRemoved( SGPropertyNode * parent,
SGPropertyNode * child );
/**
* Get OpenGL texture name for given canvas
@ -57,23 +34,6 @@ class CanvasMgr:
* @return OpenGL texture name
*/
unsigned int getCanvasTexId(size_t index) const;
private:
/** Root node for everything concerning the canvas system */
SGPropertyNode_ptr _props;
/** The actual canvases */
std::vector<CanvasPtr> _canvases;
void textureAdded(SGPropertyNode* node);
/**
* Trigger a childAdded and valueChanged event for every child of node
* (Unlimited depth) and node itself.
*/
void triggerChangeRecursive(SGPropertyNode* node);
};
#endif /* CANVAS_MGR_H_ */

View file

@ -126,54 +126,12 @@ namespace canvas
_font_size = getChildDefault<float>(_node, "character-size", 32);
_font_aspect = getChildDefault<float>(_node, "character-aspect-ratio", 1);
_node->tie
(
"alignment",
SGRawValueMethods<Text, const char*>
(
*this,
&Text::getAlignment,
&Text::setAlignment
)
);
_node->tie
(
"padding",
SGRawValueMethods<osgText::Text, float>
(
*_text.get(),
&osgText::Text::getBoundingBoxMargin,
&osgText::Text::setBoundingBoxMargin
)
);
typedef SGRawValueMethods<osgText::Text, int> TextIntMethods;
_node->tie
(
"draw-mode",
// TEXT = 1 default
// BOUNDINGBOX = 2
// FILLEDBOUNDINGBOX = 4
// ALIGNMENT = 8
TextIntMethods
(
*_text.get(),
(TextIntMethods::getter_t)&osgText::Text::getDrawMode,
(TextIntMethods::setter_t)&osgText::Text::setDrawMode
)
);
}
//----------------------------------------------------------------------------
Text::~Text()
{
if( _node )
{
_node->untie("alignment");
_node->untie("padding");
_node->untie("draw-mode");
}
_node = 0;
}
//----------------------------------------------------------------------------
@ -210,10 +168,20 @@ namespace canvas
#include "text-alignment.hxx"
#undef ENUM_MAPPING
else
{
if( !align_string.empty() )
SG_LOG
(
SG_GENERAL,
SG_WARN,
"canvas::Text: unknown alignment '" << align_string << "'"
);
_text->setAlignment(osgText::Text::LEFT_BASE_LINE);
}
}
//----------------------------------------------------------------------------
#if 0
const char* Text::getAlignment() const
{
switch( _text->getAlignment() )
@ -227,7 +195,7 @@ namespace canvas
return "unknown";
}
}
#endif
//----------------------------------------------------------------------------
void Text::childChanged(SGPropertyNode* child)
{
@ -247,10 +215,20 @@ namespace canvas
osgText::String( child->getStringValue(),
osgText::String::ENCODING_UTF8 )
);
else if( name == "padding" )
_text->setBoundingBoxMargin( child->getFloatValue() );
else if( name == "draw-mode" )
// TEXT = 1 default
// BOUNDINGBOX = 2
// FILLEDBOUNDINGBOX = 4
// ALIGNMENT = 8
_text->setDrawMode( child->getIntValue() );
else if( name == "max-width" )
_text->setMaximumWidth( child->getFloatValue() );
else if( name == "font" )
setFont( child->getStringValue() );
else if( name == "alignment" )
setAlignment( child->getStringValue() );
}
//----------------------------------------------------------------------------

View file

@ -33,14 +33,12 @@ namespace canvas
{
public:
Text(SGPropertyNode_ptr node);
virtual ~Text();
~Text();
virtual void update(double dt);
void setFont(const char* name);
void setAlignment(const char* align);
const char* getAlignment() const;
protected:

297
src/Canvas/gui_mgr.cxx Normal file
View file

@ -0,0 +1,297 @@
// Canvas gui/dialog manager
//
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
//
// 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.
#include "gui_mgr.hxx"
#include "mouse_event.hxx"
#include <Canvas/window.hxx>
#include <Canvas/canvas.hxx>
#include <Main/globals.hxx>
#include <Viewer/CameraGroup.hxx>
#include <Viewer/renderer.hxx>
#include <osgViewer/Viewer>
#include <osgGA/GUIEventHandler>
#include <boost/bind.hpp>
/**
* Event handler
*/
class GUIEventHandler:
public osgGA::GUIEventHandler
{
public:
GUIEventHandler(GUIMgr* gui_mgr):
_gui_mgr( gui_mgr )
{}
bool handle( const osgGA::GUIEventAdapter& ea,
osgGA::GUIActionAdapter& aa,
osg::Object*,
osg::NodeVisitor* )
{
return _gui_mgr->handleEvent(ea);
}
protected:
GUIMgr *_gui_mgr;
};
/**
* Track a canvas placement on a window
*/
class WindowPlacement:
public canvas::Placement
{
public:
WindowPlacement( canvas::WindowPtr window,
CanvasPtr canvas ):
_window(window),
_canvas(canvas)
{}
/**
* Remove placement from window
*/
virtual ~WindowPlacement()
{
canvas::WindowPtr window = _window.lock();
CanvasPtr canvas = _canvas.lock();
if( window && canvas && canvas == window->getCanvas().lock() )
window->setCanvas( CanvasPtr() );
}
private:
canvas::WindowWeakPtr _window;
CanvasWeakPtr _canvas;
};
//------------------------------------------------------------------------------
typedef boost::shared_ptr<canvas::Window> WindowPtr;
WindowPtr windowFactory(SGPropertyNode* node)
{
return WindowPtr(new canvas::Window(node));
}
//------------------------------------------------------------------------------
GUIMgr::GUIMgr():
PropertyBasedMgr("/sim/gui/canvas", "window", &windowFactory),
_event_handler( new GUIEventHandler(this) ),
_transform( new osg::MatrixTransform ),
_geode_windows( new osg::Geode ),
_width(_props, "size[0]"),
_height(_props, "size[1]"),
_last_push(-1)
{
_width = _height = -1;
osg::Camera* camera =
flightgear::getGUICamera( flightgear::CameraGroup::getDefault() );
assert(camera);
osg::Viewport* vp = camera->getViewport();
handleResize(vp->x(), vp->y(), vp->width(), vp->height());
_transform->addChild(_geode_windows);
camera->addChild(_transform);
Canvas::addPlacementFactory
(
"window",
boost::bind(&GUIMgr::addPlacement, this, _1, _2)
);
}
//------------------------------------------------------------------------------
void GUIMgr::init()
{
PropertyBasedMgr::init();
globals->get_renderer()
->getViewer()
->addEventHandler( _event_handler );
}
//------------------------------------------------------------------------------
void GUIMgr::shutdown()
{
PropertyBasedMgr::shutdown();
globals->get_renderer()
->getViewer()
->removeEventHandler( _event_handler );
}
//------------------------------------------------------------------------------
void GUIMgr::elementCreated(PropertyBasedElementPtr element)
{
_geode_windows->addDrawable
(
static_cast<canvas::Window*>(element.get())->getDrawable()
);
}
//------------------------------------------------------------------------------
bool GUIMgr::handleEvent(const osgGA::GUIEventAdapter& ea)
{
switch( ea.getEventType() )
{
case osgGA::GUIEventAdapter::PUSH:
case osgGA::GUIEventAdapter::RELEASE:
// case osgGA::GUIEventAdapter::DOUBLECLICK:
// // DOUBLECLICK doesn't seem to be triggered...
case osgGA::GUIEventAdapter::DRAG:
case osgGA::GUIEventAdapter::MOVE:
case osgGA::GUIEventAdapter::SCROLL:
return handleMouse(ea);
// case osgGA::GUIEventAdapter::MOVE:
// std::cout << "MOVE" << std::endl;
// break;
case osgGA::GUIEventAdapter::RESIZE:
handleResize( ea.getWindowX(),
ea.getWindowY(),
ea.getWindowWidth(),
ea.getWindowHeight() );
return true;
default:
return false;
}
}
//------------------------------------------------------------------------------
canvas::WindowPtr GUIMgr::getWindow(size_t i)
{
return boost::shared_static_cast<canvas::Window>(_elements[i]);
}
//------------------------------------------------------------------------------
canvas::Placements GUIMgr::addPlacement( const SGPropertyNode* node,
CanvasPtr canvas )
{
int placement_index = node->getIntValue("index", -1);
canvas::Placements placements;
for( size_t i = 0; i < _elements.size(); ++i )
{
if( placement_index > 0 && static_cast<int>(i) != placement_index )
continue;
canvas::WindowPtr window = getWindow(i);
if( !window )
continue;
window->setCanvas(canvas);
placements.push_back(
canvas::PlacementPtr(new WindowPlacement(window, canvas))
);
}
return placements;
}
//------------------------------------------------------------------------------
bool GUIMgr::handleMouse(const osgGA::GUIEventAdapter& ea)
{
canvas::MouseEvent event( ea.getEventType() );
event.x = 0.5 * (ea.getXnormalized() + 1) * _width + 0.5;
event.y = 0.5 * (ea.getYnormalized() + 1) * _height + 0.5;
if( ea.getMouseYOrientation()
!= osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS )
event.y = _height - event.y;
event.button = ea.getButton();
event.state = ea.getButtonMask();
event.mod = ea.getModKeyMask();
event.scroll = ea.getScrollingMotion();
int window_at_cursor = -1;
for( size_t i = 0; i < _elements.size(); ++i )
{
if( _elements[i]
&& getWindow(i)->getRegion().contains(event.x, event.y) )
{
window_at_cursor = i;
break;
}
}
int target_window = window_at_cursor;
switch( ea.getEventType() )
{
case osgGA::GUIEventAdapter::PUSH:
_last_push = window_at_cursor;
break;
case osgGA::GUIEventAdapter::SCROLL:
case osgGA::GUIEventAdapter::MOVE:
break;
case osgGA::GUIEventAdapter::RELEASE:
if( _last_push < 0 )
return false;
target_window = _last_push;
_last_push = -1;
break;
case osgGA::GUIEventAdapter::DRAG:
target_window = _last_push;
break;
default:
return false;
}
if( target_window >= 0 )
{
canvas::WindowPtr window = getWindow(target_window);
event.dx = event.x - _last_x;
event.dy = event.y - _last_y;
_last_x = event.x;
_last_y = event.y;
// Let the event position be always relative to the top left window corner
event.x -= window->getRegion().x();
event.y -= window->getRegion().y();
return window->handleMouseEvent(event);
}
else
return false;
}
//------------------------------------------------------------------------------
void GUIMgr::handleResize(int x, int y, int width, int height)
{
if( _width == width && _height == height )
return;
_width = width;
_height = height;
// Origin should be at top left corner, therefore we need to mirror the y-axis
_transform->setMatrix(osg::Matrix(
1, 0, 0, 0,
0, -1, 0, 0,
0, 0, 1, 0,
0, _height, 0, 1
));
}

71
src/Canvas/gui_mgr.hxx Normal file
View file

@ -0,0 +1,71 @@
// Canvas gui/dialog manager
//
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
//
// 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 CANVAS_GUI_MGR_HXX_
#define CANVAS_GUI_MGR_HXX_
#include "property_based_mgr.hxx"
#include <Canvas/canvas_fwd.hpp>
#include <Canvas/placement.hxx>
#include <simgear/props/propertyObject.hxx>
#include <osg/ref_ptr>
#include <osg/Geode>
#include <osg/MatrixTransform>
namespace osgGA
{
class GUIEventAdapter;
}
class GUIEventHandler;
class GUIMgr:
public PropertyBasedMgr
{
public:
GUIMgr();
virtual void init();
virtual void shutdown();
virtual void elementCreated(PropertyBasedElementPtr element);
bool handleEvent(const osgGA::GUIEventAdapter& ea);
protected:
osg::ref_ptr<GUIEventHandler> _event_handler;
osg::ref_ptr<osg::MatrixTransform> _transform;
osg::ref_ptr<osg::Geode> _geode_windows;
simgear::PropertyObject<int> _width,
_height;
int _last_push,
_last_x,
_last_y;
canvas::WindowPtr getWindow(size_t i);
canvas::Placements addPlacement( const SGPropertyNode*,
CanvasPtr canvas );
bool handleMouse(const osgGA::GUIEventAdapter& ea);
void handleResize(int x, int y, int width, int height);
};
#endif /* CANVAS_GUI_MGR_HXX_ */

View file

@ -0,0 +1,52 @@
// Mouse event
//
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
//
// 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 CANVAS_MOUSE_EVENT_HXX_
#define CANVAS_MOUSE_EVENT_HXX_
#include <osgGA/GUIEventAdapter>
namespace canvas
{
struct MouseEvent
{
typedef osgGA::GUIEventAdapter::EventType EventType;
typedef osgGA::GUIEventAdapter::ScrollingMotion Scroll;
MouseEvent(EventType type):
type(type),
x(-1), y(-1),
dx(0), dy(0),
button(-1),
state(-1),
mod(-1)
{}
EventType type;
int x, y,
dx, dy,
button, //<! Button for this event
state, //<! Current button state
mod; //<! Keyboard modifier state
Scroll scroll;
};
} // namespace canvas
#endif /* CANVAS_MOUSE_EVENT_HXX_ */

36
src/Canvas/placement.cxx Normal file
View file

@ -0,0 +1,36 @@
// Base class for canvas placements
//
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
//
// 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.
#include "placement.hxx"
namespace canvas
{
//----------------------------------------------------------------------------
Placement::Placement()
{
}
//----------------------------------------------------------------------------
Placement::~Placement()
{
}
} // namespace canvas

38
src/Canvas/placement.hxx Normal file
View file

@ -0,0 +1,38 @@
// Base class for canvas placements
//
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
//
// 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 CANVAS_PLACEMENT_HXX_
#define CANVAS_PLACEMENT_HXX_
namespace canvas
{
class Placement
{
public:
Placement();
virtual ~Placement() = 0;
private:
Placement(const Placement&) /* = delete */;
Placement& operator=(const Placement&) /* = delete */;
};
} // namespace canvas
#endif /* CANVAS_PLACEMENT_HXX_ */

View file

@ -0,0 +1,32 @@
// Base class for elements of property controlled subsystems
//
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
//
// 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.
#include "property_based_element.hxx"
//------------------------------------------------------------------------------
PropertyBasedElement::PropertyBasedElement(SGPropertyNode* node):
_node(node)
{
_node->addChangeListener(this);
}
//------------------------------------------------------------------------------
PropertyBasedElement::~PropertyBasedElement()
{
_node->removeChangeListener(this);
}

View file

@ -0,0 +1,46 @@
// Base class for elements of property controlled subsystems
//
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
//
// 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 PROPERTY_BASED_ELEMENT_HXX_
#define PROPERTY_BASED_ELEMENT_HXX_
#include <Canvas/canvas_fwd.hpp>
#include <simgear/props/props.hxx>
/**
* Base class for a property controlled element
*/
class PropertyBasedElement:
public SGPropertyChangeListener
{
public:
PropertyBasedElement(SGPropertyNode* node);
virtual ~PropertyBasedElement();
virtual void update(double delta_time_sec) = 0;
protected:
friend class PropertyBasedMgr;
SGPropertyNode_ptr _node;
PropertyBasedElementWeakPtr _self;
};
#endif /* PROPERTY_BASED_ELEMENT_HXX_ */

View file

@ -0,0 +1,118 @@
// Base class for all property controlled subsystems
//
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
//
// 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.
#include "property_based_mgr.hxx"
#include "property_helper.hxx"
#include <Main/fg_props.hxx>
#include <stdexcept>
#include <string>
//------------------------------------------------------------------------------
void PropertyBasedMgr::init()
{
_props->addChangeListener(this);
canvas::triggerChangeRecursive(_props);
}
//------------------------------------------------------------------------------
void PropertyBasedMgr::shutdown()
{
_props->removeChangeListener(this);
}
//------------------------------------------------------------------------------
void PropertyBasedMgr::update(double delta_time_sec)
{
for( size_t i = 0; i < _elements.size(); ++i )
if( _elements[i] )
_elements[i]->update(delta_time_sec);
}
//------------------------------------------------------------------------------
void PropertyBasedMgr::childAdded( SGPropertyNode * parent,
SGPropertyNode * child )
{
if( parent != _props || child->getNameString() != _name_elements )
return;
size_t index = child->getIndex();
if( index >= _elements.size() )
{
if( index > _elements.size() )
SG_LOG
(
SG_GENERAL,
SG_WARN,
"Skipping unused " << _name_elements << " slot(s)!"
);
_elements.resize(index + 1);
}
else if( _elements[index] )
SG_LOG
(
SG_GENERAL,
SG_WARN,
_name_elements << "[" << index << "] already exists!"
);
PropertyBasedElementPtr el = _element_factory(child);
el->_self = el;
_elements[index] = el;
elementCreated( el );
}
//------------------------------------------------------------------------------
void PropertyBasedMgr::childRemoved( SGPropertyNode * parent,
SGPropertyNode * child )
{
if( parent != _props || child->getNameString() != _name_elements )
return;
size_t index = child->getIndex();
if( index >= _elements.size() )
SG_LOG
(
SG_GENERAL,
SG_WARN,
"can't removed unknown " << _name_elements << "[" << index << "]!"
);
else
// remove the element...
_elements[index].reset();
}
//------------------------------------------------------------------------------
PropertyBasedMgr::PropertyBasedMgr( const std::string& path_root,
const std::string& name_elements,
ElementFactory element_factory ):
_props( fgGetNode(path_root, true) ),
_name_elements( name_elements ),
_element_factory( element_factory )
{
}
//------------------------------------------------------------------------------
PropertyBasedMgr::~PropertyBasedMgr()
{
}

View file

@ -0,0 +1,75 @@
// Base class for all property controlled subsystems
//
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
//
// 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 PROPERTY_BASED_MGR_HXX_
#define PROPERTY_BASED_MGR_HXX_
#include "property_based_element.hxx"
#include <simgear/structure/subsystem_mgr.hxx>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <vector>
class PropertyBasedMgr:
public SGSubsystem,
public SGPropertyChangeListener
{
public:
virtual void init();
virtual void shutdown();
virtual void update (double delta_time_sec);
virtual void childAdded( SGPropertyNode * parent,
SGPropertyNode * child );
virtual void childRemoved( SGPropertyNode * parent,
SGPropertyNode * child );
virtual void elementCreated(PropertyBasedElementPtr element) {}
protected:
typedef boost::function<PropertyBasedElementPtr(SGPropertyNode*)>
ElementFactory;
/** Branch in the property tree for this property managed subsystem */
SGPropertyNode* _props;
/** Property name of managed elements */
const std::string _name_elements;
/** The actually managed elements */
std::vector<PropertyBasedElementPtr> _elements;
/** Function object which creates a new element */
ElementFactory _element_factory;
/**
* @param path_root Path to property branch used for controlling this
* subsystem
* @param name_elements The name of the nodes for the managed elements
*/
PropertyBasedMgr( const std::string& path_root,
const std::string& name_elements,
ElementFactory element_factory );
virtual ~PropertyBasedMgr() = 0;
};
#endif /* PROPERTY_BASED_MGR_HXX_ */

View file

@ -44,4 +44,16 @@ namespace canvas
for( size_t i = 0; i < num_channels; ++i )
nodes.push_back( getChildDefault(color, channels[i], def[i]) );
}
//----------------------------------------------------------------------------
void triggerChangeRecursive(SGPropertyNode* node)
{
node->getParent()->fireChildAdded(node);
if( node->nChildren() == 0 && node->getType() != simgear::props::NONE )
return node->fireValueChanged();
for( int i = 0; i < node->nChildren(); ++i )
triggerChangeRecursive( node->getChild(i) );
}
}

View file

@ -78,6 +78,12 @@ namespace canvas
std::vector<SGPropertyNode_ptr>& nodes,
const osg::Vec4& def = osg::Vec4(0,0,0,1) );
/**
* Trigger a childAdded and valueChanged event for every child of node
* (Unlimited depth) and node itself.
*/
void triggerChangeRecursive(SGPropertyNode* node);
} // namespace canvas
#endif /* PROPERTY_HELPER_HXX_ */

68
src/Canvas/rect.hxx Normal file
View file

@ -0,0 +1,68 @@
// Class representing a rectangular region
//
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
//
// 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 CANVAS_RECT_HXX_
#define CANVAS_RECT_HXX_
#include <osg/Vec2>
namespace canvas
{
template<typename T>
class Rect
{
public:
Rect() {}
Rect(T x, T y, T w, T h):
_x1(x),
_x2(x + w),
_y1(y),
_y2(y + h)
{}
void set(T x, T y, T w, T h)
{
_x1 = x;
_x2 = x + w;
_y1 = y;
_y2 = y + h;
}
T x() const { return _x1; }
T y() const { return _y1; }
T width() const { return _x2 - _x1; }
T height() const { return _y2 - _y1; }
T l() const { return _x1; }
T r() const { return _x2; }
T t() const { return _y1; }
T b() const { return _y2; }
bool contains(T x, T y) const
{
return _x1 <= x && x <= _x2
&& _y1 <= y && y <= _y2;
}
private:
T _x1, _x2, _y1, _y2;
};
} // namespace canvas
#endif /* CANVAS_RECT_HXX_ */

177
src/Canvas/window.cxx Normal file
View file

@ -0,0 +1,177 @@
// Window for placing a Canvas onto it (for dialogs, menus, etc.)
//
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
//
// 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.
#include "window.hxx"
#include <Canvas/canvas.hxx>
#include <osg/BlendFunc>
#include <osg/Geometry>
#include <osg/Texture2D>
#include <osgGA/GUIEventHandler>
/**
* Callback to enable/disable rendering of canvas displayed inside windows
*/
class CullCallback:
public osg::Drawable::CullCallback
{
public:
CullCallback(Canvas::CameraCullCallback* camera_cull);
private:
Canvas::CameraCullCallback *_camera_cull;
virtual bool cull( osg::NodeVisitor* nv,
osg::Drawable* drawable,
osg::RenderInfo* renderInfo ) const;
};
//------------------------------------------------------------------------------
CullCallback::CullCallback(Canvas::CameraCullCallback* camera_cull):
_camera_cull( camera_cull )
{
}
//------------------------------------------------------------------------------
bool CullCallback::cull( osg::NodeVisitor* nv,
osg::Drawable* drawable,
osg::RenderInfo* renderInfo ) const
{
_camera_cull->enableRendering();
return false;
}
namespace canvas
{
//----------------------------------------------------------------------------
Window::Window(SGPropertyNode* node):
PropertyBasedElement(node),
_dirty(true),
_geometry( new osg::Geometry ),
_vertices( new osg::Vec3Array(4) ),
_tex_coords( new osg::Vec2Array(4) ),
_x(node, "x"),
_y(node, "y"),
_width(node, "size[0]"),
_height(node, "size[1]")
{
_x = 50;
_y = 100;
_width = 400;
_height = 300;
_geometry->setVertexArray(_vertices);
_geometry->setTexCoordArray(0,_tex_coords);
osg::Vec4Array* colors = new osg::Vec4Array(1);
(*colors)[0].set(1.0f,1.0f,1.0,1.0f);
_geometry->setColorArray(colors);
_geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
_geometry->addPrimitiveSet(
new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4)
);
_geometry->setDataVariance(osg::Object::DYNAMIC);
osg::StateSet* stateSet = _geometry->getOrCreateStateSet();
stateSet->setRenderBinDetails(1000, "RenderBin");
// speed optimization?
stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
stateSet->setAttribute(new osg::BlendFunc(
osg::BlendFunc::SRC_ALPHA,
osg::BlendFunc::ONE_MINUS_SRC_ALPHA)
);
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
}
//----------------------------------------------------------------------------
Window::~Window()
{
}
//----------------------------------------------------------------------------
void Window::update(double delta_time_sec)
{
if( !_dirty )
return;
_dirty = false;
_region.set(_x, _y, _width, _height);
int z = 0; // TODO do we need to use z for depth ordering?
(*_vertices)[0].set(_region.l(), _region.t(), z);
(*_vertices)[1].set(_region.r(), _region.t(), z);
(*_vertices)[2].set(_region.r(), _region.b(), z);
(*_vertices)[3].set(_region.l(), _region.b(), z);
float l = 0, t = 1, b = 0, r = 1;
(*_tex_coords)[0].set(l,t);
(*_tex_coords)[1].set(r,t);
(*_tex_coords)[2].set(r,b);
(*_tex_coords)[3].set(l,b);
_geometry->dirtyDisplayList();
}
//----------------------------------------------------------------------------
void Window::valueChanged (SGPropertyNode * node)
{
if( node->getParent() != _node )
return;
const std::string& name = node->getNameString();
if( name == "x" || name == "y" || name == "size" )
_dirty = true;
}
//----------------------------------------------------------------------------
void Window::setCanvas(CanvasPtr canvas)
{
_canvas = canvas;
_geometry->getOrCreateStateSet()
->setTextureAttribute(0, canvas ? canvas->getTexture() : 0);
_geometry->dirtyDisplayList();
_geometry->setCullCallback(
canvas ? new CullCallback(canvas->getCameraCullCallback()) : 0
);
}
//----------------------------------------------------------------------------
CanvasWeakPtr Window::getCanvas() const
{
return _canvas;
}
//----------------------------------------------------------------------------
bool Window::handleMouseEvent(const MouseEvent& event)
{
if( !_canvas.expired() )
return _canvas.lock()->handleMouseEvent(event);
else
return false;
}
} // namespace canvas

66
src/Canvas/window.hxx Normal file
View file

@ -0,0 +1,66 @@
// Window for placing a Canvas onto it (for dialogs, menus, etc.)
//
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
//
// 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 CANVAS_WINDOW_HXX_
#define CANVAS_WINDOW_HXX_
#include "mouse_event.hxx"
#include "property_based_element.hxx"
#include "rect.hxx"
#include <simgear/props/propertyObject.hxx>
#include <osg/Geometry>
namespace canvas
{
class Window:
public PropertyBasedElement
{
public:
Window(SGPropertyNode* node);
virtual ~Window();
virtual void update(double delta_time_sec);
virtual void valueChanged (SGPropertyNode * node);
osg::Drawable* getDrawable() { return _geometry; }
const Rect<int>& getRegion() const { return _region; }
void setCanvas(CanvasPtr canvas);
CanvasWeakPtr getCanvas() const;
bool handleMouseEvent(const MouseEvent& event);
protected:
bool _dirty;
osg::ref_ptr<osg::Geometry> _geometry;
osg::ref_ptr<osg::Vec3Array> _vertices;
osg::ref_ptr<osg::Vec2Array> _tex_coords;
simgear::PropertyObject<int> _x, _y,
_width, _height;
Rect<int> _region;
CanvasWeakPtr _canvas;
};
} // namespace canvas
#endif /* CANVAS_WINDOW_HXX_ */

View file

@ -311,7 +311,7 @@ class ReplaceStaticTextureVisitor:
* Get a list of groups which have been inserted into the scene graph to
* replace the given texture
*/
Placements& getPlacements()
canvas::Placements& getPlacements()
{
return _placements;
}
@ -386,7 +386,9 @@ class ReplaceStaticTextureVisitor:
if( _cull_callback )
group->setCullCallback(_cull_callback);
_placements.push_back(group);
_placements.push_back(
canvas::PlacementPtr(new ObjectPlacement(group))
);
osg::StateSet* stateSet = group->getOrCreateStateSet();
stateSet->setTextureAttribute( unit, _new_texture,
@ -407,10 +409,38 @@ class ReplaceStaticTextureVisitor:
}
}
protected:
class ObjectPlacement:
public canvas::Placement
{
public:
ObjectPlacement(osg::ref_ptr<osg::Group> group):
_group(group)
{}
/**
* Remove placement from the scene
*/
virtual ~ObjectPlacement()
{
assert( _group->getNumChildren() == 1 );
osg::Node *child = _group->getChild(0);
if( _group->getNumParents() )
{
osg::Group *parent = _group->getParent(0);
parent->addChild(child);
parent->removeChild(_group);
}
_group->removeChild(child);
}
private:
osg::ref_ptr<osg::Group> _group;
};
std::string _tex_name, ///<! Name of texture to be replaced
_node_name, ///<! Only replace if node name matches
_parent_name; ///<! Only replace if any parent node matches
@ -418,11 +448,12 @@ class ReplaceStaticTextureVisitor:
osg::Texture2D *_new_texture;
osg::NodeCallback *_cull_callback;
Placements _placements;
canvas::Placements _placements;
};
//------------------------------------------------------------------------------
Placements FGODGauge::set_texture(const char* name, osg::Texture2D* new_texture)
canvas::Placements FGODGauge::set_texture( const char* name,
osg::Texture2D* new_texture )
{
osg::Group* root = globals->get_scenery()->get_aircraft_branch();
ReplaceStaticTextureVisitor visitor(name, new_texture);
@ -431,9 +462,9 @@ class ReplaceStaticTextureVisitor:
}
//------------------------------------------------------------------------------
Placements FGODGauge::set_texture( const SGPropertyNode* placement,
osg::Texture2D* new_texture,
osg::NodeCallback* cull_callback )
canvas::Placements FGODGauge::set_texture( const SGPropertyNode* placement,
osg::Texture2D* new_texture,
osg::NodeCallback* cull_callback )
{
osg::Group* root = globals->get_scenery()->get_aircraft_branch();
ReplaceStaticTextureVisitor visitor(placement, new_texture, cull_callback);

View file

@ -29,6 +29,9 @@
#ifndef _OD_GAUGE_HXX
#define _OD_GAUGE_HXX
#include <Canvas/canvas_fwd.hpp>
#include <Canvas/placement.hxx>
#include <osg/NodeCallback>
#include <osg/Group>
@ -38,14 +41,13 @@ namespace osg {
}
class SGPropertyNode;
typedef std::vector<osg::ref_ptr<osg::Group> > Placements;
/**
* Owner Drawn Gauge helper class.
*/
class FGODGauge
{
public:
public:
FGODGauge();
virtual ~FGODGauge();
@ -109,7 +111,9 @@ public:
* @param new_texture dynamic texture to replace the old one
* @return A list of groups which override the given texture
*/
Placements set_texture(const char * name, osg::Texture2D* new_texture);
static
canvas::Placements set_texture( const char * name,
osg::Texture2D* new_texture );
/**
* Replace an opengl texture name inside the aircraft scene graph.
@ -125,9 +129,10 @@ public:
* object
* @return A list of groups which override the given texture
*/
Placements set_texture( const SGPropertyNode* placement,
osg::Texture2D* new_texture,
osg::NodeCallback* cull_callback = 0 );
static
canvas::Placements set_texture( const SGPropertyNode* placement,
osg::Texture2D* new_texture,
osg::NodeCallback* cull_callback = 0 );
/**
* Get the OSG camera for drawing this gauge.

View file

@ -81,6 +81,7 @@
#include <Cockpit/panel_io.hxx>
#include <Canvas/canvas_mgr.hxx>
#include <Canvas/gui_mgr.hxx>
#include <GUI/new_gui.hxx>
#include <Input/input.hxx>
#include <Instrumentation/instrument_mgr.hxx>
@ -1164,6 +1165,7 @@ bool fgInitSubsystems() {
// Initialize the canvas 2d drawing subsystem.
////////////////////////////////////////////////////////////////////
globals->add_subsystem("Canvas", new CanvasMgr, SGSubsystemMgr::DISPLAY);
globals->add_subsystem("CanvasGUI", new GUIMgr, SGSubsystemMgr::DISPLAY);
////////////////////////////////////////////////////////////////////
// Initialise the ATIS Manager