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 SoHandleBoxDragger SoHandleBoxDragger.h Inventor/draggers/SoHandleBoxDragger.h
41   \brief The SoHandleBoxDragger class provides support for interactive scaling and translation.
42 
43   \ingroup draggers
44 
45   \DRAGGER_DEFAULT_SCREENSHOT
46 
47   <center>
48   \image html handlebox.png "Screen Shot of Default Dragger"
49   </center>
50 
51   A handlebox dragger is convenient to use for letting the user
52   interact with geometry that can be scaled (uniformly or in a
53   non-uniform way) and translated in 3D.
54 
55   The dragger consists of a "cube" of interaction geometry. The
56   end-user can click and drag any side of the cube to translate the
57   dragger and click and drag any of the corner or edge markers for
58   scaling operations.
59 */
60 // FIXME: Should include an URL-link to the default geometry-file?
61 // Plus a small usage example.  20011113 mortene.
62 
63 #include <Inventor/draggers/SoHandleBoxDragger.h>
64 
65 #include <cstring>
66 
67 #include <Inventor/nodes/SoDrawStyle.h>
68 #include <Inventor/nodes/SoSeparator.h>
69 #include <Inventor/nodes/SoSurroundScale.h>
70 #include <Inventor/nodes/SoSwitch.h>
71 #include <Inventor/nodes/SoTranslation.h>
72 #include <Inventor/sensors/SoFieldSensor.h>
73 #include <Inventor/projectors/SbPlaneProjector.h>
74 #include <Inventor/projectors/SbLineProjector.h>
75 #include <Inventor/events/SoKeyboardEvent.h>
76 #include <Inventor/actions/SoGetMatrixAction.h>
77 
78 #include <data/draggerDefaults/handleBoxDragger.h>
79 
80 #include "nodekits/SoSubKitP.h"
81 #include "coindefs.h"
82 #include "SbBasicP.h"
83 
84 /*!
85   \var SoSFVec3f SoHandleBoxDragger::scaleFactor
86 
87   Continuously updated to contain the current vector of scaling along
88   the X, Y and Z axes.
89 */
90 
91 /*!
92   \var SoSFVec3f SoHandleBoxDragger::translation
93 
94   Continuously updated to contain the current translation from the
95   dragger's local origo position.
96 
97   The application programmer applying this dragger in his code should
98   connect the relevant node fields in the scene to this field to make
99   it follow the dragger.
100 */
101 
102 
103 /*!
104   \var SoFieldSensor * SoHandleBoxDragger::translFieldSensor
105   \COININTERNAL
106 */
107 /*!
108   \var SoFieldSensor * SoHandleBoxDragger::scaleFieldSensor
109   \COININTERNAL
110 */
111 
112 #define WHATKIND_NONE       0
113 #define WHATKIND_TRANSLATOR 1
114 #define WHATKIND_EXTRUDER   2
115 #define WHATKIND_UNIFORM    3
116 
117 #define CONSTRAINT_OFF  0
118 #define CONSTRAINT_WAIT 1
119 #define CONSTRAINT_X    2
120 #define CONSTRAINT_Y    3
121 #define CONSTRAINT_Z    4
122 
123 static int uniform_ctrl_lookup[8][6] = {
124   { 1,4,5,2,3,6 },
125   { 1,4,6,2,3,5 },
126   { 2,4,5,1,3,6 },
127   { 2,4,6,1,3,5 },
128   { 1,3,5,2,4,6 },
129   { 1,3,6,2,4,5 },
130   { 2,3,5,1,4,6 },
131   { 2,3,6,1,4,5 }
132 };
133 
134 class SoHandleBoxDraggerP {
135 public:
136 };
137 
138 SO_KIT_SOURCE(SoHandleBoxDragger);
139 
140 
141 // doc in superclass
142 void
initClass(void)143 SoHandleBoxDragger::initClass(void)
144 {
145   SO_KIT_INTERNAL_INIT_CLASS(SoHandleBoxDragger, SO_FROM_INVENTOR_1);
146 }
147 
148 // FIXME: document which parts need to be present in the geometry
149 // scenegraph, and what role they play in the dragger. 20010913 mortene.
150 /*!
151   \DRAGGER_CONSTRUCTOR
152 
153   \NODEKIT_PRE_DIAGRAM
154 
155   \verbatim
156   CLASS SoHandleBoxDragger
157   -->"this"
158         "callbackList"
159         "topSeparator"
160            "motionMatrix"
161   -->      "surroundScale"
162            "geomSeparator"
163   -->         "drawStyle"
164   -->         "translator1Switch"
165   -->            "translator1"
166   -->            "translator1Active"
167   -->         "translator2Switch"
168   -->            "translator2"
169   -->            "translator2Active"
170   -->         "translator3Switch"
171   -->            "translator3"
172   -->            "translator3Active"
173   -->         "translator4Switch"
174   -->            "translator4"
175   -->            "translator4Active"
176   -->         "translator5Switch"
177   -->            "translator5"
178   -->            "translator5Active"
179   -->         "translator6Switch"
180   -->            "translator6"
181   -->            "translator6Active"
182   -->         "extruder1Switch"
183   -->            "extruder1"
184   -->            "extruder1Active"
185   -->         "extruder2Switch"
186   -->            "extruder2"
187   -->            "extruder2Active"
188   -->         "extruder3Switch"
189   -->            "extruder3"
190   -->            "extruder3Active"
191   -->         "extruder4Switch"
192   -->            "extruder4"
193   -->            "extruder4Active"
194   -->         "extruder5Switch"
195   -->            "extruder5"
196   -->            "extruder5Active"
197   -->         "extruder6Switch"
198   -->            "extruder6"
199   -->            "extruder6Active"
200   -->         "uniform1Switch"
201   -->            "uniform1"
202   -->            "uniform1Active"
203   -->         "uniform2Switch"
204   -->            "uniform2"
205   -->            "uniform2Active"
206   -->         "uniform3Switch"
207   -->            "uniform3"
208   -->            "uniform3Active"
209   -->         "uniform4Switch"
210   -->            "uniform4"
211   -->            "uniform4Active"
212   -->         "uniform5Switch"
213   -->            "uniform5"
214   -->            "uniform5Active"
215   -->         "uniform6Switch"
216   -->            "uniform6"
217   -->            "uniform6Active"
218   -->         "uniform7Switch"
219   -->            "uniform7"
220   -->            "uniform7Active"
221   -->         "uniform8Switch"
222   -->            "uniform8"
223   -->            "uniform8Active"
224   -->         "arrowTranslation"
225   -->         "arrow1Switch"
226   -->            "arrow1"
227   -->         "arrow2Switch"
228   -->            "arrow2"
229   -->         "arrow3Switch"
230   -->            "arrow3"
231   -->         "arrow4Switch"
232   -->            "arrow4"
233   -->         "arrow5Switch"
234   -->            "arrow5"
235   -->         "arrow6Switch"
236   -->            "arrow6"
237   \endverbatim
238 
239   \NODEKIT_POST_DIAGRAM
240 
241 
242   \NODEKIT_PRE_TABLE
243 
244   \verbatim
245   CLASS SoHandleBoxDragger
246   PVT   "this",  SoHandleBoxDragger  ---
247         "callbackList",  SoNodeKitListPart [ SoCallback, SoEventCallback ]
248   PVT   "topSeparator",  SoSeparator  ---
249   PVT   "motionMatrix",  SoMatrixTransform  ---
250         "surroundScale",  SoSurroundScale  ---
251   PVT   "geomSeparator",  SoSeparator  ---
252   PVT   "drawStyle",  SoDrawStyle  ---
253   PVT   "translator1Switch",  SoSwitch  ---
254         "translator1",  SoSeparator  ---
255         "translator1Active",  SoSeparator  ---
256   PVT   "translator2Switch",  SoSwitch  ---
257         "translator2",  SoSeparator  ---
258         "translator2Active",  SoSeparator  ---
259   PVT   "translator3Switch",  SoSwitch  ---
260         "translator3",  SoSeparator  ---
261         "translator3Active",  SoSeparator  ---
262   PVT   "translator4Switch",  SoSwitch  ---
263         "translator4",  SoSeparator  ---
264         "translator4Active",  SoSeparator  ---
265   PVT   "translator5Switch",  SoSwitch  ---
266         "translator5",  SoSeparator  ---
267         "translator5Active",  SoSeparator  ---
268   PVT   "translator6Switch",  SoSwitch  ---
269         "translator6",  SoSeparator  ---
270         "translator6Active",  SoSeparator  ---
271   PVT   "extruder1Switch",  SoSwitch  ---
272         "extruder1",  SoSeparator  ---
273         "extruder1Active",  SoSeparator  ---
274   PVT   "extruder2Switch",  SoSwitch  ---
275         "extruder2",  SoSeparator  ---
276         "extruder2Active",  SoSeparator  ---
277   PVT   "extruder3Switch",  SoSwitch  ---
278         "extruder3",  SoSeparator  ---
279         "extruder3Active",  SoSeparator  ---
280   PVT   "extruder4Switch",  SoSwitch  ---
281         "extruder4",  SoSeparator  ---
282         "extruder4Active",  SoSeparator  ---
283   PVT   "extruder5Switch",  SoSwitch  ---
284         "extruder5",  SoSeparator  ---
285         "extruder5Active",  SoSeparator  ---
286   PVT   "extruder6Switch",  SoSwitch  ---
287         "extruder6",  SoSeparator  ---
288         "extruder6Active",  SoSeparator  ---
289   PVT   "uniform1Switch",  SoSwitch  ---
290         "uniform1",  SoSeparator  ---
291         "uniform1Active",  SoSeparator  ---
292   PVT   "uniform2Switch",  SoSwitch  ---
293         "uniform2",  SoSeparator  ---
294         "uniform2Active",  SoSeparator  ---
295   PVT   "uniform3Switch",  SoSwitch  ---
296         "uniform3",  SoSeparator  ---
297         "uniform3Active",  SoSeparator  ---
298   PVT   "uniform4Switch",  SoSwitch  ---
299         "uniform4",  SoSeparator  ---
300         "uniform4Active",  SoSeparator  ---
301   PVT   "uniform5Switch",  SoSwitch  ---
302         "uniform5",  SoSeparator  ---
303         "uniform5Active",  SoSeparator  ---
304   PVT   "uniform6Switch",  SoSwitch  ---
305         "uniform6",  SoSeparator  ---
306         "uniform6Active",  SoSeparator  ---
307   PVT   "uniform7Switch",  SoSwitch  ---
308         "uniform7",  SoSeparator  ---
309         "uniform7Active",  SoSeparator  ---
310   PVT   "uniform8Switch",  SoSwitch  ---
311         "uniform8",  SoSeparator  ---
312         "uniform8Active",  SoSeparator  ---
313   PVT   "arrowTranslation",  SoTranslation  ---
314   PVT   "arrow1Switch",  SoSwitch  ---
315         "arrow1",  SoSeparator  ---
316   PVT   "arrow2Switch",  SoSwitch  ---
317         "arrow2",  SoSeparator  ---
318   PVT   "arrow3Switch",  SoSwitch  ---
319         "arrow3",  SoSeparator  ---
320   PVT   "arrow4Switch",  SoSwitch  ---
321         "arrow4",  SoSeparator  ---
322   PVT   "arrow5Switch",  SoSwitch  ---
323         "arrow5",  SoSeparator  ---
324   PVT   "arrow6Switch",  SoSwitch  ---
325         "arrow6",  SoSeparator  ---
326   \endverbatim
327 
328   \NODEKIT_POST_TABLE
329 */
SoHandleBoxDragger(void)330 SoHandleBoxDragger::SoHandleBoxDragger(void)
331 {
332   SO_KIT_INTERNAL_CONSTRUCTOR(SoHandleBoxDragger);
333 
334   SO_KIT_ADD_CATALOG_ENTRY(surroundScale, SoSurroundScale, TRUE, topSeparator, geomSeparator, TRUE);
335   SO_KIT_ADD_CATALOG_ENTRY(drawStyle, SoDrawStyle, TRUE, geomSeparator, translator1Switch, FALSE);
336   SO_KIT_ADD_CATALOG_ENTRY(translator1Switch, SoSwitch, TRUE, geomSeparator, translator2Switch, FALSE);
337   SO_KIT_ADD_CATALOG_ENTRY(translator1, SoSeparator, TRUE, translator1Switch, translator1Active, TRUE);
338   SO_KIT_ADD_CATALOG_ENTRY(translator1Active, SoSeparator, TRUE, translator1Switch, "", TRUE);
339   SO_KIT_ADD_CATALOG_ENTRY(translator2Switch, SoSwitch, TRUE, geomSeparator, translator3Switch, FALSE);
340   SO_KIT_ADD_CATALOG_ENTRY(translator2, SoSeparator, TRUE, translator2Switch, translator2Active, TRUE);
341   SO_KIT_ADD_CATALOG_ENTRY(translator2Active, SoSeparator, TRUE, translator2Switch, "", TRUE);
342   SO_KIT_ADD_CATALOG_ENTRY(translator3Switch, SoSwitch, TRUE, geomSeparator, translator4Switch, FALSE);
343   SO_KIT_ADD_CATALOG_ENTRY(translator3, SoSeparator, TRUE, translator3Switch, translator3Active, TRUE);
344   SO_KIT_ADD_CATALOG_ENTRY(translator3Active, SoSeparator, TRUE, translator3Switch, "", TRUE);
345   SO_KIT_ADD_CATALOG_ENTRY(translator4Switch, SoSwitch, TRUE, geomSeparator, translator5Switch, FALSE);
346   SO_KIT_ADD_CATALOG_ENTRY(translator4, SoSeparator, TRUE, translator4Switch, translator4Active, TRUE);
347   SO_KIT_ADD_CATALOG_ENTRY(translator4Active, SoSeparator, TRUE, translator4Switch, "", TRUE);
348   SO_KIT_ADD_CATALOG_ENTRY(translator5Switch, SoSwitch, TRUE, geomSeparator, translator6Switch, FALSE);
349   SO_KIT_ADD_CATALOG_ENTRY(translator5, SoSeparator, TRUE, translator5Switch, translator5Active, TRUE);
350   SO_KIT_ADD_CATALOG_ENTRY(translator5Active, SoSeparator, TRUE, translator5Switch, "", TRUE);
351   SO_KIT_ADD_CATALOG_ENTRY(translator6Switch, SoSwitch, TRUE, geomSeparator, extruder1Switch, FALSE);
352   SO_KIT_ADD_CATALOG_ENTRY(translator6, SoSeparator, TRUE, translator6Switch, translator6Active, TRUE);
353   SO_KIT_ADD_CATALOG_ENTRY(translator6Active, SoSeparator, TRUE, translator6Switch, "", TRUE);
354   SO_KIT_ADD_CATALOG_ENTRY(extruder1Switch, SoSwitch, TRUE, geomSeparator, extruder2Switch, FALSE);
355   SO_KIT_ADD_CATALOG_ENTRY(extruder1, SoSeparator, TRUE, extruder1Switch, extruder1Active, TRUE);
356   SO_KIT_ADD_CATALOG_ENTRY(extruder1Active, SoSeparator, TRUE, extruder1Switch, "", TRUE);
357   SO_KIT_ADD_CATALOG_ENTRY(extruder2Switch, SoSwitch, TRUE, geomSeparator, extruder3Switch, FALSE);
358   SO_KIT_ADD_CATALOG_ENTRY(extruder2, SoSeparator, TRUE, extruder2Switch, extruder2Active, TRUE);
359   SO_KIT_ADD_CATALOG_ENTRY(extruder2Active, SoSeparator, TRUE, extruder2Switch, "", TRUE);
360   SO_KIT_ADD_CATALOG_ENTRY(extruder3Switch, SoSwitch, TRUE, geomSeparator, extruder4Switch, FALSE);
361   SO_KIT_ADD_CATALOG_ENTRY(extruder3, SoSeparator, TRUE, extruder3Switch, extruder3Active, TRUE);
362   SO_KIT_ADD_CATALOG_ENTRY(extruder3Active, SoSeparator, TRUE, extruder3Switch, "", TRUE);
363   SO_KIT_ADD_CATALOG_ENTRY(extruder4Switch, SoSwitch, TRUE, geomSeparator, extruder5Switch, FALSE);
364   SO_KIT_ADD_CATALOG_ENTRY(extruder4, SoSeparator, TRUE, extruder4Switch, extruder4Active, TRUE);
365   SO_KIT_ADD_CATALOG_ENTRY(extruder4Active, SoSeparator, TRUE, extruder4Switch, "", TRUE);
366   SO_KIT_ADD_CATALOG_ENTRY(extruder5Switch, SoSwitch, TRUE, geomSeparator, extruder6Switch, FALSE);
367   SO_KIT_ADD_CATALOG_ENTRY(extruder5, SoSeparator, TRUE, extruder5Switch, extruder5Active, TRUE);
368   SO_KIT_ADD_CATALOG_ENTRY(extruder5Active, SoSeparator, TRUE, extruder5Switch, "", TRUE);
369   SO_KIT_ADD_CATALOG_ENTRY(extruder6Switch, SoSwitch, TRUE, geomSeparator, uniform1Switch, FALSE);
370   SO_KIT_ADD_CATALOG_ENTRY(extruder6, SoSeparator, TRUE, extruder6Switch, extruder6Active, TRUE);
371   SO_KIT_ADD_CATALOG_ENTRY(extruder6Active, SoSeparator, TRUE, extruder6Switch, "", TRUE);
372   SO_KIT_ADD_CATALOG_ENTRY(uniform1Switch, SoSwitch, TRUE, geomSeparator, uniform2Switch, FALSE);
373   SO_KIT_ADD_CATALOG_ENTRY(uniform1, SoSeparator, TRUE, uniform1Switch, uniform1Active, TRUE);
374   SO_KIT_ADD_CATALOG_ENTRY(uniform1Active, SoSeparator, TRUE, uniform1Switch, "", TRUE);
375   SO_KIT_ADD_CATALOG_ENTRY(uniform2Switch, SoSwitch, TRUE, geomSeparator, uniform3Switch, FALSE);
376   SO_KIT_ADD_CATALOG_ENTRY(uniform2, SoSeparator, TRUE, uniform2Switch, uniform2Active, TRUE);
377   SO_KIT_ADD_CATALOG_ENTRY(uniform2Active, SoSeparator, TRUE, uniform2Switch, "", TRUE);
378   SO_KIT_ADD_CATALOG_ENTRY(uniform3Switch, SoSwitch, TRUE, geomSeparator, uniform4Switch, FALSE);
379   SO_KIT_ADD_CATALOG_ENTRY(uniform3, SoSeparator, TRUE, uniform3Switch, uniform3Active, TRUE);
380   SO_KIT_ADD_CATALOG_ENTRY(uniform3Active, SoSeparator, TRUE, uniform3Switch, "", TRUE);
381   SO_KIT_ADD_CATALOG_ENTRY(uniform4Switch, SoSwitch, TRUE, geomSeparator, uniform5Switch, FALSE);
382   SO_KIT_ADD_CATALOG_ENTRY(uniform4, SoSeparator, TRUE, uniform4Switch, uniform4Active, TRUE);
383   SO_KIT_ADD_CATALOG_ENTRY(uniform4Active, SoSeparator, TRUE, uniform4Switch, "", TRUE);
384   SO_KIT_ADD_CATALOG_ENTRY(uniform5Switch, SoSwitch, TRUE, geomSeparator, uniform6Switch, FALSE);
385   SO_KIT_ADD_CATALOG_ENTRY(uniform5, SoSeparator, TRUE, uniform5Switch, uniform5Active, TRUE);
386   SO_KIT_ADD_CATALOG_ENTRY(uniform5Active, SoSeparator, TRUE, uniform5Switch, "", TRUE);
387   SO_KIT_ADD_CATALOG_ENTRY(uniform6Switch, SoSwitch, TRUE, geomSeparator, uniform7Switch, FALSE);
388   SO_KIT_ADD_CATALOG_ENTRY(uniform6, SoSeparator, TRUE, uniform6Switch, uniform6Active, TRUE);
389   SO_KIT_ADD_CATALOG_ENTRY(uniform6Active, SoSeparator, TRUE, uniform6Switch, "", TRUE);
390   SO_KIT_ADD_CATALOG_ENTRY(uniform7Switch, SoSwitch, TRUE, geomSeparator, uniform8Switch, FALSE);
391   SO_KIT_ADD_CATALOG_ENTRY(uniform7, SoSeparator, TRUE, uniform7Switch, uniform7Active, TRUE);
392   SO_KIT_ADD_CATALOG_ENTRY(uniform7Active, SoSeparator, TRUE, uniform7Switch, "", TRUE);
393   SO_KIT_ADD_CATALOG_ENTRY(uniform8Switch, SoSwitch, TRUE, geomSeparator, arrowTranslation, FALSE);
394   SO_KIT_ADD_CATALOG_ENTRY(uniform8, SoSeparator, TRUE, uniform8Switch, uniform8Active, TRUE);
395   SO_KIT_ADD_CATALOG_ENTRY(uniform8Active, SoSeparator, TRUE, uniform8Switch, "", TRUE);
396   SO_KIT_ADD_CATALOG_ENTRY(arrowTranslation, SoTranslation, TRUE, geomSeparator, arrow1Switch, FALSE);
397   SO_KIT_ADD_CATALOG_ENTRY(arrow1Switch, SoSwitch, TRUE, geomSeparator, arrow2Switch, FALSE);
398   SO_KIT_ADD_CATALOG_ENTRY(arrow1, SoSeparator, TRUE, arrow1Switch, "", TRUE);
399   SO_KIT_ADD_CATALOG_ENTRY(arrow2Switch, SoSwitch, TRUE, geomSeparator, arrow3Switch, FALSE);
400   SO_KIT_ADD_CATALOG_ENTRY(arrow2, SoSeparator, TRUE, arrow2Switch, "", TRUE);
401   SO_KIT_ADD_CATALOG_ENTRY(arrow3Switch, SoSwitch, TRUE, geomSeparator, arrow4Switch, FALSE);
402   SO_KIT_ADD_CATALOG_ENTRY(arrow3, SoSeparator, TRUE, arrow3Switch, "", TRUE);
403   SO_KIT_ADD_CATALOG_ENTRY(arrow4Switch, SoSwitch, TRUE, geomSeparator, arrow5Switch, FALSE);
404   SO_KIT_ADD_CATALOG_ENTRY(arrow4, SoSeparator, TRUE, arrow4Switch, "", TRUE);
405   SO_KIT_ADD_CATALOG_ENTRY(arrow5Switch, SoSwitch, TRUE, geomSeparator, arrow6Switch, FALSE);
406   SO_KIT_ADD_CATALOG_ENTRY(arrow5, SoSeparator, TRUE, arrow5Switch, "", TRUE);
407   SO_KIT_ADD_CATALOG_ENTRY(arrow6Switch, SoSwitch, TRUE, geomSeparator, "", FALSE);
408   SO_KIT_ADD_CATALOG_ENTRY(arrow6, SoSeparator, TRUE, arrow6Switch, "", TRUE);
409 
410   if (SO_KIT_IS_FIRST_INSTANCE()) {
411     SoInteractionKit::readDefaultParts("handleBoxDragger.iv",
412                                        HANDLEBOXDRAGGER_draggergeometry,
413                                        static_cast<int>(strlen(HANDLEBOXDRAGGER_draggergeometry)));
414   }
415 
416   SO_KIT_ADD_FIELD(translation, (0.0f, 0.0f, 0.0f));
417   SO_KIT_ADD_FIELD(scaleFactor, (1.0f, 1.0f, 1.0f));
418 
419   SO_KIT_INIT_INSTANCE();
420 
421   this->setPartAsDefault("translator1", "handleBoxTranslator1");
422   this->setPartAsDefault("translator2", "handleBoxTranslator2");
423   this->setPartAsDefault("translator3", "handleBoxTranslator3");
424   this->setPartAsDefault("translator4", "handleBoxTranslator4");
425   this->setPartAsDefault("translator5", "handleBoxTranslator5");
426   this->setPartAsDefault("translator6", "handleBoxTranslator6");
427 
428   this->setPartAsDefault("translator1Active", "handleBoxTranslator1Active");
429   this->setPartAsDefault("translator2Active", "handleBoxTranslator2Active");
430   this->setPartAsDefault("translator3Active", "handleBoxTranslator3Active");
431   this->setPartAsDefault("translator4Active", "handleBoxTranslator4Active");
432   this->setPartAsDefault("translator5Active", "handleBoxTranslator5Active");
433   this->setPartAsDefault("translator6Active", "handleBoxTranslator6Active");
434 
435   this->setPartAsDefault("extruder1", "handleBoxExtruder1");
436   this->setPartAsDefault("extruder2", "handleBoxExtruder2");
437   this->setPartAsDefault("extruder3", "handleBoxExtruder3");
438   this->setPartAsDefault("extruder4", "handleBoxExtruder4");
439   this->setPartAsDefault("extruder5", "handleBoxExtruder5");
440   this->setPartAsDefault("extruder6", "handleBoxExtruder6");
441 
442   this->setPartAsDefault("extruder1Active", "handleBoxExtruder1Active");
443   this->setPartAsDefault("extruder2Active", "handleBoxExtruder2Active");
444   this->setPartAsDefault("extruder3Active", "handleBoxExtruder3Active");
445   this->setPartAsDefault("extruder4Active", "handleBoxExtruder4Active");
446   this->setPartAsDefault("extruder5Active", "handleBoxExtruder5Active");
447   this->setPartAsDefault("extruder6Active", "handleBoxExtruder6Active");
448 
449   this->setPartAsDefault("uniform1", "handleBoxUniform1");
450   this->setPartAsDefault("uniform2", "handleBoxUniform2");
451   this->setPartAsDefault("uniform3", "handleBoxUniform3");
452   this->setPartAsDefault("uniform4", "handleBoxUniform4");
453   this->setPartAsDefault("uniform5", "handleBoxUniform5");
454   this->setPartAsDefault("uniform6", "handleBoxUniform6");
455   this->setPartAsDefault("uniform7", "handleBoxUniform7");
456   this->setPartAsDefault("uniform8", "handleBoxUniform8");
457 
458   this->setPartAsDefault("uniform1Active", "handleBoxUniform1Active");
459   this->setPartAsDefault("uniform2Active", "handleBoxUniform2Active");
460   this->setPartAsDefault("uniform3Active", "handleBoxUniform3Active");
461   this->setPartAsDefault("uniform4Active", "handleBoxUniform4Active");
462   this->setPartAsDefault("uniform5Active", "handleBoxUniform5Active");
463   this->setPartAsDefault("uniform6Active", "handleBoxUniform6Active");
464   this->setPartAsDefault("uniform7Active", "handleBoxUniform7Active");
465   this->setPartAsDefault("uniform8Active", "handleBoxUniform8Active");
466 
467   this->setPartAsDefault("arrow1", "handleBoxArrow1");
468   this->setPartAsDefault("arrow2", "handleBoxArrow2");
469   this->setPartAsDefault("arrow3", "handleBoxArrow3");
470   this->setPartAsDefault("arrow4", "handleBoxArrow4");
471   this->setPartAsDefault("arrow5", "handleBoxArrow5");
472   this->setPartAsDefault("arrow6", "handleBoxArrow6");
473 
474   this->constraintState = CONSTRAINT_OFF;
475   this->whatkind = WHATKIND_NONE;
476 
477   this->setAllPartsActive(FALSE);
478 
479   this->planeProj = new SbPlaneProjector;
480   this->lineProj = new SbLineProjector;
481 
482   this->addStartCallback(SoHandleBoxDragger::startCB);
483   this->addMotionCallback(SoHandleBoxDragger::motionCB);
484   this->addFinishCallback(SoHandleBoxDragger::finishCB);
485   this->addValueChangedCallback(SoHandleBoxDragger::valueChangedCB);
486   this->addOtherEventCallback(SoHandleBoxDragger::metaKeyChangeCB);
487 
488   this->translFieldSensor = new SoFieldSensor(SoHandleBoxDragger::fieldSensorCB, this);
489   this->translFieldSensor->setPriority(0);
490   this->scaleFieldSensor = new SoFieldSensor(SoHandleBoxDragger::fieldSensorCB, this);
491   this->scaleFieldSensor->setPriority(0);
492 
493   this->setUpConnections(TRUE, TRUE);
494 }
495 
496 /*!
497   Protected destructor.
498 
499   (Dragger classes are derived from SoBase, so they are reference
500   counted and automatically destroyed when their reference count goes
501   to 0.)
502  */
~SoHandleBoxDragger()503 SoHandleBoxDragger::~SoHandleBoxDragger()
504 {
505   delete this->lineProj;
506   delete this->planeProj;
507   delete this->translFieldSensor;
508   delete this->scaleFieldSensor;
509 }
510 
511 // Doc in superclass.
512 SbBool
setUpConnections(SbBool onoff,SbBool doitalways)513 SoHandleBoxDragger::setUpConnections(SbBool onoff, SbBool doitalways)
514 {
515   if (!doitalways && this->connectionsSetUp == onoff) return onoff;
516 
517   if (onoff) {
518     inherited::setUpConnections(onoff, doitalways);
519 
520     SoHandleBoxDragger::fieldSensorCB(this, NULL);
521 
522     if (this->translFieldSensor->getAttachedField() != &this->translation) {
523       this->translFieldSensor->attach(&this->translation);
524     }
525     if (this->scaleFieldSensor->getAttachedField() != &this->scaleFactor) {
526       this->scaleFieldSensor->attach(&this->scaleFactor);
527     }
528 
529   }
530   else {
531     if (this->translFieldSensor->getAttachedField() != NULL) {
532       this->translFieldSensor->detach();
533     }
534     if (this->scaleFieldSensor->getAttachedField() != NULL) {
535       this->scaleFieldSensor->detach();
536     }
537     inherited::setUpConnections(onoff, doitalways);
538   }
539   return !(this->connectionsSetUp = onoff);
540 }
541 
542 // Doc in superclass.
543 void
setDefaultOnNonWritingFields(void)544 SoHandleBoxDragger::setDefaultOnNonWritingFields(void)
545 {
546   this->surroundScale.setDefault(TRUE);
547   this->arrowTranslation.setDefault(TRUE);
548   this->drawStyle.setDefault(TRUE);
549 
550   inherited::setDefaultOnNonWritingFields();
551 }
552 
553 /*! \COININTERNAL */
554 void
fieldSensorCB(void * d,SoSensor *)555 SoHandleBoxDragger::fieldSensorCB(void * d, SoSensor *)
556 {
557   SoHandleBoxDragger * thisp = static_cast<SoHandleBoxDragger *>(d);
558   SbMatrix matrix = thisp->getMotionMatrix();
559   thisp->workFieldsIntoTransform(matrix);
560   thisp->setMotionMatrix(matrix);
561 }
562 
563 /*! \COININTERNAL */
564 void
valueChangedCB(void * COIN_UNUSED_ARG (f),SoDragger * d)565 SoHandleBoxDragger::valueChangedCB(void * COIN_UNUSED_ARG(f), SoDragger * d)
566 {
567   SoHandleBoxDragger * thisp = static_cast<SoHandleBoxDragger *>(d);
568   SbMatrix matrix = thisp->getMotionMatrix();
569   SbVec3f trans, scale;
570   SbRotation rot, scaleOrient;
571   matrix.getTransform(trans, rot, scale, scaleOrient);
572 
573   thisp->translFieldSensor->detach();
574   if (thisp->translation.getValue() != trans)
575     thisp->translation = trans;
576   thisp->translFieldSensor->attach(&thisp->translation);
577 
578   thisp->scaleFieldSensor->detach();
579   if (thisp->scaleFactor.getValue() != scale)
580     thisp->scaleFactor = scale;
581   thisp->scaleFieldSensor->attach(&thisp->scaleFactor);
582 }
583 
584 /*! \COININTERNAL */
585 void
startCB(void *,SoDragger * d)586 SoHandleBoxDragger::startCB(void *, SoDragger * d)
587 {
588   SoHandleBoxDragger * thisp = static_cast<SoHandleBoxDragger *>(d);
589   thisp->dragStart();
590 }
591 
592 /*! \COININTERNAL */
593 void
motionCB(void *,SoDragger * d)594 SoHandleBoxDragger::motionCB(void *, SoDragger * d)
595 {
596   SoHandleBoxDragger * thisp = static_cast<SoHandleBoxDragger *>(d);
597   thisp->drag();
598 }
599 
600 /*! \COININTERNAL */
601 void
finishCB(void *,SoDragger * d)602 SoHandleBoxDragger::finishCB(void *, SoDragger * d)
603 {
604   SoHandleBoxDragger * thisp = static_cast<SoHandleBoxDragger *>(d);
605   thisp->dragFinish();
606 }
607 
608 /*! \COININTERNAL */
609 void
metaKeyChangeCB(void *,SoDragger * d)610 SoHandleBoxDragger::metaKeyChangeCB(void *, SoDragger * d)
611 {
612   SoHandleBoxDragger * thisp = static_cast<SoHandleBoxDragger *>(d);
613   if (!thisp->isActive.getValue()) return;
614 
615   const SoEvent *event = thisp->getEvent();
616   if (SO_KEY_RELEASE_EVENT(event, LEFT_SHIFT) ||
617       SO_KEY_RELEASE_EVENT(event, RIGHT_SHIFT)) {
618     if (thisp->constraintState != CONSTRAINT_OFF) thisp->drag();
619   }
620   else if (thisp->ctrlDown != event->wasCtrlDown()) {
621     thisp->ctrlDown = !thisp->ctrlDown;
622     thisp->updateSwitches();
623   }
624 }
625 
626 // Invalidate surround scale node, if it exists.
627 //
628 // Note: keep the function name prefix to avoid name clashes with
629 // other dragger .cpp files for "--enable-compact" builds.
630 //
631 // FIXME: should collect these methods in a common method visible to
632 // all draggers implementing the exact same functionality. 20010826 mortene.
633 static void
SoHandleBoxDragger_invalidate_surroundscale(SoBaseKit * kit)634 SoHandleBoxDragger_invalidate_surroundscale(SoBaseKit * kit)
635 {
636   SoSurroundScale * ss = coin_safe_cast<SoSurroundScale *>(
637     kit->getPart("surroundScale", FALSE)
638     );
639   if (ss) ss->invalidate();
640 }
641 
642 /*! \COININTERNAL
643   Called when dragger is selected (picked) by the user.
644 */
645 void
dragStart(void)646 SoHandleBoxDragger::dragStart(void)
647 {
648   SoHandleBoxDragger_invalidate_surroundscale(this);
649 
650   static const char translatorname[] = "translator";
651   static const char extrudername[] = "extruder";
652   static const char uniformname[] = "uniform";
653 
654   const SoPath *pickpath = this->getPickPath();
655 
656   SbBool found = FALSE;
657   this->whatkind = WHATKIND_NONE;
658   this->whatnum = 0;
659 
660   int i;
661   SbString str;
662   if (!found) {
663     for (i = 1; i <= 6; i++) {
664       str.sprintf("%s%d", translatorname, i);
665       if (pickpath->findNode(this->getNodeFieldNode(str.getString())) >= 0||
666           this->getSurrogatePartPickedName() == str.getString()) break;
667     }
668     if (i <= 6) {
669       found = TRUE;
670       this->whatkind = WHATKIND_TRANSLATOR;
671       this->whatnum = i;
672     }
673   }
674 
675   if (!found) {
676     for (i = 1; i <= 6; i++) {
677       str.sprintf("%s%d", extrudername, i);
678       if (pickpath->findNode(this->getNodeFieldNode(str.getString()))>= 0 ||
679           this->getSurrogatePartPickedName() == str.getString()) break;
680     }
681     if (i <= 6) {
682       found = TRUE;
683       this->whatkind = WHATKIND_EXTRUDER;
684       this->whatnum = i;
685     }
686   }
687   if (!found) {
688     for (i = 1; i <= 8; i++) {
689       str.sprintf("%s%d", uniformname, i);
690       if (pickpath->findNode(this->getNodeFieldNode(str.getString()))>= 0 ||
691           this->getSurrogatePartPickedName() == str.getString()) break;
692     }
693     if (i <= 8) {
694       found = TRUE;
695       this->whatkind = WHATKIND_UNIFORM;
696       this->whatnum = i;
697     }
698   }
699   assert(found);
700   if (!found) return;
701 
702   SbVec3f startPt = this->getLocalStartingPoint();
703 
704   switch(this->whatkind) {
705   case WHATKIND_TRANSLATOR:
706     {
707       SbVec3f n;
708       if (this->whatnum <= 2) {
709         n = SbVec3f(0.0f, 1.0f, 0.0f);
710       }
711       else if (this->whatnum <= 4) {
712         n = SbVec3f(1.0f, 0.0f, 0.0f);
713       }
714       else {
715         n = SbVec3f(0.0f, 0.0f, 1.0f);
716       }
717       SbVec3f localPt;
718       {
719         SbMatrix mat, inv;
720         this->getSurroundScaleMatrices(mat, inv);
721         inv.multVecMatrix(startPt, localPt);
722       }
723       this->planeProj->setPlane(SbPlane(n, startPt));
724       SbLine myline(SbVec3f(0.0f, 0.0f, 0.0f), n);
725       SoTranslation *t = SO_GET_ANY_PART(this, "arrowTranslation", SoTranslation);
726       t->translation = myline.getClosestPoint(localPt);
727       if (this->getEvent()->wasShiftDown()) {
728         this->getLocalToWorldMatrix().multVecMatrix(startPt, this->worldRestartPt);
729         this->constraintState = CONSTRAINT_WAIT;
730       }
731     }
732     break;
733   case WHATKIND_EXTRUDER:
734     this->lineProj->setLine(SbLine(this->getDraggerCenter(), startPt));
735     this->ctrlOffset = this->calcCtrlOffset(startPt);
736     break;
737   case WHATKIND_UNIFORM:
738     this->lineProj->setLine(SbLine(this->getDraggerCenter(), startPt));
739     this->ctrlOffset = this->calcCtrlOffset(startPt);
740     break;
741   }
742   this->ctrlDown = this->getEvent()->wasCtrlDown();
743   this->updateSwitches();
744 }
745 
746 /*! \COININTERNAL
747   Called when user drags the mouse after picking the dragger.
748 */
749 void
drag(void)750 SoHandleBoxDragger::drag(void)
751 {
752   SbVec3f startPt = this->getLocalStartingPoint();
753 
754   if (this->whatkind == WHATKIND_TRANSLATOR) {
755     this->planeProj->setViewVolume(this->getViewVolume());
756     this->planeProj->setWorkingSpace(this->getLocalToWorldMatrix());
757     SbVec3f projPt = this->planeProj->project(this->getNormalizedLocaterPosition());
758 
759     const SoEvent *event = this->getEvent();
760     if (event->wasShiftDown() && this->constraintState == CONSTRAINT_OFF) {
761       this->constraintState = CONSTRAINT_WAIT;
762       this->setStartLocaterPosition(event->getPosition());
763       this->getLocalToWorldMatrix().multVecMatrix(projPt, this->worldRestartPt);
764     }
765     else if (!event->wasShiftDown() && this->constraintState != CONSTRAINT_OFF) {
766       this->constraintState = CONSTRAINT_OFF;
767       this->updateArrows();
768     }
769 
770     SbVec3f motion, localrestartpt;
771     if (this->constraintState != CONSTRAINT_OFF) {
772       this->getWorldToLocalMatrix().multVecMatrix(this->worldRestartPt,
773                                                   localrestartpt);
774       motion = localrestartpt - startPt;
775     }
776     else motion = projPt - startPt;
777     switch(this->constraintState) {
778     case CONSTRAINT_OFF:
779       break;
780     case CONSTRAINT_WAIT:
781       if (this->isAdequateConstraintMotion()) {
782         SbVec3f newmotion = projPt - localrestartpt;
783         int biggest = 0;
784         double bigval = fabs(newmotion[0]);
785         if (fabs(newmotion[1]) > bigval) {
786           biggest = 1;
787           bigval = fabs(newmotion[1]);
788         }
789         if (fabs(newmotion[2]) > bigval) {
790           biggest = 2;
791         }
792         motion[biggest] += newmotion[biggest];
793         this->constraintState = CONSTRAINT_X + biggest;
794         this->updateArrows();
795       }
796       else {
797         return;
798       }
799       break;
800     case CONSTRAINT_X:
801       motion[0] += projPt[0] - localrestartpt[0];
802       break;
803     case CONSTRAINT_Y:
804       motion[1] += projPt[1] - localrestartpt[1];
805       break;
806     case CONSTRAINT_Z:
807       motion[2] += projPt[2] - localrestartpt[2];
808     }
809     this->setMotionMatrix(this->appendTranslation(this->getStartMotionMatrix(), motion));
810   }
811   else {
812     this->lineProj->setViewVolume(this->getViewVolume());
813     this->lineProj->setWorkingSpace(this->getLocalToWorldMatrix());
814     SbVec3f projPt = this->lineProj->project(this->getNormalizedLocaterPosition());
815     SbVec3f center = this->getDraggerCenter();
816     if (this->getEvent()->wasCtrlDown()) {
817       center += this->ctrlOffset;
818     }
819 
820     float orglen = (startPt-center).length();
821     float currlen = (projPt-center).length();
822     float scale = 0.0f;
823 
824     if (orglen > 0.0f) scale = currlen / orglen;
825     if (scale > 0.0f && (startPt-center).dot(projPt-center) <= 0.0f) scale = 0.0f;
826 
827     SbVec3f scalevec(scale, scale, scale);
828     if (this->whatkind == WHATKIND_EXTRUDER) {
829       if (this->whatnum <= 2) scalevec[0] = scalevec[2] = 1.0f;
830       else if (this->whatnum <= 4) scalevec[1] = scalevec[2] = 1.0f;
831       else scalevec[0] = scalevec[1] = 1.0f;
832     }
833 
834     this->setMotionMatrix(this->appendScale(this->getStartMotionMatrix(),
835                                             scalevec,
836                                             center));
837   }
838 }
839 
840 /*! \COININTERNAL
841   Called when mouse button is released after picking and interacting
842   with the dragger.
843 */
844 void
dragFinish(void)845 SoHandleBoxDragger::dragFinish(void)
846 {
847   this->constraintState = CONSTRAINT_OFF;
848   this->whatkind = WHATKIND_NONE;
849   this->setAllPartsActive(FALSE);
850 
851   SoHandleBoxDragger_invalidate_surroundscale(this);
852 }
853 
854 /*!
855   Activate or deactive all dragger geometry parts.
856 */
857 void
setAllPartsActive(SbBool onoroff)858 SoHandleBoxDragger::setAllPartsActive(SbBool onoroff)
859 {
860   int i;
861   int val = onoroff ? 1 : 0;
862   SoSwitch *sw;
863   SbString str;
864   for (i = 1; i <= 6; i++) {
865     str.sprintf("translator%dSwitch", i);
866     sw = SO_GET_ANY_PART(this, str.getString(), SoSwitch);
867     SoInteractionKit::setSwitchValue(sw, val);
868   }
869   for (i = 1; i <= 6; i++) {
870     str.sprintf("extruder%dSwitch", i);
871     sw = SO_GET_ANY_PART(this, str.getString(), SoSwitch);
872     SoInteractionKit::setSwitchValue(sw, val);
873   }
874   for (i = 1; i <= 8; i++) {
875     str.sprintf("uniform%dSwitch", i);
876     sw = SO_GET_ANY_PART(this, str.getString(), SoSwitch);
877     SoInteractionKit::setSwitchValue(sw, val);
878   }
879   this->updateArrows();
880 }
881 
882 // Return node pointer from a SoSFNode field. Does misc sanity
883 // checking for robustness.
884 SoNode *
getNodeFieldNode(const char * fieldname)885 SoHandleBoxDragger::getNodeFieldNode(const char * fieldname)
886 {
887   SoField * field = this->getField(fieldname);
888   assert(field != NULL);
889   assert(coin_assert_cast<SoSFNode *>(field)->getValue() != NULL);
890   return coin_assert_cast<SoSFNode *>(field)->getValue();
891 }
892 
893 void
updateSwitches(void)894 SoHandleBoxDragger::updateSwitches(void)
895 {
896   int i;
897   SbString str;
898   SoSwitch *sw;
899 
900   if (this->whatkind == WHATKIND_UNIFORM) {
901     if (this->ctrlDown) {
902       const int *ptr = uniform_ctrl_lookup[this->whatnum-1];
903       for (i = 0; i < 6; i++) {
904         str.sprintf("extruder%dSwitch", ptr[i]);
905         sw = SO_GET_ANY_PART(this, str.getString(), SoSwitch);
906         SoInteractionKit::setSwitchValue(sw, i < 3 ? 1 : 0);
907       }
908     }
909     else {
910       for (i = 1; i <= 6; i++) {
911         str.sprintf("extruder%dSwitch", i);
912         sw = SO_GET_ANY_PART(this, str.getString(), SoSwitch);
913         SoInteractionKit::setSwitchValue(sw, 1);
914       }
915     }
916     str.sprintf("uniform%dSwitch", this->whatnum);
917     sw = SO_GET_ANY_PART(this, str.getString(), SoSwitch);
918     SoInteractionKit::setSwitchValue(sw, 1);
919   }
920   else if (this->whatkind == WHATKIND_EXTRUDER) {
921     int othernum = ((this->whatnum-1) & ~1) + 1;
922     if (othernum == this->whatnum) othernum++;
923 
924     str.sprintf("extruder%dSwitch", this->whatnum);
925     sw = SO_GET_ANY_PART(this, str.getString(), SoSwitch);
926     SoInteractionKit::setSwitchValue(sw, 1);
927     str.sprintf("extruder%dSwitch", othernum);
928     sw = SO_GET_ANY_PART(this, str.getString(), SoSwitch);
929     SoInteractionKit::setSwitchValue(sw, this->ctrlDown ? 0 : 1);
930   }
931   else {
932     this->setAllPartsActive(TRUE);
933     this->updateArrows();
934   }
935 }
936 
937 void
updateArrows(void)938 SoHandleBoxDragger::updateArrows(void)
939 {
940   int i;
941   SbString str;
942   SoSwitch *sw;
943 
944   if (this->constraintState >= CONSTRAINT_X) {
945     int onval = -1;
946     switch (this->constraintState) {
947     case CONSTRAINT_X:
948       onval = 3;
949       break;
950     case CONSTRAINT_Y:
951       onval = 1;
952       break;
953     case CONSTRAINT_Z:
954       onval = 5;
955       break;
956     }
957     for (i = 1; i <= 6; i++) {
958       str.sprintf("arrow%dSwitch", i);
959       sw = SO_GET_ANY_PART(this, str.getString(), SoSwitch);
960       if (i == onval || i == onval + 1) {
961         SoInteractionKit::setSwitchValue(sw, 0);
962       }
963       else {
964         SoInteractionKit::setSwitchValue(sw, SO_SWITCH_NONE);
965       }
966     }
967   }
968   else if (this->whatkind == WHATKIND_TRANSLATOR) {
969     int num = (this->whatnum-1) & ~1;
970     for (i = 0; i < 6; i++) {
971       str.sprintf("arrow%dSwitch", i+1);
972       sw = SO_GET_ANY_PART(this, str.getString(), SoSwitch);
973       if (i == num || i == num+1) {
974         SoInteractionKit::setSwitchValue(sw, SO_SWITCH_NONE);
975       }
976       else {
977         SoInteractionKit::setSwitchValue(sw, 0);
978       }
979     }
980   }
981   else {
982     for (i = 1; i <= 6; i++) {
983       str.sprintf("arrow%dSwitch", i);
984       sw = SO_GET_ANY_PART(this, str.getString(), SoSwitch);
985       SoInteractionKit::setSwitchValue(sw, SO_SWITCH_NONE);
986     }
987   }
988 }
989 
990 void
getSurroundScaleMatrices(SbMatrix & mat,SbMatrix & inv)991 SoHandleBoxDragger::getSurroundScaleMatrices(SbMatrix &mat, SbMatrix &inv)
992 {
993   if (this->surroundScale.getValue()) {
994     this->getPartToLocalMatrix("surroundScale", mat, inv);
995   }
996   else {
997     mat = inv = SbMatrix::identity();
998   }
999 }
1000 
1001 SbVec3f
getDraggerCenter(void)1002 SoHandleBoxDragger::getDraggerCenter(void)
1003 {
1004   SbMatrix mat, inv;
1005   this->getSurroundScaleMatrices(mat, inv);
1006   return SbVec3f(mat[3][0], mat[3][1], mat[3][2]);
1007 }
1008 
1009 SbVec3f
calcCtrlOffset(const SbVec3f startpt)1010 SoHandleBoxDragger::calcCtrlOffset(const SbVec3f startpt)
1011 {
1012   SbMatrix m, inv;
1013   this->getSurroundScaleMatrices(m, inv);
1014   SbVec3f v = SbVec3f(m[3][0], m[3][1], m[3][2]) - startpt;
1015 
1016   for (int i = 0; i < 3; i++) {
1017     v[i] *= inv[i][i];
1018     if (v[i] < -0.95) v[i] = -1.0f;
1019     else if (v[i] > 0.95) v[i] = 1.0f;
1020     else v[i] = 0.0f;
1021     v[i] *= m[i][i];
1022   }
1023   return v;
1024 }
1025 
1026 #undef WHATKIND_NONE
1027 #undef WHATKIND_TRANSLATOR
1028 #undef WHATKIND_EXTRUDER
1029 #undef WHATKIND_UNIFORM
1030 #undef CONSTRAINT_OFF
1031 #undef CONSTRAINT_WAIT
1032 #undef CONSTRAINT_X
1033 #undef CONSTRAINT_Y
1034 #undef CONSTRAINT_Z
1035 
1036 #endif // HAVE_DRAGGERS
1037