]> git.mxchange.org Git - simgear.git/commitdiff
Work on knob/slider animations.
authorJames Turner <zakalawe@mac.com>
Thu, 7 Mar 2013 18:40:37 +0000 (18:40 +0000)
committerJames Turner <zakalawe@mac.com>
Thu, 7 Mar 2013 18:40:37 +0000 (18:40 +0000)
Rename some values, and support mouse-dragging.

simgear/scene/model/SGPickAnimation.cxx
simgear/scene/model/SGPickAnimation.hxx
simgear/scene/model/animation.cxx
simgear/scene/model/animation.hxx
simgear/scene/util/SGPickCallback.hxx

index b212161f891115285877eb4630d87e6b01b99079..0a8a4d883a184396cd085db4cd1d66cf806664d6 100644 (file)
 #include <osg/PolygonMode>
 #include <osg/Material>
 #include <osgGA/GUIEventAdapter>
-     
+
+#include <simgear/sg_inlines.h>
 #include <simgear/scene/util/SGPickCallback.hxx>
 #include <simgear/scene/material/EffectGeode.hxx>
 #include <simgear/scene/util/SGSceneUserData.hxx>
 #include <simgear/structure/SGBinding.hxx>
 #include <simgear/scene/util/StateAttributeFactory.hxx>
 #include <simgear/scene/model/SGRotateTransform.hxx>
+#include <simgear/scene/model/SGTranslateTransform.hxx>
 
 using namespace simgear;
 
@@ -49,6 +51,23 @@ static void readOptionalBindingList(const SGPropertyNode* aNode, SGPropertyNode*
     
 }
 
