1 /**************************************************************************\
2  * Copyright (c) Kongsberg Oil & Gas Technologies AS
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * Neither the name of the copyright holder nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32 
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif // HAVE_CONFIG_H
36 
37 #ifdef HAVE_DRAGGERS
38 
39 /*!
40   \class SoDragger SoDragger.h Inventor/draggers/SoDragger.h
41   \brief The SoDragger class is the base class for all draggers.
42 
43   \ingroup draggers
44 
45   Draggers is a mechanism used for letting the end-users of your
46   application code interact with elements in 3D, by scaling, rotating
47   or translating geometry or other instances in the scene (like
48   cameras or light sources).
49 
50   For a very thorough introduction and tutorial to the dragger classes
51   and general concepts, we advise you to consult «The Inventor
52   Mentor», ISBN 0-201-62495-8, chapter 15.
53 
54   This is the common superclass for all dragger classes.
55 
56   It holds the current motion matrix, and offers lots of convenience
57   methods to build from for it's subclasses -- that is, the
58   non-abstract dragger classes to use as nodes in your scenegraph.
59 
60   The motion matrix is used to modify the model matrix during
61   traversal, and this is a common dragger mechanism -- all draggers
62   should update this during dragging.
63 
64   A number of the Coin dragger classes have built-in convenience
65   wrapper classes, called \e manipulators. See for instance the
66   SoTrackballDragger / SoTrackballManip pair.
67 
68   The matching manipulator class for any dragger class has basically
69   two convenient additions to the functionality of the stand-alone
70   dragger: 1) it makes swapping the dragger in and out of the
71   scenegraph very straightforward (something which is often done for
72   draggers in 3D user interfaces), 2) it wraps up the dragger with
73   SoSurroundScale and SoAntiSquish nodes where applicable, so the
74   dragger geometry automatically scales up or down to match the
75   geometry it influences.
76 
77   This last functionality can also be duplicated in a rather
78   straightforward manner outside of the context of a manipulator, as
79   can be seen from the usage example in the SoSurroundScale class
80   documentation.
81 
82   The appearance of draggers can be modified by either using the
83   SoDragger::setPart() method (see usage example below) or by setting
84   up external Inventor-format files which the geometry parts are read
85   from. The latter method can be done by setting the environment
86   variable \c SO_DRAGGER_DIR to point to a directory with replacement
87   geometry files. The name of the new files and the name of the nodes
88   / sub-graphs with the replacement geometries must follow a rigid
89   scheme. We advise you to look at the Coin sourcecode directory
90   Coin/data/draggerDefaults/ to see how the replacement geometry files
91   should be named. Setting \c SO_DRAGGER_DIR to this directory and
92   modifying the files there provides a convenient way to play around
93   with new dragger geometry arrangements.
94 
95 
96   As mentioned above, SoDragger::setPart() can be used to modify the
97   appearance of a dragger by changing it's default geometry. One
98   common technique is for instance to take advantage of this to use
99   only \e parts of a dragger, by replacing / disabling the geometry
100   that you don't want the end-user to interact with. The following
101   code example shows how to remove the translation functionality of
102   the SoTransformBoxDragger:
103 
104   \code
105   #include <Inventor/Qt/SoQt.h>
106   #include <Inventor/Qt/viewers/SoQtExaminerViewer.h>
107   #include <Inventor/draggers/SoTransformBoxDragger.h>
108   #include <Inventor/nodes/SoSeparator.h>
109 
110   int
111   main(int argc, char ** argv)
112   {
113     QWidget * window = SoQt::init(argv[0]);
114 
115     SoTransformBoxDragger * dragger = new SoTransformBoxDragger;
116 
117     SbString str;
118     for (int i = 1; i <= 6; i++) {
119       str.sprintf("translator%d.translator", i);
120       dragger->setPart(str.getString(), new SoSeparator);
121     }
122 
123     SoQtExaminerViewer * viewer = new SoQtExaminerViewer(window);
124     viewer->setSceneGraph(dragger);
125     viewer->show();
126     SoQt::show(window);
127 
128     SoQt::mainLoop();
129 
130     delete viewer;
131     return 0;
132   }
133   \endcode
134 
135   Draggers are also node kits, and below is the catalog structure for
136   this top-level dragger class.
137 
138   \NODEKIT_PRE_DIAGRAM
139 
140   \verbatim
141   CLASS SoDragger
142   -->"this"
143         "callbackList"
144         "topSeparator"
145   -->      "motionMatrix"
146            "geomSeparator"
147   \endverbatim
148 
149   \NODEKIT_POST_DIAGRAM
150 
151 
152   \NODEKIT_PRE_TABLE
153 
154   \verbatim
155   CLASS SoDragger
156   PVT   "this",  SoDragger  ---
157         "callbackList",  SoNodeKitListPart [ SoCallback, SoEventCallback ]
158   PVT   "topSeparator",  SoSeparator  ---
159   PVT   "motionMatrix",  SoMatrixTransform  ---
160   PVT   "geomSeparator",  SoSeparator  ---
161   \endverbatim
162 
163   \NODEKIT_POST_TABLE
164 */
165 
166 //   FIXME: more class doc! The general concept of draggers should be
167 //   explained in more detail here -- just refering to the Inventor
168 //   Mentor is a cop-out. And include at least one general usage example
169 //   and some screenshots.  20011219 mortene.
170 
171 
172 /*!
173   \var SoSFBool SoDragger::isActive
174   Is \c TRUE whenever the user is interacting with the dragger. For
175   compound draggers (draggers consisting of one or more subdraggers),
176   the isActive field is updated only for the active subdragger, not
177   for the compound dragger.
178 */
179 
180 /*!
181   \enum SoDragger::ProjectorFrontSetting
182 
183   Holds various settings for projectors, which might affect
184   cylindrical and spherical based draggers.  Specifies whether
185   dragging should be based on the front or back of the sphere /
186   cylinder, or if the picked point should be used to decide this.
187 */
188 
189 /*!
190   \var SoDragger::ProjectorFrontSetting SoDragger::FRONT
191   Always use front of projector.
192 */
193 
194 /*!
195   \var SoDragger::ProjectorFrontSetting SoDragger::BACK
196   Always use back of projector.
197 */
198 
199 /*!
200   \var SoDragger::ProjectorFrontSetting SoDragger::USE_PICK
201   Use picked point to decide front or back of projector.
202 */
203 
204 // FIXME: document DraggerCB typedef? 20010909 mortene.
205 
206 /*! \file SoDragger.h */
207 #include <Inventor/draggers/SoDragger.h>
208 
209 #include <Inventor/draggers/SoCenterballDragger.h>
210 #include <Inventor/draggers/SoDirectionalLightDragger.h>
211 #include <Inventor/draggers/SoDragPointDragger.h>
212 #include <Inventor/draggers/SoHandleBoxDragger.h>
213 #include <Inventor/draggers/SoJackDragger.h>
214 #include <Inventor/draggers/SoPointLightDragger.h>
215 #include <Inventor/draggers/SoRotateCylindricalDragger.h>
216 #include <Inventor/draggers/SoRotateDiscDragger.h>
217 #include <Inventor/draggers/SoRotateSphericalDragger.h>
218 #include <Inventor/draggers/SoScale1Dragger.h>
219 #include <Inventor/draggers/SoScale2Dragger.h>
220 #include <Inventor/draggers/SoScale2UniformDragger.h>
221 #include <Inventor/draggers/SoScaleUniformDragger.h>
222 #include <Inventor/draggers/SoSpotLightDragger.h>
223 #include <Inventor/draggers/SoTabBoxDragger.h>
224 #include <Inventor/draggers/SoTabPlaneDragger.h>
225 #include <Inventor/draggers/SoTrackballDragger.h>
226 #include <Inventor/draggers/SoTransformBoxDragger.h>
227 #include <Inventor/draggers/SoTransformerDragger.h>
228 #include <Inventor/draggers/SoTranslate1Dragger.h>
229 #include <Inventor/draggers/SoTranslate2Dragger.h>
230 #include <Inventor/actions/SoHandleEventAction.h>
231 #include <Inventor/actions/SoRayPickAction.h>
232 #include <Inventor/actions/SoGetMatrixAction.h>
233 #include <Inventor/events/SoMouseButtonEvent.h>
234 #include <Inventor/events/SoLocation2Event.h>
235 #include <Inventor/events/SoKeyboardEvent.h>
236 #include <Inventor/elements/SoViewVolumeElement.h>
237 #include <Inventor/elements/SoViewportRegionElement.h>
238 
239 #include <Inventor/actions/SoGLRenderAction.h>
240 #include <Inventor/actions/SoCallbackAction.h>
241 #include <Inventor/actions/SoRayPickAction.h>
242 #include <Inventor/actions/SoGetPrimitiveCountAction.h>
243 
244 #include <Inventor/elements/SoMultiTextureEnabledElement.h>
245 #include <Inventor/elements/SoShapeHintsElement.h>
246 #include <Inventor/elements/SoNormalBindingElement.h>
247 #include <Inventor/elements/SoMaterialBindingElement.h>
248 #include <Inventor/elements/SoLazyElement.h>
249 #include <Inventor/elements/SoNormalElement.h>
250 #include <Inventor/elements/SoLineWidthElement.h>
251 #include <Inventor/elements/SoLinePatternElement.h>
252 #include <Inventor/elements/SoCreaseAngleElement.h>
253 #include <Inventor/elements/SoComplexityElement.h>
254 #include <Inventor/elements/SoComplexityTypeElement.h>
255 #include <Inventor/nodes/SoCamera.h>
256 
257 #include <Inventor/SbViewportRegion.h>
258 #include <Inventor/nodes/SoMatrixTransform.h>
259 #include <Inventor/SoNodeKitPath.h>
260 #include <Inventor/SoPickedPoint.h>
261 
262 #include <Inventor/errors/SoDebugError.h>
263 
264 #include "coindefs.h" // COIN_OBSOLETED
265 #include "tidbitsp.h"
266 #include "nodekits/SoSubKitP.h"
267 #include "SbBasicP.h"
268 
269 // Internal helper class.
270 class SoDraggerCache {
271 public:
SoDraggerCache(SoDragger * parent)272   SoDraggerCache(SoDragger * parent) :
273     path(reclassify_cast<SoFullPath *>(new SoPath(4))),
274     dragger(parent),
275     matrixAction(new SoGetMatrixAction(dragger->getViewportRegion())),
276     draggerToWorld(SbMatrix::identity()),
277     worldToDragger(SbMatrix::identity())
278   {
279     this->path->ref();
280   }
281 
~SoDraggerCache()282   ~SoDraggerCache() {
283     delete this->matrixAction;
284     this->path->unref();
285   }
286 
updateMatrix(void)287   void updateMatrix(void) {
288     this->matrixAction->setViewportRegion(this->dragger->getViewportRegion());
289     this->matrixAction->apply(this->path);
290     this->draggerToWorld = this->matrixAction->getMatrix();
291     this->worldToDragger = this->matrixAction->getInverse();
292   }
293 
update(const SoFullPath * newpath,const int draggeridx)294   void update(const SoFullPath * newpath, const int draggeridx) {
295     this->path->setHead(newpath->getHead());
296     for (int i = 1; i <= draggeridx; i++) {
297       this->path->append(newpath->getIndex(i));
298     }
299     this->updateMatrix();
300   }
301 
truncatePath(void)302   void truncatePath(void) {
303     this->path->truncate(0);
304   }
305 
306   SoFullPath * path;
307   SoDragger * dragger; // pointer to cache owner
308   SoGetMatrixAction * matrixAction; // avoid reallocating this action each frame
309   SbMatrix draggerToWorld;
310   SbMatrix worldToDragger;
311 };
312 
313 class SoDraggerP {
314 public:
315   int mingesture;
316   SoHandleEventAction * eventaction;
317   SoDragger::ProjectorFrontSetting frontonprojector;
318   SbBool valuechangedcbenabled;
319   SbBool ignoreinbbox;
320   const SoEvent * currentevent;
321   SoPath * pickedpath;
322   SoDraggerCache * draggercache;
323   SbBool didmousemove;
324 
325   SoCallbackList startCB;
326   SoCallbackList motionCB;
327   SoCallbackList finishCB;
328   SoCallbackList valueChangedCB;
329   SoCallbackList otherEventCB;
330   SbMatrix startmotionmatrix;
331   SbVec3f startingpoint;
332   SbViewVolume viewvolume;
333   SbViewportRegion viewport;
334   SbVec2s startlocaterpos;
335   SoDragger * activechilddragger;
336   SbBool isgrabbing;
337 
338   SbName surrogatename;
339   SoPath * surrogateownerpath;
340   SoPath * surrogatepath;
341 
342   SoCallbackAction * cbaction;
343   float projectorepsilon;
344 };
345 
346 #define PRIVATE(obj) ((obj)->pimpl)
347 
348 SO_KIT_SOURCE(SoDragger);
349 
350 float SoDragger::minscale = 0.001f;
351 
352 /*!
353   A protected constructor for this abstract superclass for all Coin
354   draggers.
355 */
SoDragger(void)356 SoDragger::SoDragger(void)
357 {
358   SO_KIT_INTERNAL_CONSTRUCTOR(SoDragger);
359 
360   SO_KIT_ADD_CATALOG_ENTRY(motionMatrix, SoMatrixTransform, FALSE, topSeparator, geomSeparator, FALSE);
361 
362   SO_KIT_ADD_FIELD(isActive, (FALSE));
363 
364   SO_KIT_INIT_INSTANCE();
365 
366   PRIVATE(this)->mingesture = 8;
367   PRIVATE(this)->eventaction = NULL;
368   PRIVATE(this)->frontonprojector = USE_PICK;
369   PRIVATE(this)->valuechangedcbenabled = TRUE;
370   PRIVATE(this)->ignoreinbbox = FALSE;
371   PRIVATE(this)->currentevent = NULL;
372   PRIVATE(this)->pickedpath = NULL;
373   PRIVATE(this)->draggercache = NULL;
374   PRIVATE(this)->isgrabbing = FALSE;
375   PRIVATE(this)->activechilddragger = NULL;
376   PRIVATE(this)->surrogateownerpath = NULL;
377   PRIVATE(this)->surrogatepath = NULL;
378   PRIVATE(this)->cbaction = NULL;
379   PRIVATE(this)->didmousemove = FALSE;
380   PRIVATE(this)->projectorepsilon = 0.0f;
381 }
382 
383 /*!
384   Virtual protected destructor.
385 */
~SoDragger()386 SoDragger::~SoDragger()
387 {
388   if (PRIVATE(this)->isgrabbing)
389     this->grabEventsCleanup();
390   if (PRIVATE(this)->pickedpath)
391     PRIVATE(this)->pickedpath->unref();
392   if (PRIVATE(this)->surrogateownerpath)
393     PRIVATE(this)->surrogateownerpath->unref();
394   if (PRIVATE(this)->surrogatepath)
395     PRIVATE(this)->surrogatepath->unref();
396   delete PRIVATE(this)->draggercache;
397   delete PRIVATE(this)->cbaction;
398 }
399 
400 // Note: the following documentation for initClass() will also be used
401 // for dragger subclasses, so keep it general.
402 /*!
403   Initializes type system for this dragger class.
404 
405   Application programmers should usually not have to invoke this
406   method, see documentation of SoInteraction::init().
407 */
408 void
initClass(void)409 SoDragger::initClass(void)
410 {
411   SO_KIT_INTERNAL_INIT_CLASS(SoDragger, SO_FROM_INVENTOR_1);
412   SoDragger::minscale = 0.001f;
413 
414   SoDragger::initClasses();
415 
416   SoType type = SoDragger::getClassTypeId();
417   SoRayPickAction::addMethod(type, SoNode::rayPickS);
418 }
419 
420 /*!
421   Initializes all built-in draggers.
422 */
423 void
initClasses(void)424 SoDragger::initClasses(void)
425 {
426   SoCenterballDragger::initClass();
427   SoDirectionalLightDragger::initClass();
428   SoDragPointDragger::initClass();
429   SoHandleBoxDragger::initClass();
430   SoJackDragger::initClass();
431   SoPointLightDragger::initClass();
432   SoRotateCylindricalDragger::initClass();
433   SoRotateDiscDragger::initClass();
434   SoRotateSphericalDragger::initClass();
435   SoScale1Dragger::initClass();
436   SoScale2Dragger::initClass();
437   SoScale2UniformDragger::initClass();
438   SoScaleUniformDragger::initClass();
439   SoSpotLightDragger::initClass();
440   SoTabBoxDragger::initClass();
441   SoTabPlaneDragger::initClass();
442   SoTrackballDragger::initClass();
443   SoTransformBoxDragger::initClass();
444   SoTransformerDragger::initClass();
445   SoTranslate1Dragger::initClass();
446   SoTranslate2Dragger::initClass();
447 }
448 
449 // Private method that sets some elements to default (for our
450 // draggers) values.
451 void
updateElements(SoState * state)452 SoDragger::updateElements(SoState * state)
453 {
454   if (state->isElementEnabled(SoShapeHintsElement::getClassStackIndex())) {
455     // turn on backface culling for draggers
456     SoShapeHintsElement::set(state, this,
457                              SoShapeHintsElement::COUNTERCLOCKWISE,
458                              SoShapeHintsElement::SOLID,
459                              SoShapeHintsElement::CONVEX);
460   }
461   if (state->isElementEnabled(SoMultiTextureEnabledElement::getClassStackIndex())) {
462     SoMultiTextureEnabledElement::disableAll(state);
463   }
464   if (state->isElementEnabled(SoNormalBindingElement::getClassStackIndex())) {
465     // make default
466     SoNormalBindingElement::set(state, SoNormalBindingElement::DEFAULT);
467   }
468   if (state->isElementEnabled(SoMaterialBindingElement::getClassStackIndex())) {
469     // make default
470     SoMaterialBindingElement::set(state, SoMaterialBindingElement::DEFAULT);
471   }
472   if (state->isElementEnabled(SoLazyElement::getClassStackIndex())) {
473     // we need phong shading for our geometry
474     SoLazyElement::setLightModel(state, SoLazyElement::PHONG);
475   }
476 
477   if (state->isElementEnabled(SoNormalElement::getClassStackIndex())) {
478     // lines/shapes will use normals if on state. We don't want that.
479     SoNormalElement::set(state, this, 0, NULL);
480   }
481   if (state->isElementEnabled(SoLineWidthElement::getClassStackIndex())) {
482     // make default
483     SoLineWidthElement::set(state, this, SoLineWidthElement::getDefault());
484   }
485   if (state->isElementEnabled(SoLinePatternElement::getClassStackIndex())) {
486     // make default
487     SoLinePatternElement::set(state, this, SoLinePatternElement::getDefault());
488   }
489   if (state->isElementEnabled(SoCreaseAngleElement::getClassStackIndex())) {
490     // set to 0.5, which is the value we like
491     SoCreaseAngleElement::set(state, this, 0.5f);
492   }
493   if (state->isElementEnabled(SoComplexityElement::getClassStackIndex())) {
494     // make default
495     SoComplexityElement::set(state, this, SoComplexityElement::getDefault());
496   }
497   if (state->isElementEnabled(SoComplexityTypeElement::getClassStackIndex())) {
498     // make default
499     SoComplexityTypeElement::set(state, this, SoComplexityTypeElement::getDefault());
500   }
501   // hopefully we didn't forget something...
502 }
503 
504 // The action methods are overridden in case we decide to do some
505 // extra work before passing the control on the SoBaseKit.
506 
507 // Doc in superclass. Overridden to initialize some elements before
508 // traversing children.
509 void
callback(SoCallbackAction * action)510 SoDragger::callback(SoCallbackAction * action)
511 {
512   SoState * state = action->getState();
513   state->push();
514   inherited::callback(action);
515   state->pop();
516 }
517 
518 // Doc in superclass. Overridden to initialize some elements before
519 // traversing children.
520 void
GLRender(SoGLRenderAction * action)521 SoDragger::GLRender(SoGLRenderAction * action)
522 {
523   SoState * state = action->getState();
524   state->push();
525   this->updateElements(state);
526   inherited::GLRender(action);
527   state->pop();
528 }
529 
530 // Doc in superclass. Overridden to initialize some elements before
531 // traversing children.
532 void
getMatrix(SoGetMatrixAction * action)533 SoDragger::getMatrix(SoGetMatrixAction * action)
534 {
535   // no need to update any elements here
536   inherited::getMatrix(action);
537 }
538 
539 // Doc in superclass. Overridden to initialize some elements before
540 // traversing children.
541 void
rayPick(SoRayPickAction * action)542 SoDragger::rayPick(SoRayPickAction * action)
543 {
544   SoState * state = action->getState();
545   state->push();
546   this->updateElements(state);
547   inherited::rayPick(action);
548   state->pop();
549 }
550 
551 // Doc in superclass. Overridden to initialize some elements before
552 // traversing children.
553 void
search(SoSearchAction * action)554 SoDragger::search(SoSearchAction * action)
555 {
556   // no need to update any elements here
557   inherited::search(action);
558 }
559 
560 // Doc in superclass. Overridden to initialize some elements before
561 // traversing children.
562 void
write(SoWriteAction * action)563 SoDragger::write(SoWriteAction * action)
564 {
565   // no need to update any elements here
566   inherited::write(action);
567 }
568 
569 // Doc in superclass. Overridden to initialize some elements before
570 // traversing children.
571 void
getPrimitiveCount(SoGetPrimitiveCountAction * action)572 SoDragger::getPrimitiveCount(SoGetPrimitiveCountAction * action)
573 {
574   SoState * state = action->getState();
575   state->push();
576   this->updateElements(state);
577   inherited::getPrimitiveCount(action);
578   state->pop();
579 }
580 
581 /*!
582   Sets the epsilon used for restricting the draggers when the
583   intersection line is almost parallel with the projector direction.
584 
585   For line projectors this is based on the dot product between the
586   picking ray and the projector line. For plane projector, the dot
587   product between the plane normal and the picking ray is used.
588 
589   Default value is 0.0.
590 
591   \since Coin 3.0
592 */
593 void
setProjectorEpsilon(const float epsilon)594 SoDragger::setProjectorEpsilon(const float epsilon)
595 {
596   PRIVATE(this)->projectorepsilon = epsilon;
597 }
598 
599 /*
600   Returns the projector epsilon set for this dragger.
601 
602   \since Coin 3.0
603 */
604 float
getProjectorEpsilon(void) const605 SoDragger::getProjectorEpsilon(void) const
606 {
607   return PRIVATE(this)->projectorepsilon;
608 }
609 
610 /*!
611   Adds a callback which is called at the start of a drag, after the
612   mouse button 1 is pressed, and dragger is picked.
613 */
614 void
addStartCallback(SoDraggerCB * func,void * data)615 SoDragger::addStartCallback(SoDraggerCB * func, void * data)
616 {
617   PRIVATE(this)->startCB.addCallback(reinterpret_cast<SoCallbackListCB *>(func), data);
618 }
619 
620 /*!
621   Removes a previously registered start callback.
622 
623   \sa addStartCallback()
624 */
625 void
removeStartCallback(SoDraggerCB * func,void * data)626 SoDragger::removeStartCallback(SoDraggerCB * func, void * data)
627 {
628   PRIVATE(this)->startCB.removeCallback(reinterpret_cast<SoCallbackListCB *>(func), data);
629 }
630 
631 /*!
632   Adds a callback which is called for each mouse movement during
633   dragging.
634 */
635 void
addMotionCallback(SoDraggerCB * func,void * data)636 SoDragger::addMotionCallback(SoDraggerCB * func, void * data)
637 {
638   PRIVATE(this)->motionCB.addCallback(reinterpret_cast<SoCallbackListCB *>(func), data);
639 }
640 
641 /*!
642   Removes a previously registered motion callback.
643 
644   \sa addMotionCallback()
645 */
646 void
removeMotionCallback(SoDraggerCB * func,void * data)647 SoDragger::removeMotionCallback(SoDraggerCB * func, void * data)
648 {
649   PRIVATE(this)->motionCB.removeCallback(reinterpret_cast<SoCallbackListCB *>(func), data);
650 }
651 
652 /*!
653   Adds a callback which is called after dragging is finished.
654 */
655 void
addFinishCallback(SoDraggerCB * func,void * data)656 SoDragger::addFinishCallback(SoDraggerCB * func, void * data)
657 {
658   PRIVATE(this)->finishCB.addCallback(reinterpret_cast<SoCallbackListCB *>(func), data);
659 }
660 
661 /*!
662   Removes a finish callback.
663 
664   \sa addFinishCallback()
665 */
666 void
removeFinishCallback(SoDraggerCB * func,void * data)667 SoDragger::removeFinishCallback(SoDraggerCB * func, void * data)
668 {
669   PRIVATE(this)->finishCB.removeCallback(reinterpret_cast<SoCallbackListCB *>(func), data);
670 }
671 
672 /*!
673   Adds a callback which is called after a dragger has changed a field.
674   It is not called if the SoDragger::isActive field is changed.
675 
676   \sa enableValueChangedCallback()
677 */
678 void
addValueChangedCallback(SoDraggerCB * func,void * data)679 SoDragger::addValueChangedCallback(SoDraggerCB * func, void * data)
680 {
681   PRIVATE(this)->valueChangedCB.addCallback(reinterpret_cast<SoCallbackListCB *>(func), data);
682 }
683 
684 /*!
685   Removes a value changed callback.
686 
687   \sa addValueChangedCallback()
688 */
689 void
removeValueChangedCallback(SoDraggerCB * func,void * data)690 SoDragger::removeValueChangedCallback(SoDraggerCB * func, void * data)
691 {
692   PRIVATE(this)->valueChangedCB.removeCallback(reinterpret_cast<SoCallbackListCB *>(func), data);
693 }
694 
695 /*!
696   Sets the number of pixel movement needed to trigger a constraint
697   gesture.  Default is 8 pixels.
698 */
699 void
setMinGesture(int pixels)700 SoDragger::setMinGesture(int pixels)
701 {
702   PRIVATE(this)->mingesture = pixels;
703 }
704 
705 /*!
706   Returns the gesture pixels threshold value.
707 
708   \sa setMinGesture()
709 */
710 int
getMinGesture(void) const711 SoDragger::getMinGesture(void) const
712 {
713   return PRIVATE(this)->mingesture;
714 }
715 
716 /*!
717   Enable or disable "value changed" callbacks.
718 
719   \sa addValueChangedCallback()
720 */
721 SbBool
enableValueChangedCallbacks(SbBool val)722 SoDragger::enableValueChangedCallbacks(SbBool val)
723 {
724   SbBool oldval = PRIVATE(this)->valuechangedcbenabled;
725   PRIVATE(this)->valuechangedcbenabled = val;
726   return oldval;
727 }
728 
729 /*!
730   Returns the motion matrix for this dragger.
731 */
732 const SbMatrix &
getMotionMatrix(void)733 SoDragger::getMotionMatrix(void)
734 {
735   SoMatrixTransform * node =
736     SO_GET_ANY_PART(this, "motionMatrix", SoMatrixTransform);
737   assert(node);
738   return node->matrix.getValue();
739 }
740 
741 /*!
742   Adds an event callback for events other then drag events.  As soon
743   as dragging starts, the dragger grabs all events (until mouse button
744   is released). This method can be used to handle other events during
745   dragging.
746 */
747 void
addOtherEventCallback(SoDraggerCB * func,void * data)748 SoDragger::addOtherEventCallback(SoDraggerCB * func, void * data)
749 {
750   PRIVATE(this)->otherEventCB.addCallback(reinterpret_cast<SoCallbackListCB *>(func), data);
751 }
752 
753 /*!
754   Removes a other event callback.
755 
756   \sa addOtherEventCallback()
757 */
758 void
removeOtherEventCallback(SoDraggerCB * func,void * data)759 SoDragger::removeOtherEventCallback(SoDraggerCB * func, void * data)
760 {
761   PRIVATE(this)->otherEventCB.removeCallback(reinterpret_cast<SoCallbackListCB *>(func), data);
762 }
763 
764 /*!
765   Should be called by compound draggers to register child draggers.
766 */
767 void
registerChildDragger(SoDragger * child)768 SoDragger::registerChildDragger(SoDragger * child)
769 {
770   child->addStartCallback(SoDragger::childStartCB, this);
771   child->addMotionCallback(SoDragger::childMotionCB, this);
772   child->addFinishCallback(SoDragger::childFinishCB, this);
773   child->addOtherEventCallback(SoDragger::childOtherEventCB, this);
774   child->addValueChangedCallback(SoDragger::childTransferMotionAndValueChangedCB, this);
775 }
776 
777 /*!
778   Should be called by compound draggers to unregister child draggers.
779 */
780 void
unregisterChildDragger(SoDragger * child)781 SoDragger::unregisterChildDragger(SoDragger * child)
782 {
783   child->removeStartCallback(SoDragger::childStartCB, this);
784   child->removeMotionCallback(SoDragger::childMotionCB, this);
785   child->removeFinishCallback(SoDragger::childFinishCB, this);
786   child->removeOtherEventCallback(SoDragger::childOtherEventCB, this);
787   child->removeValueChangedCallback(SoDragger::childTransferMotionAndValueChangedCB, this);
788 }
789 
790 /*!
791   Should be called by compund draggers to register child draggers that
792   should move independently of their parent.
793 */
794 void
registerChildDraggerMovingIndependently(SoDragger * child)795 SoDragger::registerChildDraggerMovingIndependently(SoDragger * child)
796 {
797   child->addStartCallback(SoDragger::childStartCB, this);
798   child->addMotionCallback(SoDragger::childMotionCB, this);
799   child->addFinishCallback(SoDragger::childFinishCB, this);
800   child->addOtherEventCallback(SoDragger::childOtherEventCB, this);
801   child->addValueChangedCallback(SoDragger::childValueChangedCB, this);
802 }
803 
804 /*!
805   Should be called by compund draggers to unregister child draggers.
806   \sa registerChildDraggerMovingIndependently()
807 */
808 void
unregisterChildDraggerMovingIndependently(SoDragger * child)809 SoDragger::unregisterChildDraggerMovingIndependently(SoDragger * child)
810 {
811   child->removeStartCallback(SoDragger::childStartCB, this);
812   child->removeMotionCallback(SoDragger::childMotionCB, this);
813   child->removeFinishCallback(SoDragger::childFinishCB, this);
814   child->removeOtherEventCallback(SoDragger::childOtherEventCB, this);
815   child->removeValueChangedCallback(SoDragger::childValueChangedCB, this);
816 }
817 
818 /*!
819   Returns a matrix that converts from local to world space.
820 */
821 SbMatrix
getLocalToWorldMatrix(void)822 SoDragger::getLocalToWorldMatrix(void)
823 {
824   if (PRIVATE(this)->draggercache) {
825     SbMatrix m = PRIVATE(this)->draggercache->draggerToWorld;
826     m.multLeft(this->getMotionMatrix());
827     return m;
828   }
829   return SbMatrix::identity();
830 }
831 
832 
833 /*!
834   Returns a matrix that converts from world to local space.
835 */
836 SbMatrix
getWorldToLocalMatrix(void)837 SoDragger::getWorldToLocalMatrix(void)
838 {
839   if (PRIVATE(this)->draggercache) {
840     SbMatrix m = PRIVATE(this)->draggercache->worldToDragger;
841     m.multRight(this->getMotionMatrix().inverse());
842     return m;
843   }
844   return SbMatrix::identity();
845 }
846 
847 /*!
848   Returns the drag starting point in the local coordinate system.
849 */
850 SbVec3f
getLocalStartingPoint(void)851 SoDragger::getLocalStartingPoint(void)
852 {
853   SbVec3f res;
854   this->getWorldToLocalMatrix().multVecMatrix(PRIVATE(this)->startingpoint, res);
855   return res;
856 }
857 
858 /*!
859   Returns the drag starting point in the world coordinate system.
860 */
861 SbVec3f
getWorldStartingPoint(void)862 SoDragger::getWorldStartingPoint(void)
863 {
864   return PRIVATE(this)->startingpoint;
865 }
866 
867 /*!
868   Returns matrices that will convert between local space and the space in
869   which \a partname lies in.
870 */
871 void
getPartToLocalMatrix(const SbName & partname,SbMatrix & parttolocalmatrix,SbMatrix & localtopartmatrix)872 SoDragger::getPartToLocalMatrix(const SbName & partname, SbMatrix & parttolocalmatrix, SbMatrix & localtopartmatrix)
873 {
874   // ref, in case somebody is operating on a zero-ref instance to the
875   // dragger.
876   this->ref();
877   // we need to create a path from the root node, since
878   // SoSurroundScale nodes need the entire path to calculate the
879   // surround parameters correctly.
880   SoPath * pathtothis = this->createPathToThis();
881   assert(pathtothis);
882   pathtothis->ref();
883   SoPath * path = reclassify_cast<SoPath *>(this->createPathToAnyPart(partname, FALSE, FALSE, FALSE, pathtothis));
884   assert(path);
885   pathtothis->unref();
886 
887   path->ref();
888   SoGetMatrixAction action(PRIVATE(this)->viewport);
889   action.apply(path);
890   SbMatrix p2w = action.getMatrix();
891   SbMatrix w2p = action.getInverse();
892   path->unref();
893 
894   // premultiply with matrix to/from this dragger to remove
895   // contributions before the dragger.
896   parttolocalmatrix = p2w;
897   parttolocalmatrix.multRight(this->getWorldToLocalMatrix());
898 
899   localtopartmatrix = this->getLocalToWorldMatrix();
900   localtopartmatrix.multRight(w2p);
901 
902   // we ref'ed at the beginning of the function
903   this->unrefNoDelete();
904 }
905 
906 /*!
907   Convenience method that transforms the local \a frommatrix to a world
908   coordinate systems matrix.
909 */
910 void
transformMatrixLocalToWorld(const SbMatrix & frommatrix,SbMatrix & tomatrix)911 SoDragger::transformMatrixLocalToWorld(const SbMatrix & frommatrix, SbMatrix & tomatrix)
912 {
913   if (&tomatrix != &frommatrix) tomatrix = frommatrix;
914   tomatrix.multRight(this->getLocalToWorldMatrix());
915   tomatrix.multLeft(this->getWorldToLocalMatrix());
916 }
917 
918 /*!
919   Convenience method that transforms the world \a frommatrix to a local
920   coordinate systems matrix.
921 */
922 void
transformMatrixWorldToLocal(const SbMatrix & frommatrix,SbMatrix & tomatrix)923 SoDragger::transformMatrixWorldToLocal(const SbMatrix & frommatrix, SbMatrix & tomatrix)
924 {
925   if (&tomatrix != &frommatrix) tomatrix = frommatrix;
926   tomatrix.multRight(this->getWorldToLocalMatrix());
927   tomatrix.multLeft(this->getLocalToWorldMatrix());
928 }
929 
930 /*!
931   Transforms a matrix that lies in the \a frompartname coordinate system into
932   the local coordinate system.
933 */
934 void
transformMatrixToLocalSpace(const SbMatrix & frommatrix,SbMatrix & tomatrix,const SbName & fromspacepartname)935 SoDragger::transformMatrixToLocalSpace(const SbMatrix & frommatrix, SbMatrix & tomatrix, const SbName & fromspacepartname)
936 {
937   if (&tomatrix != &frommatrix) tomatrix = frommatrix;
938   SbMatrix parttolocal, localtopart;
939   this->getPartToLocalMatrix(fromspacepartname, parttolocal, localtopart);
940   tomatrix.multRight(parttolocal);
941   tomatrix.multLeft(localtopart);
942 }
943 
944 /*!
945   Sets a new current motion matrix for the dragger geometry.
946 
947   Triggers value changed callbacks if \a matrix is unequal to the
948   previous motion matrix.
949 */
950 void
setMotionMatrix(const SbMatrix & matrix)951 SoDragger::setMotionMatrix(const SbMatrix & matrix)
952 {
953   SoMatrixTransform * node = SO_GET_ANY_PART(this, "motionMatrix", SoMatrixTransform);
954   if (matrix != node->matrix.getValue()) {
955     node->matrix = matrix;
956     this->valueChanged();
957   }
958 }
959 
960 /*!
961   Can be called by subclasses to trigger value changed callbacks. This might
962   be needed if a field is changed without changing the motion matrix.
963 */
964 void
valueChanged(void)965 SoDragger::valueChanged(void)
966 {
967   if (PRIVATE(this)->valuechangedcbenabled) {
968     PRIVATE(this)->valueChangedCB.invokeCallbacks(this);
969   }
970 }
971 
972 /*!
973   Returns the motion matrix as it was when saveStartParameters() was called.
974 */
975 const SbMatrix &
getStartMotionMatrix(void)976 SoDragger::getStartMotionMatrix(void)
977 {
978   return PRIVATE(this)->startmotionmatrix;
979 }
980 
981 /*!
982   This is invoked to save start parameters, to enable draggers to
983   calculate relative motion.
984 
985   Default method in superclass SoDragger just saves the motion matrix,
986   but subclasses should overload this method if other data needs to be
987   saved.
988 */
989 void
saveStartParameters(void)990 SoDragger::saveStartParameters(void)
991 {
992   PRIVATE(this)->startmotionmatrix = this->getMotionMatrix();
993 }
994 
995 /*!
996   Returns the picked path.
997 */
998 const SoPath *
getPickPath(void) const999 SoDragger::getPickPath(void) const
1000 {
1001   return PRIVATE(this)->pickedpath;
1002 }
1003 
1004 /*!
1005   Returns the current event.
1006 */
1007 const SoEvent *
getEvent(void) const1008 SoDragger::getEvent(void) const
1009 {
1010   return PRIVATE(this)->currentevent;
1011 }
1012 
1013 /*!
1014   Creates a new path to this dragger. Don't forget to ref() and
1015   unref() since this method creates a fresh copy for you.
1016 */
1017 SoPath *
createPathToThis(void)1018 SoDragger::createPathToThis(void)
1019 {
1020   assert(PRIVATE(this)->draggercache);
1021   assert(PRIVATE(this)->draggercache->path);
1022   SoPath * orgpath = reclassify_cast<SoPath *>(PRIVATE(this)->draggercache->path);
1023   return new SoPath(*orgpath);
1024 }
1025 
1026 /*!
1027   Returns the path to the SoInteractionKit that holds the current surrogate
1028   path.
1029 */
1030 const SoPath *
getSurrogatePartPickedOwner(void) const1031 SoDragger::getSurrogatePartPickedOwner(void) const
1032 {
1033   return PRIVATE(this)->surrogateownerpath;
1034 }
1035 
1036 /*!
1037   Returns the name of the path in the SoInteractionKit that holds the current
1038   surrogate path.
1039 */
1040 const SbName &
getSurrogatePartPickedName(void) const1041 SoDragger::getSurrogatePartPickedName(void) const
1042 {
1043   return PRIVATE(this)->surrogatename;
1044 }
1045 
1046 /*!
1047   Returns the current surrogate path.
1048 */
1049 const SoPath *
getSurrogatePartPickedPath(void) const1050 SoDragger::getSurrogatePartPickedPath(void) const
1051 {
1052   return PRIVATE(this)->surrogatepath;
1053 }
1054 
1055 /*!
1056   Sets the staring point for the drag. \a point is usually a
1057   picked point from a SoRayPickAction.
1058 */
1059 void
setStartingPoint(const SoPickedPoint * point)1060 SoDragger::setStartingPoint(const SoPickedPoint * point)
1061 {
1062   PRIVATE(this)->startingpoint = point->getPoint();
1063 }
1064 
1065 /*!
1066   Sets the starting point for a drag.
1067 */
1068 void
setStartingPoint(const SbVec3f & point)1069 SoDragger::setStartingPoint(const SbVec3f & point)
1070 {
1071   PRIVATE(this)->startingpoint = point;
1072 }
1073 
1074 typedef struct {
1075   SbViewVolume vv;
1076 } sodragger_vv_data;
1077 
1078 static sodragger_vv_data * vvdata = NULL;
1079 
1080 static SoCallbackAction::Response
sodragger_vv_cb(void * userdata,SoCallbackAction * action,const SoNode * node)1081 sodragger_vv_cb(void * userdata, SoCallbackAction * action, const SoNode * node)
1082 {
1083   if (node->isOfType(SoDragger::getClassTypeId())) {
1084     return (userdata==node)?SoCallbackAction::ABORT:SoCallbackAction::CONTINUE;
1085   }
1086   else {
1087     sodragger_vv_data * data = static_cast<sodragger_vv_data *>(userdata);
1088     data->vv = SoViewVolumeElement::get(action->getState());
1089     return SoCallbackAction::CONTINUE;
1090   }
1091 }
1092 
1093 extern "C" {
1094 
vv_data_cleanup(void)1095 static void vv_data_cleanup(void)
1096 {
1097   delete vvdata;
1098   vvdata = NULL;
1099 }
1100 
1101 } // extern "C"
1102 
1103 /*!
1104   Return the current view volume.
1105 */
1106 const SbViewVolume &
getViewVolume(void)1107 SoDragger::getViewVolume(void)
1108 {
1109   // FIXME: this is a temporary fix. We should really make
1110   // SoHandleEventAction support transformations so that the correct
1111   // view volume can be found directly. pederb, 2002-10-30
1112 
1113   if (PRIVATE(this)->draggercache && PRIVATE(this)->draggercache->path) {
1114     if (vvdata == NULL) {
1115       vvdata = new sodragger_vv_data;
1116       coin_atexit(static_cast<coin_atexit_f *>(vv_data_cleanup), CC_ATEXIT_NORMAL);
1117     }
1118     if (PRIVATE(this)->cbaction == NULL) {
1119       PRIVATE(this)->cbaction = new SoCallbackAction;
1120       PRIVATE(this)->cbaction->addPostCallback(SoCamera::getClassTypeId(), sodragger_vv_cb, vvdata);
1121       PRIVATE(this)->cbaction->addPostCallback(SoDragger::getClassTypeId(), sodragger_vv_cb, this);
1122     }
1123     PRIVATE(this)->cbaction->setViewportRegion(PRIVATE(this)->viewport);
1124     PRIVATE(this)->cbaction->apply(PRIVATE(this)->draggercache->path);
1125     PRIVATE(this)->viewvolume = vvdata->vv;
1126   }
1127   return PRIVATE(this)->viewvolume;
1128 }
1129 
1130 /*!
1131   Sets the current view volume.
1132 */
1133 void
setViewVolume(const SbViewVolume & vv)1134 SoDragger::setViewVolume(const SbViewVolume & vv)
1135 {
1136   PRIVATE(this)->viewvolume = vv;
1137 }
1138 
1139 /*!
1140   Returns the current viewport region.
1141 */
1142 const SbViewportRegion &
getViewportRegion(void)1143 SoDragger::getViewportRegion(void)
1144 {
1145   return PRIVATE(this)->viewport;
1146 }
1147 
1148 /*!
1149   Sets the current viewport region.
1150 */
1151 void
setViewportRegion(const SbViewportRegion & vp)1152 SoDragger::setViewportRegion(const SbViewportRegion & vp)
1153 {
1154   PRIVATE(this)->viewport = vp;
1155 }
1156 
1157 /*!
1158   Return the current (most recent) SoHandleEventAction.
1159 */
1160 SoHandleEventAction *
getHandleEventAction(void) const1161 SoDragger::getHandleEventAction(void) const
1162 {
1163   return PRIVATE(this)->eventaction;
1164 }
1165 
1166 /*!
1167   Stores a handle event action.
1168 */
1169 void
setHandleEventAction(SoHandleEventAction * action)1170 SoDragger::setHandleEventAction(SoHandleEventAction * action)
1171 {
1172   PRIVATE(this)->eventaction = action;
1173 }
1174 
1175 /*!
1176   This function is part of the original SGI Inventor 2.1 API, but has
1177   not been implemented in Coin as it looks like a function which
1178   should probably have been private in Open Inventor.
1179 */
1180 void
setTempPathToThis(const SoPath *)1181 SoDragger::setTempPathToThis(const SoPath *)
1182 {
1183   COIN_OBSOLETED();
1184 }
1185 
1186 /*!
1187   Called when dragger starts grabbing events (mouse button down).
1188   Overload if you need to do something extra in your dragger.
1189   \sa grabEventCleanup()
1190 */
1191 void
grabEventsSetup(void)1192 SoDragger::grabEventsSetup(void)
1193 {
1194   assert(PRIVATE(this)->eventaction);
1195   PRIVATE(this)->eventaction->setGrabber(this);
1196 }
1197 
1198 /*!
1199   Called when dragger stops grabbing events (mouse button up).
1200   \sa grabEventSetup()
1201 */
1202 void
grabEventsCleanup(void)1203 SoDragger::grabEventsCleanup(void)
1204 {
1205   assert(PRIVATE(this)->eventaction);
1206   PRIVATE(this)->eventaction->releaseGrabber();
1207 }
1208 
1209 /*!
1210   Examines the fields of the dragger, changes the matrix according to
1211   those fields and leaves the rest of the matrix as it was.  The
1212   following field names are supported: translation, scaleFactor,
1213   rotation and scaleOrientation.
1214 */
1215 void
workFieldsIntoTransform(SbMatrix & matrix)1216 SoDragger::workFieldsIntoTransform(SbMatrix & matrix)
1217 {
1218   SoSFVec3f * vecfield;
1219   SoSFRotation * rotfield;
1220   const SbVec3f * translation = NULL;
1221   const SbVec3f * scaleFactor = NULL;
1222   const SbRotation * rotation = NULL;
1223   const SbRotation * scaleOrientation = NULL;
1224   const SbVec3f * center = NULL;
1225 
1226   vecfield = coin_safe_cast<SoSFVec3f *>(this->getField("translation"));
1227   if (vecfield) translation = &vecfield->getValue();
1228 
1229   vecfield = coin_safe_cast<SoSFVec3f *>(this->getField("scaleFactor"));
1230   if (vecfield) scaleFactor = &vecfield->getValue();
1231 
1232   vecfield = coin_safe_cast<SoSFVec3f *>(this->getField("center"));
1233   if (vecfield) center = &vecfield->getValue();
1234 
1235   rotfield = coin_safe_cast<SoSFRotation *>(this->getField("rotation"));
1236   if (rotfield) rotation = &rotfield->getValue();
1237 
1238   rotfield = coin_safe_cast<SoSFRotation *>(this->getField("scaleOrientation"));
1239   if (rotfield) scaleOrientation = &rotfield->getValue();
1240 
1241   this->workValuesIntoTransform(matrix, translation, rotation,
1242                                 scaleFactor, scaleOrientation, center);
1243 }
1244 
1245 /*!
1246   Controls the behaviour of the SbProjector.
1247 */
1248 void
setFrontOnProjector(ProjectorFrontSetting val)1249 SoDragger::setFrontOnProjector(ProjectorFrontSetting val)
1250 {
1251   PRIVATE(this)->frontonprojector = val;
1252 }
1253 
1254 /*!
1255   Returns the behaviour of the SbProjector.
1256 */
1257 SoDragger::ProjectorFrontSetting
getFrontOnProjector(void) const1258 SoDragger::getFrontOnProjector(void) const
1259 {
1260   return PRIVATE(this)->frontonprojector;
1261 }
1262 
1263 /*!
1264   Sets the minimum scale value all scale factors are clamped against.
1265   This is used in workFieldsIntoTransform(). The default value is 0.01
1266 */
1267 void
setMinScale(float minscalearg)1268 SoDragger::setMinScale(float minscalearg)
1269 {
1270   SoDragger::minscale = minscalearg;
1271 }
1272 
1273 /*!
1274   Returns the minimum scale value.
1275   \sa setMinScale()
1276 */
1277 float
getMinScale(void)1278 SoDragger::getMinScale(void)
1279 {
1280   return SoDragger::minscale;
1281 }
1282 
1283 /*!
1284   Same as above, but pointers to values are supplied. If a pointer is
1285   \c NULL, the matrix value for that argument is used when
1286   reconstructing the matrix.
1287 */
1288 void
workValuesIntoTransform(SbMatrix & matrix,const SbVec3f * translationptr,const SbRotation * rotationptr,const SbVec3f * scalefactorptr,const SbRotation * scaleorientationptr,const SbVec3f * centerptr)1289 SoDragger::workValuesIntoTransform(SbMatrix & matrix, const SbVec3f * translationptr, const SbRotation * rotationptr, const SbVec3f * scalefactorptr, const SbRotation * scaleorientationptr, const SbVec3f * centerptr)
1290 {
1291   SbVec3f t, s;
1292   SbRotation r, so;
1293   if (centerptr) matrix.getTransform(t, r, s, so, *centerptr);
1294   else matrix.getTransform(t, r, s, so);
1295 
1296   if (translationptr) t = *translationptr;
1297   if (rotationptr) r = *rotationptr;
1298   if (scalefactorptr) s = *scalefactorptr;
1299   if (scaleorientationptr) so = *scaleorientationptr;
1300 
1301   if (centerptr) matrix.setTransform(t, r, s, so, *centerptr);
1302   else matrix.setTransform(t, r, s, so);
1303 }
1304 
1305 /*!
1306   Can be used when there is no scaleorientation. Faster than
1307   SoDragger::workValuesIntoTransform().
1308 */
1309 void
getTransformFast(SbMatrix & matrix,SbVec3f & translation,SbRotation & rotation,SbVec3f & scalefactor,SbRotation & scaleorientation,const SbVec3f & center)1310 SoDragger::getTransformFast(SbMatrix & matrix, SbVec3f & translation,
1311                             SbRotation & rotation, SbVec3f & scalefactor,
1312                             SbRotation & scaleorientation,
1313                             const SbVec3f & center)
1314 {
1315   // FIXME: faster code not implemented, we just forward the call to
1316   // workValuesIntoTransform() anyway. 20011219 mortene.
1317 
1318   SoDragger::workValuesIntoTransform(matrix, &translation, &rotation,
1319                                      &scalefactor,
1320                                      &scaleorientation, &center);
1321 }
1322 
1323 /*!
1324   \overload
1325 */
1326 void
getTransformFast(SbMatrix & matrix,SbVec3f & translation,SbRotation & rotation,SbVec3f & scalefactor,SbRotation & scaleorientation)1327 SoDragger::getTransformFast(SbMatrix & matrix, SbVec3f & translation,
1328                             SbRotation & rotation, SbVec3f & scalefactor,
1329                             SbRotation & scaleorientation)
1330 {
1331   // FIXME: faster code not implemented, we just forward the call to
1332   // workValuesIntoTransform() anyway. 20011219 mortene.
1333 
1334   SoDragger::workValuesIntoTransform(matrix, &translation, &rotation,
1335                                      &scalefactor,
1336                                      &scaleorientation, NULL);
1337 }
1338 
1339 /*!
1340   Returns \a matrix after \a translation has been appended.  If \a
1341   conversion != \c NULL it is used to transform \a translation into
1342   the space \a matrix is defined.
1343 */
1344 SbMatrix
appendTranslation(const SbMatrix & matrix,const SbVec3f & translation,const SbMatrix * conversion)1345 SoDragger::appendTranslation(const SbMatrix & matrix, const SbVec3f & translation, const SbMatrix * conversion)
1346 {
1347   SbMatrix transform;
1348   transform.setTranslate(translation);
1349   if (conversion) {
1350     transform.multRight(*conversion);
1351     transform.multLeft(conversion->inverse());
1352   }
1353   SbMatrix res = matrix;
1354   return res.multLeft(transform);
1355 }
1356 
1357 /*!
1358   Returns \a matrix after \a scale and \a scalecenter has been
1359   appended.  If \a conversion != \c NULL it is used to transform scale
1360   into the space \a matrix is defined.
1361 */
1362 
1363 SbMatrix
appendScale(const SbMatrix & matrix,const SbVec3f & scale,const SbVec3f & scalecenter,const SbMatrix * conversion)1364 SoDragger::appendScale(const SbMatrix & matrix, const SbVec3f & scale, const SbVec3f & scalecenter, const SbMatrix * conversion)
1365 {
1366   // Clamp the dragger values so that huge scaling in one go does not
1367   // work, and negative scale values are made positive. The explicit
1368   // casts are done to humour the HPUX aCC compiler, which will
1369   // otherwise say ``Template deduction failed to find a match for the
1370   // call to 'SbMax'''.  mortene.
1371   SbVec3f clampedscale;
1372   clampedscale[0] = SbMax(static_cast<float>(scale[0]), SoDragger::minscale);
1373   clampedscale[1] = SbMax(static_cast<float>(scale[1]), SoDragger::minscale);
1374   clampedscale[2] = SbMax(static_cast<float>(scale[2]), SoDragger::minscale);
1375 
1376   SbMatrix transform, tmp;
1377   // Calculate the scaled matrix without doing any testing if the
1378   // scale of the resulting matrix is above SoDragger::minscale.
1379   transform.setTranslate(-scalecenter);
1380   tmp.setScale(clampedscale);
1381   transform.multRight(tmp);
1382   tmp.setTranslate(scalecenter);
1383   transform.multRight(tmp);
1384 
1385   if (conversion) {
1386     transform.multRight(*conversion);
1387     transform.multLeft(conversion->inverse());
1388   }
1389   SbMatrix res = matrix;
1390   res.multLeft(transform);
1391 
1392   // Decompose the calculated matrix to be able to clamp the scale.
1393   SbVec3f t, s;
1394   SbRotation r, so;
1395   res.getTransform(t, r, s, so);
1396 
1397   // If the scale of the resulting matrix is smaller in x,y or z than
1398   // SoDragger::minscale, then the scale value has to be corrected. If
1399   // no correction is needed, the res matrix is returned without more
1400   // calculations.
1401   if (s[0] < SoDragger::minscale ||
1402       s[1] < SoDragger::minscale ||
1403       s[2] < SoDragger::minscale) {
1404 
1405     // Clamp the values of the scale to be SoDragger::minscale or
1406     // above.
1407     int i;
1408     for (i = 0; i < 3; i++) {
1409       if (s[i] < SoDragger::minscale) {
1410         s[i] = SoDragger::minscale;
1411       }
1412     }
1413 
1414     // Set the new transform with the adjusted scale
1415     transform.setTransform(t, r, s, so);
1416     // Just returning this matrix does not work as expected.
1417     // The dragger gets translated along the screen while trying
1418     // to scale below SoDragger::minscale. This is why further
1419     // processing is needed. We use the relationship between the
1420     // matrices to calculate the required scale vector.
1421     //
1422     // The scale matrix is found by the following equality:
1423     //
1424     // M = C^-1 * P^-1 * S * P * C * Mold
1425     //
1426     // By having the scale on one side and moving all other matrices
1427     // to the other side, we end up with this equation:
1428     //
1429     // S = P * C * M * Mold^-1 * C^-1 * P^-1
1430     //
1431     // Where S is the scale matrix which has a diagonal containing
1432     // the required scale vector.
1433 
1434     // Calculate the scale vector:
1435     transform.multRight(matrix.inverse());
1436     if (conversion) {
1437       transform.multLeft(*conversion);
1438       transform.multRight(conversion->inverse());
1439     }
1440     tmp.setTranslate(scalecenter);
1441     transform.multLeft(tmp);
1442     tmp.setTranslate(-scalecenter);
1443     transform.multRight(tmp);
1444 
1445     // SbMatrix does not have a getScale method, so just read the
1446     // values directly out of the matrix. This matrix does not only
1447     // contain scale. It might also have some other junk that we are
1448     // not interested in, so just read the scale values and ignore the
1449     // rest.
1450     SbVec3f newscale;
1451     newscale[0] = transform[0][0];
1452     newscale[1] = transform[1][1];
1453     newscale[2] = transform[2][2];
1454 
1455     // Calling appendScale here might cause a neverending loop if the
1456     // adjusted scale is just below SoDragger::minscale, so redo the
1457     // calculation of the resulting matrix without recursion.
1458     transform.setTranslate(-scalecenter);
1459     tmp.setScale(newscale);
1460     transform.multRight(tmp);
1461     tmp.setTranslate(scalecenter);
1462     transform.multRight(tmp);
1463 
1464     if (conversion) {
1465       transform.multRight(*conversion);
1466       transform.multLeft(conversion->inverse());
1467     }
1468     res = matrix;
1469     res.multLeft(transform);
1470   }
1471 
1472   return res;
1473 }
1474 
1475 /*!
1476   Appends \a rot, around \a rotcenter, to \a matrix. If \a conversion
1477   is != \c NULL, this is used to move the rotation into that
1478   coordinate systems before appending the rotation.
1479 */
1480 SbMatrix
appendRotation(const SbMatrix & matrix,const SbRotation & rot,const SbVec3f & rotcenter,const SbMatrix * conversion)1481 SoDragger::appendRotation(const SbMatrix & matrix, const SbRotation & rot, const SbVec3f & rotcenter, const SbMatrix * conversion)
1482 {
1483   SbMatrix transform, tmp;
1484   transform.setTranslate(-rotcenter);
1485   tmp.setRotate(rot);
1486   transform.multRight(tmp);
1487   tmp.setTranslate(rotcenter);
1488   transform.multRight(tmp);
1489   if (conversion) {
1490     transform.multRight(*conversion);
1491     transform.multLeft(conversion->inverse());
1492   }
1493   transform.multRight(matrix);
1494   return transform;
1495 }
1496 
1497 /*!
1498   Returns the position of the locater.
1499 */
1500 SbVec2f
getNormalizedLocaterPosition(void)1501 SoDragger::getNormalizedLocaterPosition(void)
1502 {
1503   if (PRIVATE(this)->currentevent) {
1504     return PRIVATE(this)->currentevent->getNormalizedPosition(PRIVATE(this)->viewport);
1505   }
1506 #if COIN_DEBUG && 1 // debug
1507   SoDebugError::postInfo("SoDragger::getLocaterPosition",
1508                          "current event is not set");
1509 #endif // debug
1510   return SbVec2f(0, 0);
1511 }
1512 
1513 /*!
1514   \overload
1515 */
1516 SbVec2s
getLocaterPosition(void)1517 SoDragger::getLocaterPosition(void)
1518 {
1519   if (PRIVATE(this)->currentevent) {
1520     return PRIVATE(this)->currentevent->getPosition();
1521   }
1522 #if COIN_DEBUG && 1 // debug
1523   SoDebugError::postInfo("SoDragger::getLocaterPosition",
1524                          "current event is not set");
1525 #endif // debug
1526   return SbVec2s(0, 0);
1527 }
1528 
1529 /*!
1530   Returns the position when mouse button 1 was pressed.
1531 */
1532 SbVec2s
getStartLocaterPosition(void) const1533 SoDragger::getStartLocaterPosition(void) const
1534 {
1535   return PRIVATE(this)->startlocaterpos;
1536 }
1537 
1538 /*!
1539   The start locater position is automatically set when mouse button 1 goes
1540   down, but subclasses can use this method to reset the value.
1541 */
1542 void
setStartLocaterPosition(SbVec2s pos)1543 SoDragger::setStartLocaterPosition(SbVec2s pos)
1544 {
1545   PRIVATE(this)->startlocaterpos = pos;
1546 }
1547 
1548 /*!
1549   Checks if the mouse pointer has been moved enough after the end-user
1550   hit a constraint mode key (which is typically \c SHIFT, sometimes
1551   also \c CTRL for the built-in draggers) that we should act upon and
1552   decide which direction the constraint should be set to.
1553 */
1554 SbBool
isAdequateConstraintMotion(void)1555 SoDragger::isAdequateConstraintMotion(void)
1556 {
1557   SbVec2s delta =
1558     this->getStartLocaterPosition() -
1559     this->getLocaterPosition();
1560 
1561   // The cast is done to avoid HPUX aCC failing with an "ambiguity
1562   // error", as sqrt() can be either "long double sqrt(long double)"
1563   // or "float sqrt(float)".  mortene.
1564   double len = sqrt(double(delta[0]*delta[0] + delta[1]*delta[1]));
1565 
1566   if (len >= static_cast<double>(PRIVATE(this)->mingesture)) return TRUE;
1567   return FALSE;
1568 }
1569 
1570 /*!
1571   Checks if \a pickpath contains \a surrogatepath and returns \c TRUE
1572   if the tail of \a surrogatepath is before any dragger in \a
1573   pickpath.
1574 */
1575 SbBool
shouldGrabBasedOnSurrogate(const SoPath * pickpath,const SoPath * surrogatepath)1576 SoDragger::shouldGrabBasedOnSurrogate(const SoPath * pickpath, const SoPath * surrogatepath)
1577 {
1578   if (!pickpath->containsPath(surrogatepath)) return FALSE;
1579 
1580   const SoFullPath * pick = reclassify_cast<const SoFullPath *>(pickpath);
1581   const SoFullPath * surr = reclassify_cast<const SoFullPath *>(surrogatepath);
1582 
1583   SoNode * tail = surr->getTail();
1584   SoType draggertype = SoDragger::getClassTypeId();
1585 
1586   for (int i = pick->getLength()-1; i >= 0; i--) {
1587     SoNode * node = pick->getNode(i);
1588     if (node == tail) return TRUE;
1589     if (node->isOfType(draggertype))
1590       return FALSE;
1591   }
1592   return FALSE;
1593 }
1594 
1595 /*!
1596   Store data about the current camera in the given action.
1597 */
1598 void
setCameraInfo(SoAction * action)1599 SoDragger::setCameraInfo(SoAction * action)
1600 {
1601   SoState * state = action->getState();
1602   PRIVATE(this)->viewport = SoViewportRegionElement::get(state);;
1603   PRIVATE(this)->viewvolume = SoViewVolumeElement::get(state);
1604 }
1605 
1606 /*!
1607   Interaction with the dragger will be started, if the returned
1608   picked point belongs to the dragger. A derived class can override
1609   this method to change the condition when the dragger starts interaction,
1610   e.g. it can return the picked point on the dragger from the
1611   picked point list of the action, even if it is covered by other
1612   (semi) transparent objects.
1613   The default implementation returns the foremost picked point
1614   from the action.
1615   This method is not present in Open Inventor.
1616   */
1617 const SoPickedPoint*
getPickedPointForStart(SoHandleEventAction * action)1618 SoDragger::getPickedPointForStart(SoHandleEventAction* action)
1619 {
1620 	return action->getPickedPoint();
1621 }
1622 
1623 // Documented in superclass. Overridden to detect picks on dragger.
1624 void
handleEvent(SoHandleEventAction * action)1625 SoDragger::handleEvent(SoHandleEventAction * action)
1626 {
1627   const SoEvent * event = action->getEvent();
1628 
1629   if (this->isActive.getValue() || this->getActiveChildDragger()) {
1630     if (!action->getGrabber())
1631       this->updateDraggerCache(action->getCurPath());
1632     else
1633       this->updateDraggerCache(NULL);
1634   }
1635   // try child draggers first
1636   if (action->getGrabber() != this) {
1637     inherited::handleEvent(action);
1638   }
1639   // return if handled by a child
1640   if (action->isHandled()) return;
1641 
1642   // Protect dragger from deletion
1643   this->ref();
1644 
1645   // this is a special case, to be able to detect when somebody
1646   // clicks ctrl over a dragger. This has a special meaning for
1647   // some draggers, and it's the only time the otherEvent callbacks
1648   // are called when the dragger is not active.
1649   //
1650   // If you disable autoredraws via
1651   // SoGuiRenderArea::setAutoRedraw(FALSE) you must remember to add an
1652   // otherEventCallback if you want to schedule a redraw when ctrl is
1653   // tapped.
1654 
1655   if (!this->isActive.getValue() &&
1656       (SO_KEY_PRESS_EVENT(event, LEFT_CONTROL) ||
1657        SO_KEY_PRESS_EVENT(event, RIGHT_CONTROL))) {
1658     const SoPickedPoint * pp = this->getPickedPointForStart(action);
1659     if (pp && this->isPicked(pp->getPath())) {
1660       this->eventHandled(event, action);
1661       PRIVATE(this)->otherEventCB.invokeCallbacks(this);
1662     }
1663   }
1664   else if (SO_MOUSE_PRESS_EVENT(event, BUTTON1)) {
1665     const SoPickedPoint * pp = this->getPickedPointForStart(action);
1666 
1667     SbBool didpick = FALSE;
1668 
1669     if (pp && this->isPicked(pp->getPath())) didpick = TRUE;
1670     else if (pp) { // check surrogate paths
1671       SoPath * owner, * path;
1672       SbName name;
1673       if (this->isPathSurrogateInMySubgraph(pp->getPath(), owner, name, path)) {
1674         owner->ref();
1675         path->ref();
1676         if (this->shouldGrabBasedOnSurrogate(pp->getPath(), path)) {
1677           if (PRIVATE(this)->surrogateownerpath)
1678             PRIVATE(this)->surrogateownerpath->unref();
1679           PRIVATE(this)->surrogateownerpath = owner;
1680           PRIVATE(this)->surrogateownerpath->ref();
1681           if (PRIVATE(this)->surrogatepath)
1682             PRIVATE(this)->surrogatepath->unref();
1683           PRIVATE(this)->surrogatepath = path;
1684           PRIVATE(this)->surrogatepath->ref();
1685           PRIVATE(this)->surrogatename = name;
1686           didpick = TRUE;
1687         }
1688         owner->unref();
1689         path->unref();
1690       }
1691     }
1692 
1693     if (didpick) {
1694       this->setCameraInfo(action);
1695 
1696       if (!action->getGrabber())
1697         this->updateDraggerCache(action->getCurPath());
1698       else
1699         this->updateDraggerCache(NULL);
1700 
1701       this->isActive = TRUE;
1702       PRIVATE(this)->didmousemove = FALSE;
1703       this->setStartingPoint(pp);
1704       this->eventHandled(event, action);
1705       if (PRIVATE(this)->pickedpath)
1706         PRIVATE(this)->pickedpath->unref();
1707       PRIVATE(this)->pickedpath = pp->getPath();
1708       PRIVATE(this)->pickedpath->ref();
1709 
1710       PRIVATE(this)->startlocaterpos = event->getPosition();
1711       PRIVATE(this)->isgrabbing = FALSE;
1712       this->saveStartParameters();
1713       PRIVATE(this)->startCB.invokeCallbacks(this);
1714     }
1715   }
1716   else if (this->isActive.getValue() && SO_MOUSE_RELEASE_EVENT(event, BUTTON1)) {
1717     this->isActive = FALSE;
1718     if (PRIVATE(this)->didmousemove) {
1719       this->eventHandled(event, action);
1720       PRIVATE(this)->didmousemove = FALSE;
1721     }
1722 	if (PRIVATE(this)->isgrabbing) {
1723 	  this->grabEventsCleanup();
1724 	  PRIVATE(this)->isgrabbing = FALSE;
1725 	}
1726     if (PRIVATE(this)->pickedpath) {
1727       PRIVATE(this)->pickedpath->unref();
1728       PRIVATE(this)->pickedpath = NULL;
1729     }
1730     PRIVATE(this)->surrogatename = "";
1731     if (PRIVATE(this)->surrogateownerpath) {
1732       PRIVATE(this)->surrogateownerpath->unref();
1733       PRIVATE(this)->surrogateownerpath = NULL;
1734     }
1735     if (PRIVATE(this)->surrogatepath) {
1736       PRIVATE(this)->surrogatepath->unref();
1737       PRIVATE(this)->surrogatepath = NULL;
1738     }
1739 
1740     PRIVATE(this)->finishCB.invokeCallbacks(this);
1741     PRIVATE(this)->draggercache->truncatePath();
1742   }
1743   else if (this->isActive.getValue() && event->isOfType(SoLocation2Event::getClassTypeId())) {
1744     this->eventHandled(event, action);
1745     PRIVATE(this)->didmousemove = TRUE;
1746     PRIVATE(this)->motionCB.invokeCallbacks(this);
1747     if (!PRIVATE(this)->isgrabbing) {
1748       this->grabEventsSetup();
1749       PRIVATE(this)->isgrabbing = TRUE;
1750     }
1751   }
1752   else if (this->isActive.getValue()) {
1753     PRIVATE(this)->eventaction = action;
1754     PRIVATE(this)->currentevent = event;
1755     PRIVATE(this)->otherEventCB.invokeCallbacks(this);
1756   }
1757   if (!action->isHandled())
1758     inherited::handleEvent(action);
1759 
1760   // Unprotect dragger
1761   this->unref();
1762 }
1763 
1764 /*!
1765   \COININTERNAL
1766 */
1767 void
transferMotion(SoDragger * child)1768 SoDragger::transferMotion(SoDragger * child)
1769 {
1770   SbMatrix childmatrix = child->getMotionMatrix();
1771   child->setMotionMatrix(SbMatrix::identity());
1772   child->transformMatrixLocalToWorld(childmatrix, childmatrix);
1773   this->transformMatrixWorldToLocal(childmatrix, childmatrix);
1774 
1775   SbMatrix matrix = this->getStartMotionMatrix();
1776   matrix.multLeft(childmatrix);
1777   this->setMotionMatrix(matrix);
1778 }
1779 
1780 /*!
1781   Sets whether dragger geometry should be ignored when calculating bbox.
1782 */
1783 void
setIgnoreInBbox(SbBool val)1784 SoDragger::setIgnoreInBbox(SbBool val)
1785 {
1786   PRIVATE(this)->ignoreinbbox = val;
1787 }
1788 
1789 /*!
1790   Returns whether dragger geometry should be ignored when calculating bbox.
1791 */
1792 SbBool
isIgnoreInBbox(void)1793 SoDragger::isIgnoreInBbox(void)
1794 {
1795   return PRIVATE(this)->ignoreinbbox;
1796 }
1797 
1798 // Documented in superclass. Overridden to ignore dragger bounding box
1799 // if SoDragger::isIgnoreInBbox() is \c TRUE.
1800 void
getBoundingBox(SoGetBoundingBoxAction * action)1801 SoDragger::getBoundingBox(SoGetBoundingBoxAction * action)
1802 {
1803   if (!PRIVATE(this)->ignoreinbbox) inherited::getBoundingBox(action);
1804 
1805 }
1806 
1807 /*!
1808   \COININTERNAL
1809 */
1810 void
setActiveChildDragger(SoDragger * childdragger)1811 SoDragger::setActiveChildDragger(SoDragger * childdragger)
1812 {
1813   PRIVATE(this)->activechilddragger = childdragger;
1814 }
1815 
1816 /*!
1817   \COININTERNAL
1818 */
1819 SoDragger *
getActiveChildDragger(void) const1820 SoDragger::getActiveChildDragger(void) const
1821 {
1822   return PRIVATE(this)->activechilddragger;
1823 }
1824 
1825 // Documented in superclass. Overridden to set default on
1826 // SoDragger::isActive, SoDragger::motionMatrix and on common
1827 // subdragger fields: translation, center, scaleFactor and rotation.
1828 void
setDefaultOnNonWritingFields(void)1829 SoDragger::setDefaultOnNonWritingFields(void)
1830 {
1831 #define CHECK_DEFAULT(name, type, val) \
1832   do { \
1833     SoField * f = this->getField(name); \
1834     if (f) { \
1835       if ((coin_assert_cast<type *>(f))->getValue() == val) f->setDefault(TRUE); \
1836     } \
1837   } while (0)
1838 
1839   // check common subdragger fields
1840   CHECK_DEFAULT("translation", SoSFVec3f, SbVec3f(0.0f, 0.0f, 0.0f));
1841   CHECK_DEFAULT("center", SoSFVec3f, SbVec3f(0.0f, 0.0f, 0.0f));
1842   CHECK_DEFAULT("scaleFactor", SoSFVec3f, SbVec3f(1.0f, 1.0f, 1.0f));
1843   CHECK_DEFAULT("rotation", SoSFRotation, SbRotation::identity());
1844 
1845   // check isActive
1846   CHECK_DEFAULT("isActive", SoSFBool, FALSE);
1847 #undef CHECK_DEFAULT
1848 
1849   this->motionMatrix.setDefault(TRUE);
1850 
1851   inherited::setDefaultOnNonWritingFields();
1852 }
1853 
1854 /*!
1855   \COININTERNAL
1856 */
1857 void
childTransferMotionAndValueChangedCB(void * data,SoDragger * child)1858 SoDragger::childTransferMotionAndValueChangedCB(void * data, SoDragger * child)
1859 {
1860   SoDragger * thisp = static_cast<SoDragger *>(data);
1861   child->removeValueChangedCallback(SoDragger::childTransferMotionAndValueChangedCB, thisp);
1862   thisp->transferMotion(child);
1863   child->addValueChangedCallback(SoDragger::childTransferMotionAndValueChangedCB, thisp);
1864 }
1865 
1866 /*!
1867   \COININTERNAL
1868 */
1869 void
childValueChangedCB(void * data,SoDragger * COIN_UNUSED_ARG (child))1870 SoDragger::childValueChangedCB(void * data, SoDragger * COIN_UNUSED_ARG(child))
1871 {
1872   SoDragger * thisp = static_cast<SoDragger *>(data);
1873   thisp->valueChanged();
1874 }
1875 
1876 /*!
1877   \COININTERNAL
1878 */
1879 void
childStartCB(void * data,SoDragger * child)1880 SoDragger::childStartCB(void * data, SoDragger * child)
1881 {
1882   SoDragger * thisp = static_cast<SoDragger *>(data);
1883   thisp->ref();
1884   // make child use the same projector epsilon as its parent
1885   child->setProjectorEpsilon(thisp->getProjectorEpsilon());
1886   thisp->saveStartParameters();
1887   thisp->setActiveChildDragger(child);
1888   PRIVATE(thisp)->startCB.invokeCallbacks(thisp);
1889   thisp->unref();
1890 }
1891 
1892 /*!
1893   \COININTERNAL
1894 */
1895 void
childMotionCB(void * data,SoDragger * COIN_UNUSED_ARG (child))1896 SoDragger::childMotionCB(void * data, SoDragger * COIN_UNUSED_ARG(child))
1897 {
1898   SoDragger * thisp = static_cast<SoDragger *>(data);
1899   PRIVATE(thisp)->motionCB.invokeCallbacks(thisp);
1900 }
1901 
1902 /*!
1903   \COININTERNAL
1904 */
1905 void
childFinishCB(void * data,SoDragger * COIN_UNUSED_ARG (child))1906 SoDragger::childFinishCB(void * data, SoDragger * COIN_UNUSED_ARG(child))
1907 {
1908   SoDragger * thisp = static_cast<SoDragger *>(data);
1909 
1910   thisp->ref();
1911   PRIVATE(thisp)->finishCB.invokeCallbacks(thisp);
1912   thisp->setActiveChildDragger(NULL);
1913   if (PRIVATE(thisp)->draggercache) PRIVATE(thisp)->draggercache->truncatePath();
1914   thisp->unref();
1915 }
1916 
1917 /*!
1918   \COININTERNAL
1919 */
1920 void
childOtherEventCB(void * data,SoDragger * child)1921 SoDragger::childOtherEventCB(void * data, SoDragger * child)
1922 {
1923   SoDragger * thisp = static_cast<SoDragger *>(data);
1924   PRIVATE(thisp)->currentevent = child->pimpl->currentevent;
1925   PRIVATE(thisp)->eventaction = child->pimpl->eventaction;
1926   PRIVATE(thisp)->otherEventCB.invokeCallbacks(thisp);
1927 }
1928 
1929 // Returns whether path goes through this node (dragger is picked).
1930 SbBool
isPicked(SoPath * path)1931 SoDragger::isPicked(SoPath * path)
1932 {
1933   // last dragger in path must be this one
1934   SoFullPath * fullpath = reclassify_cast<SoFullPath *>(path);
1935 
1936   int i = fullpath->findNode(this);
1937   if (i < 0) return FALSE;
1938 
1939   // if this is a composite dragger, the path will go through this
1940   // dragger, but it should not be regarded as picked if a child
1941   // dragger is picked.
1942   int n = fullpath->getLength();
1943   for (++i; i < n; i++) {
1944     SoNode * node = fullpath->getNode(i);
1945     if (node->isOfType(SoDragger::getClassTypeId())) return FALSE;
1946   }
1947   return TRUE;
1948 }
1949 
1950 void
eventHandled(const SoEvent * event,SoHandleEventAction * action)1951 SoDragger::eventHandled(const SoEvent * event, SoHandleEventAction * action)
1952 {
1953   action->setHandled();
1954   PRIVATE(this)->currentevent = event;
1955   PRIVATE(this)->eventaction = action;
1956 }
1957 
1958 /*!
1959   \COININTERNAL
1960 */
1961 void
updateDraggerCache(const SoPath * path)1962 SoDragger::updateDraggerCache(const SoPath * path)
1963 {
1964   if (PRIVATE(this)->draggercache == NULL)
1965     PRIVATE(this)->draggercache = new SoDraggerCache(this);
1966   if (path) PRIVATE(this)->draggercache->update(reclassify_cast<const SoFullPath *>(path), path->findNode(this));
1967   else PRIVATE(this)->draggercache->updateMatrix();
1968 }
1969 
1970 #undef PRIVATE
1971 #endif // HAVE_DRAGGERS
1972