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, ¢er);
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