From e8156c6bd9fdb94e2438db9f836881784df16f75 Mon Sep 17 00:00:00 2001 From: James Turner Date: Sun, 3 Feb 2013 16:33:30 +0000 Subject: [PATCH] Knob animation: shifted mode binding. As part of this, pass the osgGA GUIEventAdapter down into the pick callbacks, which seems reasonable to me. If anyone can foresee issues with this, please let me know and I can adjust the API. --- simgear/scene/model/SGPickAnimation.cxx | 82 ++++++++++++++++++++----- simgear/scene/util/SGPickCallback.hxx | 4 +- 2 files changed, 70 insertions(+), 16 deletions(-) diff --git a/simgear/scene/model/SGPickAnimation.cxx b/simgear/scene/model/SGPickAnimation.cxx index 6b6e9c9a..19111b24 100644 --- a/simgear/scene/model/SGPickAnimation.cxx +++ b/simgear/scene/model/SGPickAnimation.cxx @@ -26,7 +26,8 @@ #include #include #include - +#include + #include #include #include @@ -66,7 +67,7 @@ using OpenThreads::ScopedLock; _bindingsUp.push_back(new SGBinding(bindings[i], modelRoot)); } } - virtual bool buttonPressed(int button, const Info&) + virtual bool buttonPressed(int button, const osgGA::GUIEventAdapter* ea, const Info&) { bool found = false; for( std::vector::iterator it = _buttons.begin(); it != _buttons.end(); ++it ) { @@ -206,7 +207,7 @@ using OpenThreads::ScopedLock; _squaredDown = dot(_toDown, _toDown); } - virtual bool buttonPressed(int button, const Info& info) + virtual bool buttonPressed(int button, const osgGA::GUIEventAdapter* ea, const Info& info) { SGVec3d loc(info.local); SG_LOG(SG_INPUT, SG_DEBUG, "VNC pressed " << button << ": " << loc); @@ -340,12 +341,24 @@ SGPickAnimation::innerSetupPickGroup(osg::Group* commonGroup, osg::Group& parent /////////////////////////////////////////////////////////////////////////// +// insert count copies of binding list A, into the output list. +// effectively makes the output list fire binding A multiple times +// in sequence +static void repeatBindings(const SGBindingList& a, SGBindingList& out, int count) +{ + out.clear(); + for (int i=0; igetDoubleValue("interval-sec", 0.1)) + _repeatInterval(configNode->getDoubleValue("interval-sec", 0.1)), + _stickyShifted(false) { const SGPropertyNode* act = configNode->getChild("action"); if (act) @@ -358,10 +371,41 @@ public: const SGPropertyNode* ccw = configNode->getChild("ccw"); if (ccw) _bindingsCCW = readBindingList(ccw->getChildren("binding"), modelRoot); + + if (configNode->hasChild("shift-action") || configNode->hasChild("shift-cw") || + configNode->hasChild("shift-ccw")) + { + // explicit shifted behaviour - just do exactly what was provided + const SGPropertyNode* act = configNode->getChild("shift-action"); + if (act) + _shiftedAction = readBindingList(act->getChildren("binding"), modelRoot); + + const SGPropertyNode* cw = configNode->getChild("shift-cw"); + if (cw) + _shiftedCW = readBindingList(cw->getChildren("binding"), modelRoot); + + const SGPropertyNode* ccw = configNode->getChild("shift-ccw"); + if (ccw) + _shiftedCCW = readBindingList(ccw->getChildren("binding"), modelRoot); + } else { + // default shifted behaviour - repeat normal bindings N times. + int shiftRepeat = configNode->getIntValue("shift-repeat", 10); + repeatBindings(_action, _shiftedAction, shiftRepeat); + repeatBindings(_bindingsCW, _shiftedCW, shiftRepeat); + repeatBindings(_bindingsCCW, _shiftedCCW, shiftRepeat); + } // of default shifted behaviour } - virtual bool buttonPressed(int button, const Info&) + 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)) { + button = 1; + } + _direction = DIRECTION_NONE; if ((button == 0) || (button == 4)) { _direction = DIRECTION_CLOCKWISE; @@ -372,7 +416,7 @@ public: } _repeatTime = -_repeatInterval; // anti-bobble: delay start of repeat - fire(); + fire(_stickyShifted); return true; } @@ -385,28 +429,32 @@ public: _repeatTime += dt; while (_repeatInterval < _repeatTime) { _repeatTime -= _repeatInterval; - fire(); + fire(_stickyShifted); } // of repeat iteration } private: - void fire() + void fire(bool isShifted) { + const SGBindingList& act(isShifted ? _shiftedAction : _action); + const SGBindingList& cw(isShifted ? _shiftedCW : _bindingsCW); + const SGBindingList& ccw(isShifted ? _shiftedCCW : _bindingsCCW); + switch (_direction) { case DIRECTION_CLOCKWISE: - fireBindingListWithOffset(_action, 1, 1); - fireBindingList(_bindingsCW); + fireBindingListWithOffset(act, 1, 1); + fireBindingList(cw); break; case DIRECTION_ANTICLOCKWISE: - fireBindingListWithOffset(_action, -1, 1); - fireBindingList(_bindingsCCW); + fireBindingListWithOffset(act, -1, 1); + fireBindingList(ccw); break; default: break; } } - SGBindingList _action; - SGBindingList _bindingsCW, - _bindingsCCW; + SGBindingList _action, _shiftedAction; + SGBindingList _bindingsCW, _shiftedCW, + _bindingsCCW, _shiftedCCW; enum Direction { @@ -418,6 +466,10 @@ private: Direction _direction; 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; }; class SGKnobAnimation::UpdateCallback : public osg::NodeCallback { diff --git a/simgear/scene/util/SGPickCallback.hxx b/simgear/scene/util/SGPickCallback.hxx index 90b720f8..e8a63ee2 100644 --- a/simgear/scene/util/SGPickCallback.hxx +++ b/simgear/scene/util/SGPickCallback.hxx @@ -26,6 +26,8 @@ #include #include +namespace osgGA { class GUIEventAdapter; } + // Used to implement scenery interaction. // The interface is still under development class SGPickCallback : public SGReferenced { @@ -46,7 +48,7 @@ public: { } virtual ~SGPickCallback() {} - virtual bool buttonPressed(int button, const Info& info) + virtual bool buttonPressed(int button, const osgGA::GUIEventAdapter* event, const Info& info) { return false; } virtual void update(double dt) { } -- 2.39.5