+
+osg::Vec2d eventToWindowCoords(const osgGA::GUIEventAdapter* ea)
+{
+    using namespace osg;
+    const GraphicsContext* gc = ea->getGraphicsContext();
+    const GraphicsContext::Traits* traits = gc->getTraits() ;
+    // Scale x, y to the dimensions of the window
+    double x = (((ea->getX() - ea->getXmin()) / (ea->getXmax() - ea->getXmin()))
+         * (double)traits->width);
+    double y = (((ea->getY() - ea->getYmin()) / (ea->getYmax() - ea->getYmin()))
+         * (double)traits->height);
+    if (ea->getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS)
+        y = (double)traits->height - y;
+    
+    return osg::Vec2d(x, y);
+}
+
  class SGPickAnimation::PickCallback : public SGPickCallback {
  public:
    PickCallback(const SGPropertyNode* configNode,
@@ -79,12 +98,15 @@ static void readOptionalBindingList(const SGPropertyNode* aNode, SGPropertyNode*
      _repeatTime = -_repeatInterval;    // anti-bobble: delay start of repeat
      return true;
    }
-   virtual void buttonReleased(void)
+   virtual void buttonReleased(int keyModState)
    {
+       SG_UNUSED(keyModState);
        fireBindingList(_bindingsUp);
    }
-   virtual void update(double dt)
+     
+   virtual void update(double dt, int keyModState)
    {
+     SG_UNUSED(keyModState);
      if (!_repeatable)
        return;
 
@@ -193,6 +215,7 @@ static void readOptionalBindingList(const SGPropertyNode* aNode, SGPropertyNode*
    bool _done;
  };
 
+///////////////////////////////////////////////////////////////////////////////
 
  class SGPickAnimation::VncCallback : public SGPickCallback {
  public:
@@ -231,15 +254,14 @@ static void readOptionalBindingList(const SGPropertyNode* aNode, SGPropertyNode*
      return vv.wasSuccessful();
 
    }
-   virtual void buttonReleased(void)
+   virtual void buttonReleased(int keyModState)
    {
+     SG_UNUSED(keyModState);
      SG_LOG(SG_INPUT, SG_DEBUG, "VNC release");
      VncVisitor vv(_x, _y, 0);
      _node->accept(vv);
    }
-   virtual void update(double dt)
-   {
-   }
+
  private:
    double _x, _y;
    osg::ref_ptr<osg::Group> _node;
@@ -247,6 +269,8 @@ static void readOptionalBindingList(const SGPropertyNode* aNode, SGPropertyNode*
    double _squaredRight, _squaredDown;
  };
 
+///////////////////////////////////////////////////////////////////////////////
+
  SGPickAnimation::SGPickAnimation(const SGPropertyNode* configNode,
                                   SGPropertyNode* modelRoot) :
    SGAnimation(configNode, modelRoot)
@@ -363,30 +387,30 @@ static void repeatBindings(const SGBindingList& a, SGBindingList& out, int count
 }
 
 static bool static_knobMouseWheelAlternateDirection = false;
+static bool static_knobDragAlternateAxis = false;
 
-class SGKnobAnimation::KnobPickCallback : public SGPickCallback {
+class KnobSliderPickCallback : public SGPickCallback {
 public:
-    KnobPickCallback(const SGPropertyNode* configNode,
+    KnobSliderPickCallback(const SGPropertyNode* configNode,
                  SGPropertyNode* modelRoot) :
         SGPickCallback(PriorityPanel),
         _direction(DIRECTION_NONE),
-        _repeatInterval(configNode->getDoubleValue("interval-sec", 0.1)),
-        _stickyShifted(false)
+        _repeatInterval(configNode->getDoubleValue("interval-sec", 0.1))
     {
         readOptionalBindingList(configNode, modelRoot, "action", _action);
-        readOptionalBindingList(configNode, modelRoot, "cw", _bindingsCW);
-        readOptionalBindingList(configNode, modelRoot, "ccw", _bindingsCCW);
+        readOptionalBindingList(configNode, modelRoot, "increase", _bindingsCW);
+        readOptionalBindingList(configNode, modelRoot, "decrease", _bindingsCCW);
         
         readOptionalBindingList(configNode, modelRoot, "release", _releaseAction);
         readOptionalBindingList(configNode, modelRoot, "hovered", _hover);
         
-        if (configNode->hasChild("shift-action") || configNode->hasChild("shift-cw") ||
-            configNode->hasChild("shift-ccw"))
+        if (configNode->hasChild("shift-action") || configNode->hasChild("shift-increase") ||
+            configNode->hasChild("shift-decrease"))
         {
         // explicit shifted behaviour - just do exactly what was provided
             readOptionalBindingList(configNode, modelRoot, "shift-action", _shiftedAction);
-            readOptionalBindingList(configNode, modelRoot, "shift-cw", _shiftedCW);
-            readOptionalBindingList(configNode, modelRoot, "shift-ccw", _shiftedCCW);
+            readOptionalBindingList(configNode, modelRoot, "shift-increase", _shiftedCW);
+            readOptionalBindingList(configNode, modelRoot, "shift-decrease", _shiftedCCW);
         } else {
             // default shifted behaviour - repeat normal bindings N times.
             int shiftRepeat = configNode->getIntValue("shift-repeat", 10);
@@ -394,12 +418,12 @@ public:
             repeatBindings(_bindingsCW, _shiftedCW, shiftRepeat);
             repeatBindings(_bindingsCCW, _shiftedCCW, shiftRepeat);
         } // of default shifted behaviour
+        
+        _dragScale = configNode->getDoubleValue("drag-scale-px", 10.0);
     }
     
     virtual bool buttonPressed(int button, const osgGA::GUIEventAdapter* ea, const Info&)
-    {
-        _stickyShifted = ea->getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_SHIFT;
-        
+    {        
         // the 'be nice to Mac / laptop' users option; alt-clicking spins the
         // opposite direction. Should make this configurable
         if ((button == 0) && (ea->getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_ALT)) {
@@ -418,22 +442,61 @@ public:
             return false;
         }
         
-        _repeatTime = -_repeatInterval;    // anti-bobble: delay start of repeat
-        fire(_stickyShifted);
+        _lastFirePos = eventToWindowCoords(ea);
+    // delay start of repeat, makes dragging more usable
+        _repeatTime = -_repeatInterval;    
+        _hasDragged = false;
         return true;
     }
     
-    virtual void buttonReleased(void)
+    virtual void buttonReleased(int keyModState)
     {
+        // for *clicks*, we only fire on button release
+        if (!_hasDragged) {
+           // std::cout << "no drag, firing" << std::endl;
+            fire(keyModState & osgGA::GUIEventAdapter::MODKEY_SHIFT);
+        }
+        
         fireBindingList(_releaseAction);
     }
     
-    virtual void update(double dt)
+    virtual void mouseMoved(const osgGA::GUIEventAdapter* ea)
     {
+        _mousePos = eventToWindowCoords(ea);;
+        osg::Vec2d deltaMouse = _mousePos - _lastFirePos;
+        
+        if (!_hasDragged) {
+            
+            double manhattanDist = deltaMouse.x() * deltaMouse.x()  + deltaMouse.y() * deltaMouse.y();
+            if (manhattanDist < 5) {
+                // don't do anything, just input noise
+                return;
+            }
+            
+        // user is dragging, disable repeat behaviour
+            _hasDragged = true;
+        }
+        double delta = static_knobDragAlternateAxis ? deltaMouse.y() : deltaMouse.x();
+        delta /= _dragScale;
+        if (fabs(delta) >= 1.0) {
+            // determine direction from sign of delta
+            _direction = (delta > 0.0) ? DIRECTION_CLOCKWISE : DIRECTION_ANTICLOCKWISE;
+            fire(ea->getModKeyMask());
+            _lastFirePos = _mousePos;
+        }
+    }
+    
+    virtual void update(double dt, int keyModState)
+    {
+        if (_hasDragged) {
+            return;
+        }
+        
         _repeatTime += dt;
         while (_repeatInterval < _repeatTime) {
             _repeatTime -= _repeatInterval;
-            fire(_stickyShifted);
+            fire(keyModState & osgGA::GUIEventAdapter::MODKEY_SHIFT);
         } // of repeat iteration
     }
 
@@ -486,11 +549,14 @@ private:
     double _repeatInterval;
     double _repeatTime;
     
-    // FIXME - would be better to pass the current modifier state
-    // into update(), but for now let's make it sticky
-    bool _stickyShifted;
+    bool _hasDragged; ///< has the mouse been dragged since the press?
+    osg::Vec2d _mousePos, ///< current window coords location of the mouse
+        _lastFirePos; ///< mouse location where we last fired the bindings
+    double _dragScale;
 };
 
+///////////////////////////////////////////////////////////////////////////////
+
 class SGKnobAnimation::UpdateCallback : public osg::NodeCallback {
 public:
     UpdateCallback(SGExpressiond const* animationValue) :
@@ -535,7 +601,7 @@ SGKnobAnimation::createAnimationGroup(osg::Group& parent)
     transform->setAxis(_axis);
         
     SGSceneUserData* ud = SGSceneUserData::getOrCreateSceneUserData(transform);
-    ud->setPickCallback(new KnobPickCallback(getConfig(), getModelRoot()));
+    ud->setPickCallback(new KnobSliderPickCallback(getConfig(), getModelRoot()));
     
     return transform;
 }
@@ -545,3 +611,56 @@ void SGKnobAnimation::setAlternateMouseWheelDirection(bool aToggle)
     static_knobMouseWheelAlternateDirection = aToggle;
 }
 
+void SGKnobAnimation::setAlternateDragAxis(bool aToggle)
+{
+    static_knobDragAlternateAxis = aToggle;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class SGSliderAnimation::UpdateCallback : public osg::NodeCallback {
+public:
+    UpdateCallback(SGExpressiond const* animationValue) :
+    _animationValue(animationValue)
+    {
+        setName("SGSliderAnimation::UpdateCallback");
+    }
+    virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
+    {
+        SGTranslateTransform* transform = static_cast<SGTranslateTransform*>(node);
+        transform->setValue(_animationValue->getValue());
+
+        traverse(node, nv);
+    }
+    
+private:
+    SGSharedPtr<SGExpressiond const> _animationValue;
+};
+
+
+SGSliderAnimation::SGSliderAnimation(const SGPropertyNode* configNode,
+                                 SGPropertyNode* modelRoot) :
+    SGPickAnimation(configNode, modelRoot)
+{
+    SGSharedPtr<SGExpressiond> value = read_value(configNode, modelRoot, "-m",
+                                                  -SGLimitsd::max(), SGLimitsd::max());
+    _animationValue = value->simplify();
+    
+    _axis = readTranslateAxis(configNode);
+}
+
+osg::Group*
+SGSliderAnimation::createAnimationGroup(osg::Group& parent)
+{
+    SGTranslateTransform* transform = new SGTranslateTransform();
+    innerSetupPickGroup(transform, parent);
+    
+    UpdateCallback* uc = new UpdateCallback(_animationValue);
+    transform->setUpdateCallback(uc);
+    transform->setAxis(_axis);
+    
+    SGSceneUserData* ud = SGSceneUserData::getOrCreateSceneUserData(transform);
+    ud->setPickCallback(new KnobSliderPickCallback(getConfig(), getModelRoot()));
+    
+    return transform;
+}
index bf52078da96df8625bbdad5b3bd9389c2c3e1974..50a7b8d99918fe5c1c9025dfbab034e7ea334f29 100644 (file)
@@ -60,8 +60,14 @@ public:
      * Since no one can agree on that, make it a global toggle.
      */
     static void setAlternateMouseWheelDirection(bool aToggle);
+    
+    /**
+     * by default mouse is dragged left-right to change knobs.
+     * set this to true to default to up-down. Individual knobs
+     * can overrider this,
+     */
+    static void setAlternateDragAxis(bool aToggle);
 private:
-    class KnobPickCallback;
     class UpdateCallback;
     
     SGVec3d _axis;
@@ -69,5 +75,19 @@ private:
     SGSharedPtr<SGExpressiond const> _animationValue;
 };
 
+class SGSliderAnimation : public SGPickAnimation
+{
+public:
+    SGSliderAnimation(const SGPropertyNode* configNode,
+                    SGPropertyNode* modelRoot);
+    virtual osg::Group* createAnimationGroup(osg::Group& parent);
+    
+private:
+    class UpdateCallback;
+    
+    SGVec3d _axis;
+    SGSharedPtr<SGExpressiond const> _animationValue;
+};
+
 #endif // of SG_SCENE_PICK_ANIMATION_HXX
 
index 3561f7ceb2fa6463c74e32151a1f9c418e3c1fbd..962fc78387f2ddd2b0dd5ebeac47545efbb63e0d 100644 (file)
@@ -399,6 +399,9 @@ SGAnimation::animate(osg::Node* node, const SGPropertyNode* configNode,
   } else if (type == "knob") {
     SGKnobAnimation animInst(configNode, modelRoot);
     animInst.apply(node);
+  } else if (type == "slider") {
+    SGSliderAnimation animInst(configNode, modelRoot);
+    animInst.apply(node);
   } else if (type == "range") {
     SGRangeAnimation animInst(configNode, modelRoot);
     animInst.apply(node);
@@ -645,22 +648,7 @@ SGTranslateAnimation::SGTranslateAnimation(const SGPropertyNode* configNode,
   else
     _initialValue = 0;
 
-  if (configNode->hasValue("axis/x1-m")) {
-    SGVec3d v1, v2;
-    v1[0] = configNode->getDoubleValue("axis/x1-m", 0);
-    v1[1] = configNode->getDoubleValue("axis/y1-m", 0);
-    v1[2] = configNode->getDoubleValue("axis/z1-m", 0);
-    v2[0] = configNode->getDoubleValue("axis/x2-m", 0);
-    v2[1] = configNode->getDoubleValue("axis/y2-m", 0);
-    v2[2] = configNode->getDoubleValue("axis/z2-m", 0);
-    _axis = v2 - v1;
-  } else {
-    _axis[0] = configNode->getDoubleValue("axis/x", 0);
-    _axis[1] = configNode->getDoubleValue("axis/y", 0);
-    _axis[2] = configNode->getDoubleValue("axis/z", 0);
-  }
-  if (8*SGLimitsd::min() < norm(_axis))
-    _axis = normalize(_axis);
+  _axis = readTranslateAxis(configNode);
 }
 
 osg::Group*
@@ -876,6 +864,30 @@ void readRotationCenterAndAxis(const SGPropertyNode* configNode, SGVec3d& center
     center[2] = configNode->getDoubleValue("center/z-m", center[2]);
 }
 
+SGVec3d readTranslateAxis(const SGPropertyNode* configNode)
+{
+    SGVec3d axis;
+    
+    if (configNode->hasValue("axis/x1-m")) {
+        SGVec3d v1, v2;
+        v1[0] = configNode->getDoubleValue("axis/x1-m", 0);
+        v1[1] = configNode->getDoubleValue("axis/y1-m", 0);
+        v1[2] = configNode->getDoubleValue("axis/z1-m", 0);
+        v2[0] = configNode->getDoubleValue("axis/x2-m", 0);
+        v2[1] = configNode->getDoubleValue("axis/y2-m", 0);
+        v2[2] = configNode->getDoubleValue("axis/z2-m", 0);
+        axis = v2 - v1;
+    } else {
+        axis[0] = configNode->getDoubleValue("axis/x", 0);
+        axis[1] = configNode->getDoubleValue("axis/y", 0);
+        axis[2] = configNode->getDoubleValue("axis/z", 0);
+    }
+    if (8*SGLimitsd::min() < norm(axis))
+        axis = normalize(axis);
+
+    return axis;
+}
+
 SGRotateAnimation::SGRotateAnimation(const SGPropertyNode* configNode,
                                      SGPropertyNode* modelRoot) :
   SGAnimation(configNode, modelRoot)
index 2bcf49ae57214020839b3963231fbb3496d4d477..e4d573001ceec617be2a17b4ac8a87d4fe5e29db 100644 (file)
@@ -36,6 +36,7 @@ read_value(const SGPropertyNode* configNode, SGPropertyNode* modelRoot,
            const char* unit, double defMin, double defMax);
 
 void readRotationCenterAndAxis(const SGPropertyNode* configNode, SGVec3d& center, SGVec3d& axis);
+SGVec3d readTranslateAxis(const SGPropertyNode* configNode);
 
 //////////////////////////////////////////////////////////////////////
 // Base class for animation installers
index 6744337c9859360937388c15233b144982dfb794..5e2085db4e9d1862753e86d9405cb77755eae239 100644 (file)
@@ -54,9 +54,10 @@ public:
   virtual bool buttonPressed(int button, const osgGA::GUIEventAdapter* event, const Info& info)
   { return false; }
   
-  virtual void update(double dt)
+  virtual void update(double dt, int keyModState)
   { }
-  virtual void buttonReleased(void)
+    
+  virtual void buttonReleased(int keyModState)
   { }
 
   virtual void mouseMoved(const osgGA::GUIEventAdapter* event)