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
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}")
#include "canvas.hxx"
#include "elements/group.hxx"
+#include "mouse_event.hxx"
#include <Canvas/property_helper.hxx>
#include <Main/globals.hxx>
#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:
+//----------------------------------------------------------------------------
+void Canvas::CameraCullCallback::enableRendering()
+{
+ _render = true;
+}
- bool _render;
- unsigned int _render_frame;
+//----------------------------------------------------------------------------
+void Canvas::CameraCullCallback::operator()( osg::Node* node,
+ osg::NodeVisitor* nv )
+{
+ if( !_render && nv->getTraversalNumber() != _render_frame )
+ return;
- virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
- {
- if( !_render && nv->getTraversalNumber() != _render_frame )
- return;
+ traverse(node, nv);
- traverse(node, nv);
+ _render = false;
+ _render_frame = nv->getTraversalNumber();
+}
- _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
+//----------------------------------------------------------------------------
+Canvas::CullCallback::CullCallback(CameraCullCallback* camera_cull):
+ _camera_cull( camera_cull )
{
- public:
- PlacementCullCallback(Canvas* canvas, CameraCullCallback* camera_cull):
- _canvas( canvas ),
- _camera_cull( camera_cull )
- {}
-
- private:
-
- Canvas *_canvas;
- CameraCullCallback *_camera_cull;
+}
- virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
- {
- if( nv->getTraversalMask() & simgear::MODEL_BIT )
- _camera_cull->enableRendering();
+//----------------------------------------------------------------------------
+void Canvas::CullCallback::operator()( osg::Node* node,
+ osg::NodeVisitor* nv )
+{
+ if( nv->getTraversalMask() & simgear::MODEL_BIT )
+ _camera_cull->enableRendering();
- traverse(node, nv);
- }
-};
+ 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)
- );
- }
}
//------------------------------------------------------------------------------
// New placement
_placements.resize(node->getIndex() + 1);
else
- // Remove maybe already existing placements
- clearPlacements(node->getIndex());
-
- // add new placements
- _placements[node->getIndex()] = _texture.set_texture(
- node,
- _texture.getTexture(),
- _cull_callback
- );
+ // Remove possibly existing placements
+ _placements[ node->getIndex() ].clear();
+
+ // 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 )
setStatusFlags(CREATE_FAILED, false);
}
-//------------------------------------------------------------------------------
-int Canvas::getSizeX() const
-{
- return _size_x;
-}
-
//------------------------------------------------------------------------------
void Canvas::setSizeY(int sy)
{
setStatusFlags(CREATE_FAILED, false);
}
-//------------------------------------------------------------------------------
-int Canvas::getSizeY() const
-{
- return _size_y;
-}
-
//------------------------------------------------------------------------------
void Canvas::setViewWidth(int w)
{
_texture.setViewSize(_view_width, _view_height);
}
-//------------------------------------------------------------------------------
-int Canvas::getViewWidth() const
-{
- return _view_width;
-}
-
//------------------------------------------------------------------------------
void Canvas::setViewHeight(int h)
{
}
//------------------------------------------------------------------------------
-int Canvas::getViewHeight() const
-{
- return _view_height;
-}
-
-//------------------------------------------------------------------------------
-const char* Canvas::getStatusMsg() const
+bool Canvas::handleMouseEvent(const canvas::MouseEvent& event)
{
- 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;
}
//------------------------------------------------------------------------------
return;
if( child->getNameString() == "placement" )
- clearPlacements(child->getIndex());
+ _placements[ child->getIndex() ].clear();
else
static_cast<canvas::Element*>(_root_group.get())
->childRemoved(parent, child);
//----------------------------------------------------------------------------
void Canvas::valueChanged(SGPropertyNode* node)
{
+ if( boost::starts_with(node->getNameString(), "status") )
+ return;
+
if( node->getParent()->getParent() == _node )
{
if( !_color_background.empty()
_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
{
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";
}
//------------------------------------------------------------------------------
-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;
#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:
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 );
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;
_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;
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;
- void setStatusFlags(unsigned int flags, bool set = true);
- void clearPlacements(int index);
- void clearPlacements();
+ typedef std::map<std::string, canvas::PlacementFactory> PlacementFactoryMap;
+ static PlacementFactoryMap _placement_factories;
- void unbind();
+ void setStatusFlags(unsigned int flags, bool set = true);
};
#endif /* CANVAS_HXX_ */
--- /dev/null
+// 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_ */
#include "canvas_mgr.hxx"
#include "canvas.hxx"
-#include <Main/fg_props.hxx>
+#include <boost/bind.hpp>
-#include <osg/Camera>
-#include <osg/Texture2D>
-
-#include <stdexcept>
-#include <string>
-
-//------------------------------------------------------------------------------
-CanvasMgr::CanvasMgr():
- _props( fgGetNode("/canvas", true) )
-{
-
-}
-
-//------------------------------------------------------------------------------
-CanvasMgr::~CanvasMgr()
-{
-
-}
-
-//------------------------------------------------------------------------------
-void CanvasMgr::init()
+typedef boost::shared_ptr<Canvas> CanvasPtr;
+CanvasPtr canvasFactory(SGPropertyNode* node)
{
- _props->addChangeListener(this);
- triggerChangeRecursive(_props);
+ return CanvasPtr(new Canvas(node));
}
-//------------------------------------------------------------------------------
-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 )
+CanvasMgr::CanvasMgr():
+ PropertyBasedMgr("/canvas", "texture", &canvasFactory)
{
- 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();
}
#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
* @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_ */
_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;
+
}
//----------------------------------------------------------------------------
#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() )
return "unknown";
}
}
-
+#endif
//----------------------------------------------------------------------------
void Text::childChanged(SGPropertyNode* child)
{
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() );
}
//----------------------------------------------------------------------------
{
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:
--- /dev/null
+// 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
+ ));
+}
--- /dev/null
+// 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_ */
--- /dev/null
+// 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_ */
--- /dev/null
+// 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
--- /dev/null
+// 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_ */
--- /dev/null
+// 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);
+}
--- /dev/null
+// 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_ */
--- /dev/null
+// 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()
+{
+
+}
--- /dev/null
+// 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_ */
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) );
+ }
}
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_ */
--- /dev/null
+// 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_ */
--- /dev/null
+// 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
--- /dev/null
+// 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_ */
* 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;
}
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,
}
}
+ 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);
- protected:
+ 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
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);
}
//------------------------------------------------------------------------------
-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);
#ifndef _OD_GAUGE_HXX
#define _OD_GAUGE_HXX
+#include <Canvas/canvas_fwd.hpp>
+#include <Canvas/placement.hxx>
+
#include <osg/NodeCallback>
#include <osg/Group>
}
class SGPropertyNode;
-typedef std::vector<osg::ref_ptr<osg::Group> > Placements;
/**
* Owner Drawn Gauge helper class.
*/
class FGODGauge
{
-public:
+ public:
FGODGauge();
virtual ~FGODGauge();
* @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.
* 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.
#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>
// 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