using std::vector;
-static FGPanelNode* global_panel = NULL;
+class PanelTransformListener : public SGPropertyChangeListener
+{
+public:
+ PanelTransformListener(FGPanelNode* pn) : _panelNode(pn) {}
+
+ virtual void valueChanged (SGPropertyNode * node)
+ {
+ _panelNode->dirtyBound();
+ }
+private:
+ FGPanelNode* _panelNode;
+};
-/**
- * Built-in command: pass a mouse click to the panel.
- *
- * button: the mouse button number, zero-based.
- * is-down: true if the button is down, false if it is up.
- * x-pos: the x position of the mouse click.
- * y-pos: the y position of the mouse click.
- */
-static bool
-do_panel_mouse_click (const SGPropertyNode * arg)
+class PanelPathListener : public SGPropertyChangeListener
{
- if (global_panel)
- return global_panel->getPanel()
- ->doMouseAction(arg->getIntValue("button"),
- arg->getBoolValue("is-down") ? PU_DOWN : PU_UP,
- arg->getIntValue("x-pos"),
- arg->getIntValue("y-pos"));
- else
- return false;
-
- return false;
-}
+public:
+ PanelPathListener(FGPanelNode* pn) : _panelNode(pn) {}
+
+ virtual void valueChanged (SGPropertyNode * node)
+ {
+ _panelNode->setPanelPath(node->getStringValue());
+ }
+private:
+ FGPanelNode* _panelNode;
+};
class FGPanelPickCallback : public SGPickCallback {
public:
panel(p)
{}
- virtual bool buttonPressed(int b, const Info& info)
+ virtual bool buttonPressed( int b,
+ const osgGA::GUIEventAdapter&,
+ const Info& info )
{
button = b;
// convert to panel coordinates
picked.x(), picked.y());
}
- virtual void update(double dt)
+ virtual void update(double dt, int keyModState)
{
panel->getPanel()->updateMouseDelay(dt);
}
- virtual void buttonReleased(void)
+ virtual void buttonReleased( int,
+ const osgGA::GUIEventAdapter&,
+ const Info* )
{
panel->getPanel()->doLocalMouseAction(button, MOUSE_BUTTON_UP,
picked.x(), picked.y());
private:
FGPanelNode* panel;
- SGPropertyNode* visProp;
+ SGPropertyNode_ptr visProp;
};
FGPanelNode::FGPanelNode(SGPropertyNode* props) :
- _resizeToViewport(false)
+ _is2d(false),
+ _resizeToViewport(false),
+ _listener(NULL)
{
commonInit();
_panelPath = props->getStringValue("path");
}
FGPanelNode::FGPanelNode() :
+ _is2d(true),
_resizeToViewport(true),
_depthTest(false)
{
- commonInit();
+ globals->get_commands()->addCommand("panel-mouse-click", this, &FGPanelNode::panelMouseClickCommand);
+
+ SGPropertyNode* pathNode = fgGetNode("/sim/panel/path");
+ _pathListener.reset(new PanelPathListener(this));
+ pathNode->addChangeListener(_pathListener.get());
+ setPanelPath(pathNode->getStringValue());
+
+ // for a 2D panel, various options adjust the transformation
+ // matrix. We need to pass this data on to OSG or its bounding box
+ // will be stale, and picking will break.
+ // http://code.google.com/p/flightgear-bugs/issues/detail?id=864
+ _listener = new PanelTransformListener(this);
+ fgGetNode("/sim/panel/x-offset", true)->addChangeListener(_listener);
+ fgGetNode("/sim/panel/y-offset", true)->addChangeListener(_listener);
+ fgGetNode("/sim/startup/xsize", true)->addChangeListener(_listener);
+ fgGetNode("/sim/startup/ysize", true)->addChangeListener(_listener);
+
+ commonInit();
+}
+
+FGPanelNode::~FGPanelNode()
+{
+ if (_is2d) {
+ globals->get_commands()->removeCommand("panel-mouse-click");
+ SGPropertyNode* pathNode = fgGetNode("/sim/panel/path");
+ pathNode->removeChangeListener(_pathListener.get());
+ }
+
+ if (_listener) {
+ fgGetNode("/sim/panel/x-offset", true)->removeChangeListener(_listener);
+ fgGetNode("/sim/panel/y-offset", true)->removeChangeListener(_listener);
+ fgGetNode("/sim/startup/xsize", true)->removeChangeListener(_listener);
+ fgGetNode("/sim/startup/ysize", true)->removeChangeListener(_listener);
+ delete _listener;
+ }
}
void FGPanelNode::setPanelPath(const std::string& panel)
_panel = fgReadPanel(_panelPath);
if (!_panel) {
SG_LOG(SG_COCKPIT, SG_WARN, "failed to read panel from:" << _panelPath);
- _panelPath = string(); // don't keep trying to read
+ _panelPath = std::string(); // don't keep trying to read
return;
}
float panelHeight = _panel->getHeight();
_panel->getLogicalExtent(_xmin, _ymin, _xmax, _ymax);
-
+
// Now generate our transformation matrix. For shorthand, use
// "a", "b", and "c" as our corners and "m" as the matrix. The
// vector u goes from a to b, v from a to c, and w is a
osg::Vec3 v = c - a;
osg::Vec3 w = u^v;
- osg::Matrix& m = _xform;
- // Now generate a trivial basis transformation matrix. If we want
- // to map the three unit vectors to three arbitrary vectors U, V,
- // and W, then those just become the columns of the 3x3 matrix.
- m(0,0) = u[0]; m(1,0) = v[0]; m(2,0) = w[0]; m(3,0) = a[0];// |Ux Vx Wx|
- m(0,1) = u[1]; m(1,1) = v[1]; m(2,1) = w[1]; m(3,1) = a[1];//m = |Uy Vy Wy|
- m(0,2) = u[2]; m(1,2) = v[2]; m(2,2) = w[2]; m(3,2) = a[2];// |Uz Vz Wz|
- m(0,3) = 0; m(1,3) = 0; m(2,3) = 0; m(3,3) = 1;
+ osg::Matrix& m = _xform;
+ if ((u.length2() == 0.0) || (b.length2() == 0.0)) {
+ m.makeIdentity();
+ } else {
+ // Now generate a trivial basis transformation matrix. If we want
+ // to map the three unit vectors to three arbitrary vectors U, V,
+ // and W, then those just become the columns of the 3x3 matrix.
+ m(0,0) = u[0]; m(1,0) = v[0]; m(2,0) = w[0]; m(3,0) = a[0];// |Ux Vx Wx|
+ m(0,1) = u[1]; m(1,1) = v[1]; m(2,1) = w[1]; m(3,1) = a[1];//m = |Uy Vy Wy|
+ m(0,2) = u[2]; m(1,2) = v[2]; m(2,2) = w[2]; m(3,2) = a[2];// |Uz Vz Wz|
+ m(0,3) = 0; m(1,3) = 0; m(2,3) = 0; m(3,3) = 1;
+ }
// The above matrix maps the unit (!) square to the panel
// rectangle. Postmultiply scaling factors that match the
dirtyBound();
}
-FGPanelNode::~FGPanelNode()
-{
-}
-
osg::Matrix FGPanelNode::transformMatrix() const
{
if (!_panel) {
return geode;
}
-class PanelPathObserver : public SGPropertyChangeListener
-{
-public:
- PanelPathObserver(FGPanelNode* pn) : _panelNode(pn) {}
-
- virtual void valueChanged (SGPropertyNode * node)
- {
- _panelNode->setPanelPath(node->getStringValue());
- }
-private:
- FGPanelNode* _panelNode;
-};
-
osg::Node* FGPanelNode::create2DPanelNode()
{
- SGCommandMgr::instance()->addCommand("panel-mouse-click", do_panel_mouse_click);
-
- SGPropertyNode* pathNode = fgGetNode("/sim/panel/path");
-
- FGPanelNode* drawable = new FGPanelNode();
-// need a global to keep the panel_mouse_click command working, sadly
- global_panel = drawable;
-
- PanelPathObserver* ppo = new PanelPathObserver(drawable);
- pathNode->addChangeListener(ppo);
- drawable->setPanelPath(pathNode->getStringValue());
-
+ FGPanelNode* drawable = new FGPanelNode;
+
osg::Switch* ps = new osg::Switch;
osg::StateSet* stateSet = ps->getOrCreateStateSet();
stateSet->setRenderBinDetails(1000, "RenderBin");
drawable->lazyLoad(); // force load now for 2.5D panels
return createGeode(drawable);
}
+
+/**
+ * Built-in command: pass a mouse click to the panel.
+ *
+ * button: the mouse button number, zero-based.
+ * is-down: true if the button is down, false if it is up.
+ * x-pos: the x position of the mouse click.
+ * y-pos: the y position of the mouse click.
+ */
+bool
+FGPanelNode::panelMouseClickCommand(const SGPropertyNode * arg)
+{
+ return _panel->doMouseAction(arg->getIntValue("button"),
+ arg->getBoolValue("is-down") ? PU_DOWN : PU_UP,
+ arg->getIntValue("x-pos"),
+ arg->getIntValue("y-pos"));
+}