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 SoTabPlaneDragger SoTabPlaneDragger.h Inventor/draggers/SoTabPlaneDragger.h
41 \brief The SoTabPlaneDragger class is a dragger you can translate and scale within a plane.
42
43 \ingroup draggers
44
45 \DRAGGER_DEFAULT_SCREENSHOT
46
47 <center>
48 \image html tabplane.png "Screen Shot of Default Dragger"
49 </center>
50
51 For translation, click anywhere inside the dragger's plane and move
52 it about in 2D.
53
54 For non-uniform scaling operations, click and drag any of the 4 side
55 tabs. For uniform scaling, click and drag any of the 4 corner tabs.
56
57 \sa SoTabBoxDragger
58 */
59
60 #include <Inventor/draggers/SoTabPlaneDragger.h>
61
62 #include <cstring>
63 #include <cassert>
64
65 #include <Inventor/nodes/SoCoordinate3.h>
66 #include <Inventor/nodes/SoIndexedFaceSet.h>
67 #include <Inventor/nodes/SoMaterial.h>
68 #include <Inventor/nodes/SoMaterialBinding.h>
69 #include <Inventor/nodes/SoNormal.h>
70 #include <Inventor/nodes/SoNormalBinding.h>
71 #include <Inventor/nodes/SoSeparator.h>
72 #include <Inventor/nodes/SoShapeHints.h>
73 #include <Inventor/nodes/SoSwitch.h>
74 #include <Inventor/projectors/SbPlaneProjector.h>
75 #include <Inventor/projectors/SbLineProjector.h>
76 #include <Inventor/events/SoKeyboardEvent.h>
77 #include <Inventor/sensors/SoFieldSensor.h>
78 #include <Inventor/actions/SoGLRenderAction.h>
79 #include <Inventor/elements/SoModelMatrixElement.h>
80 #include <Inventor/elements/SoViewVolumeElement.h>
81 #include <Inventor/elements/SoViewportRegionElement.h>
82 #include <Inventor/elements/SoCacheElement.h>
83 #include <Inventor/SbRotation.h>
84
85 #include <data/draggerDefaults/tabPlaneDragger.h>
86
87 #include "coindefs.h" // COIN_STUB()
88 #include "nodekits/SoSubKitP.h"
89 #include "SbBasicP.h"
90
91 /*!
92 \var SoSFVec3f SoTabPlaneDragger::translation
93
94 Continuously updated to contain the current translation from the
95 dragger's local origo position.
96 */
97
98 /*!
99 \var SoSFVec3f SoTabPlaneDragger::scaleFactor
100
101 Continuously updated to contain the current vector of scaling along
102 the X, Y and Z axes. The Z component will always be 1.0.
103 */
104
105 #define WHATKIND_NONE 0
106 #define WHATKIND_SCALE 1
107 #define WHATKIND_TRANSLATE 2
108
109 #define CONSTRAINT_OFF 0
110 #define CONSTRAINT_WAIT 1
111 #define CONSTRAINT_X 2
112 #define CONSTRAINT_Y 3
113 #define CONSTRAINT_Z 4
114
115
116 // used to quickly find correct position of tabs
117
118 static float edgetab_lookup[] = {
119 0.0f, 1.0f,
120 1.0f, 0.0f,
121 0.0f, -1.0f,
122 -1.0f, 0.0f
123 };
124
125 static float cornertab_lookup[] = {
126 1.0f, 1.0f,
127 1.0f, -1.0f,
128 -1.0f, -1.0f,
129 -1.0f, 1.0f
130 };
131
132 // FIXME: find a better solution than this lame Z_OFFSET hack, pederb 20000301
133 #define Z_OFFSET 0.01f // dummy offset for tabs to get "correct" picking
134 #define TABSIZE 10.0f // size (in pixels when projected to screen) of tabs
135
136 #define THISP(d) static_cast<SoTabPlaneDragger *>(d)
137
138 class SoTabPlaneDraggerP {
139 public:
140 };
141
142 SO_KIT_SOURCE(SoTabPlaneDragger);
143
144 // doc in superclass
145 void
initClass(void)146 SoTabPlaneDragger::initClass(void)
147 {
148 SO_KIT_INTERNAL_INIT_CLASS(SoTabPlaneDragger, SO_FROM_INVENTOR_1);
149 }
150
151 // FIXME: document which parts need to be present in the geometry
152 // scenegraph, and what role they play in the dragger. 20010913 mortene.
153 /*!
154 \DRAGGER_CONSTRUCTOR
155
156 \NODEKIT_PRE_DIAGRAM
157
158 \verbatim
159 CLASS SoTabPlaneDragger
160 -->"this"
161 "callbackList"
162 "topSeparator"
163 "motionMatrix"
164 "geomSeparator"
165 --> "planeSwitch"
166 --> "translator"
167 --> "scaleTabs"
168 --> "scaleTabMaterial"
169 --> "scaleTabHints"
170 --> "scaleTabMaterialBinding"
171 --> "scaleTabNormalBinding"
172 --> "scaleTabNormal"
173 --> "edgeScaleCoords"
174 --> "edgeScaleTab0"
175 --> "edgeScaleTab1"
176 --> "edgeScaleTab2"
177 --> "edgeScaleTab3"
178 --> "cornerScaleCoords"
179 --> "cornerScaleTab0"
180 --> "cornerScaleTab1"
181 --> "cornerScaleTab2"
182 --> "cornerScaleTab3"
183 \endverbatim
184
185 \NODEKIT_POST_DIAGRAM
186
187
188 \NODEKIT_PRE_TABLE
189
190 \verbatim
191 CLASS SoTabPlaneDragger
192 PVT "this", SoTabPlaneDragger ---
193 "callbackList", SoNodeKitListPart [ SoCallback, SoEventCallback ]
194 PVT "topSeparator", SoSeparator ---
195 PVT "motionMatrix", SoMatrixTransform ---
196 PVT "geomSeparator", SoSeparator ---
197 PVT "planeSwitch", SoSwitch ---
198 "translator", SoSeparator ---
199 PVT "scaleTabs", SoSeparator ---
200 "scaleTabMaterial", SoMaterial ---
201 "scaleTabHints", SoShapeHints ---
202 PVT "scaleTabMaterialBinding", SoMaterialBinding ---
203 PVT "scaleTabNormalBinding", SoNormalBinding ---
204 PVT "scaleTabNormal", SoNormal ---
205 PVT "edgeScaleCoords", SoCoordinate3 ---
206 PVT "edgeScaleTab0", SoIndexedFaceSet ---
207 PVT "edgeScaleTab1", SoIndexedFaceSet ---
208 PVT "edgeScaleTab2", SoIndexedFaceSet ---
209 PVT "edgeScaleTab3", SoIndexedFaceSet ---
210 PVT "cornerScaleCoords", SoCoordinate3 ---
211 PVT "cornerScaleTab0", SoIndexedFaceSet ---
212 PVT "cornerScaleTab1", SoIndexedFaceSet ---
213 PVT "cornerScaleTab2", SoIndexedFaceSet ---
214 PVT "cornerScaleTab3", SoIndexedFaceSet ---
215 \endverbatim
216
217 \NODEKIT_POST_TABLE
218 */
SoTabPlaneDragger(void)219 SoTabPlaneDragger::SoTabPlaneDragger(void)
220 {
221 SO_KIT_INTERNAL_CONSTRUCTOR(SoTabPlaneDragger);
222
223 SO_KIT_ADD_CATALOG_ENTRY(planeSwitch, SoSwitch, TRUE, geomSeparator, "", FALSE);
224 SO_KIT_ADD_CATALOG_ENTRY(translator, SoSeparator, TRUE, planeSwitch, scaleTabs, TRUE);
225 SO_KIT_ADD_CATALOG_ENTRY(scaleTabs, SoSeparator, TRUE, planeSwitch, "", FALSE);
226 SO_KIT_ADD_CATALOG_ENTRY(scaleTabMaterial, SoMaterial, TRUE, scaleTabs, scaleTabHints, TRUE);
227 SO_KIT_ADD_CATALOG_ENTRY(scaleTabHints, SoShapeHints, TRUE, scaleTabs, scaleTabMaterialBinding, TRUE);
228 SO_KIT_ADD_CATALOG_ENTRY(scaleTabMaterialBinding, SoMaterialBinding, TRUE, scaleTabs, scaleTabNormalBinding, FALSE);
229 SO_KIT_ADD_CATALOG_ENTRY(scaleTabNormalBinding, SoNormalBinding, TRUE, scaleTabs, scaleTabNormal, FALSE);
230 SO_KIT_ADD_CATALOG_ENTRY(scaleTabNormal, SoNormal, TRUE, scaleTabs, edgeScaleCoords, FALSE);
231 SO_KIT_ADD_CATALOG_ENTRY(edgeScaleCoords, SoCoordinate3, TRUE, scaleTabs, edgeScaleTab0, FALSE);
232 SO_KIT_ADD_CATALOG_ENTRY(edgeScaleTab0, SoIndexedFaceSet, TRUE, scaleTabs, edgeScaleTab1, FALSE);
233 SO_KIT_ADD_CATALOG_ENTRY(edgeScaleTab1, SoIndexedFaceSet, TRUE, scaleTabs, edgeScaleTab2, FALSE);
234 SO_KIT_ADD_CATALOG_ENTRY(edgeScaleTab2, SoIndexedFaceSet, TRUE, scaleTabs, edgeScaleTab3, FALSE);
235 SO_KIT_ADD_CATALOG_ENTRY(edgeScaleTab3, SoIndexedFaceSet, TRUE, scaleTabs, cornerScaleCoords, FALSE);
236 SO_KIT_ADD_CATALOG_ENTRY(cornerScaleCoords, SoCoordinate3, TRUE, scaleTabs, cornerScaleTab0, FALSE);
237 SO_KIT_ADD_CATALOG_ENTRY(cornerScaleTab0, SoIndexedFaceSet, TRUE, scaleTabs, cornerScaleTab1, FALSE);
238 SO_KIT_ADD_CATALOG_ENTRY(cornerScaleTab1, SoIndexedFaceSet, TRUE, scaleTabs, cornerScaleTab2, FALSE);
239 SO_KIT_ADD_CATALOG_ENTRY(cornerScaleTab2, SoIndexedFaceSet, TRUE, scaleTabs, cornerScaleTab3, FALSE);
240 SO_KIT_ADD_CATALOG_ENTRY(cornerScaleTab3, SoIndexedFaceSet, TRUE, scaleTabs, "", FALSE);
241
242 if (SO_KIT_IS_FIRST_INSTANCE()) {
243 SoInteractionKit::readDefaultParts("tabPlaneDragger.iv",
244 TABPLANEDRAGGER_draggergeometry,
245 static_cast<int>(strlen(TABPLANEDRAGGER_draggergeometry)));
246 }
247
248 SO_KIT_ADD_FIELD(translation, (0.0f, 0.0f, 0.0f));
249 SO_KIT_ADD_FIELD(scaleFactor, (1.0f, 1.0f, 1.0f));
250
251 SO_KIT_INIT_INSTANCE();
252
253 this->setPartAsDefault("translator", "tabPlaneTranslator");
254 this->setPartAsDefault("scaleTabMaterial", "tabPlaneScaleTabMaterial");
255 this->setPartAsDefault("scaleTabHints", "tabPlaneScaleTabHints");
256
257 SoSwitch *sw = SO_GET_ANY_PART(this, "planeSwitch", SoSwitch);
258 SoInteractionKit::setSwitchValue(sw, SO_SWITCH_ALL);
259
260 this->createPrivateParts();
261 this->prevsizex = this->prevsizey = 0.0f;
262 this->reallyAdjustScaleTabSize(NULL);
263 this->constraintState = CONSTRAINT_OFF;
264 this->whatkind = WHATKIND_NONE;
265 this->adjustTabs = TRUE;
266
267 this->addStartCallback(SoTabPlaneDragger::startCB);
268 this->addMotionCallback(SoTabPlaneDragger::motionCB);
269 this->addFinishCallback(SoTabPlaneDragger::finishCB);
270 this->addValueChangedCallback(SoTabPlaneDragger::valueChangedCB);
271 this->addOtherEventCallback(SoTabPlaneDragger::metaKeyChangeCB);
272
273 this->planeProj = new SbPlaneProjector;
274 this->lineProj = new SbLineProjector;
275
276 this->translFieldSensor = new SoFieldSensor(SoTabPlaneDragger::fieldSensorCB, this);
277 this->translFieldSensor->setPriority(0);
278 this->scaleFieldSensor = new SoFieldSensor(SoTabPlaneDragger::fieldSensorCB, this);
279 this->scaleFieldSensor->setPriority(0);
280
281 this->setUpConnections(TRUE, TRUE);
282 }
283
284 /*!
285 Protected destructor.
286
287 (Dragger classes are derived from SoBase, so they are reference
288 counted and automatically destroyed when their reference count goes
289 to 0.)
290 */
~SoTabPlaneDragger()291 SoTabPlaneDragger::~SoTabPlaneDragger()
292 {
293 delete this->translFieldSensor;
294 delete this->scaleFieldSensor;
295 delete this->planeProj;
296 delete this->lineProj;
297 }
298
299 // Doc in superclass.
300 SbBool
setUpConnections(SbBool onoff,SbBool doitalways)301 SoTabPlaneDragger::setUpConnections(SbBool onoff, SbBool doitalways)
302 {
303 if (!doitalways && this->connectionsSetUp == onoff) return onoff;
304
305 if (onoff) {
306 inherited::setUpConnections(onoff, doitalways);
307
308 SoTabPlaneDragger::fieldSensorCB(this, NULL);
309
310 if (this->translFieldSensor->getAttachedField() != &this->translation) {
311 this->translFieldSensor->attach(&this->translation);
312 }
313 if (this->scaleFieldSensor->getAttachedField() != &this->scaleFactor) {
314 this->scaleFieldSensor->attach(&this->scaleFactor);
315 }
316 }
317 else {
318 if (this->translFieldSensor->getAttachedField() != NULL) {
319 this->translFieldSensor->detach();
320 }
321 if (this->scaleFieldSensor->getAttachedField() != NULL) {
322 this->scaleFieldSensor->detach();
323 }
324 inherited::setUpConnections(onoff, doitalways);
325 }
326 return !(this->connectionsSetUp = onoff);
327 }
328
329 // Doc in superclass.
330 void
setDefaultOnNonWritingFields(void)331 SoTabPlaneDragger::setDefaultOnNonWritingFields(void)
332 {
333 this->edgeScaleCoords.setDefault(TRUE);
334 this->cornerScaleCoords.setDefault(TRUE);
335
336 inherited::setDefaultOnNonWritingFields();
337 }
338
339 /*! \COININTERNAL */
340 void
fieldSensorCB(void * d,SoSensor *)341 SoTabPlaneDragger::fieldSensorCB(void * d, SoSensor *)
342 {
343 SoTabPlaneDragger * thisp = static_cast<SoTabPlaneDragger *>(d);
344 SbMatrix matrix = thisp->getMotionMatrix();
345 thisp->workFieldsIntoTransform(matrix);
346 thisp->setMotionMatrix(matrix);
347 }
348
349 /*! \COININTERNAL */
350 void
valueChangedCB(void *,SoDragger * d)351 SoTabPlaneDragger::valueChangedCB(void *, SoDragger * d)
352 {
353 SoTabPlaneDragger * thisp = static_cast<SoTabPlaneDragger *>(d);
354 SbMatrix matrix = thisp->getMotionMatrix();
355 SbVec3f trans, scale;
356 SbRotation rot, scaleOrient;
357 matrix.getTransform(trans, rot, scale, scaleOrient);
358
359 thisp->translFieldSensor->detach();
360 if (thisp->translation.getValue() != trans)
361 thisp->translation = trans;
362 thisp->translFieldSensor->attach(&thisp->translation);
363
364 thisp->scaleFieldSensor->detach();
365 if (thisp->scaleFactor.getValue() != scale)
366 thisp->scaleFactor = scale;
367 thisp->scaleFieldSensor->attach(&thisp->scaleFactor);
368 }
369
370 // Doc in superclass.
371 void
GLRender(SoGLRenderAction * action)372 SoTabPlaneDragger::GLRender(SoGLRenderAction * action)
373 {
374 // FIXME: it'd be better to adjust even when scaling, but it's a bit
375 // complicated to calculate the correct scale factor adjustment (to
376 // make the pointer stay at the exact same position in the tab no
377 // matter how the dragger is scaled). pederb, 2004-09-22
378 if (this->whatkind != WHATKIND_SCALE) {
379 // disable notification do avoid multiple redraws, but
380 // remember to invalidate open caches.
381 SbBool oldnotify = this->enableNotify(FALSE);
382 SoCacheElement::invalidate(action->getState());
383
384 this->reallyAdjustScaleTabSize(action);
385 this->adjustTabs = FALSE;
386
387 (void) this->enableNotify(oldnotify);
388 }
389 inherited::GLRender(action);
390 }
391
392 /*!
393 Signals the dragger to recalculate the size of its tabs. This method
394 is not doing anything useful in Coin, since the tab sizes are recalculated
395 every time the dragger is rendered, even though this method has not
396 been called.
397 */
398 void
adjustScaleTabSize(void)399 SoTabPlaneDragger::adjustScaleTabSize(void)
400 {
401 this->adjustTabs = TRUE;
402 }
403
404 /*!
405 Recalculates the size of the tabs, based on the current view volume,
406 the current viewport, the current model matrix and the current scale
407 factor. If \a action == \e NULL, a default size will be used.
408 */
409 void
reallyAdjustScaleTabSize(SoGLRenderAction * action)410 SoTabPlaneDragger::reallyAdjustScaleTabSize(SoGLRenderAction *action)
411 {
412 SoCoordinate3 *coordnode;
413 SbVec3f *coords;
414
415 float sizex = 0.08f;
416 float sizey = 0.08f;
417 if (action != NULL) {
418 SoState *state = action->getState();
419 SbMatrix toworld = SoModelMatrixElement::get(state);
420 toworld.multLeft(this->getMotionMatrix());
421 const SbViewVolume &vv = SoViewVolumeElement::get(state);
422 const SbViewportRegion &vp = SoViewportRegionElement::get(state);
423 SbVec3f center(0.0f, 0.0f, 0.0f);
424 toworld.multVecMatrix(center, center);
425 sizex = sizey =
426 vv.getWorldToScreenScale(center, TABSIZE/float(vp.getViewportSizePixels()[0]));
427
428 SbVec3f scale;
429 {
430 SbRotation r, so;
431 SbVec3f t;
432 toworld.getTransform(t, r, scale, so);
433 }
434
435 // Take absolute value to allow scales to be negative (which is a
436 // common trick when e.g. using a left-handed coordinate system).
437 sizex = static_cast<float>(fabs(sizex / scale[0]));
438 sizey = static_cast<float>(fabs(sizey / scale[1]));
439 }
440
441 if (sizex == this->prevsizex && this->prevsizey == sizey) return;
442
443 this->prevsizex = sizex;
444 this->prevsizey = sizey;
445
446 float halfx = sizex * 0.5f;
447 float halfy = sizey * 0.5f;
448
449 coordnode = SO_GET_ANY_PART(this, "edgeScaleCoords", SoCoordinate3);
450 coordnode->point.setNum(16);
451 coords = coordnode->point.startEditing();
452 {
453 coords[0].setValue(halfx, 1.0f, Z_OFFSET);
454 coords[1].setValue(-halfx, 1.0f, Z_OFFSET);
455 coords[2].setValue(-halfx, 1.0f-sizey, Z_OFFSET);
456 coords[3].setValue(halfx, 1.0f-sizey, Z_OFFSET);
457
458 coords[4].setValue(1.0f, -halfy, Z_OFFSET);
459 coords[5].setValue(1.0f, halfy, Z_OFFSET);
460 coords[6].setValue(1.0f-sizex, halfy, Z_OFFSET);
461 coords[7].setValue(1.0f-sizex, -halfy, Z_OFFSET);
462
463 coords[8].setValue(-halfx, -1.0f, Z_OFFSET);
464 coords[9].setValue(halfx, -1.0f, Z_OFFSET);
465 coords[10].setValue(halfx, -1.0f+sizey, Z_OFFSET);
466 coords[11].setValue(-halfx, -1.0f+sizey, Z_OFFSET);
467
468 coords[12].setValue(-1.0f, halfy, Z_OFFSET);
469 coords[13].setValue(-1.0f, -halfy, Z_OFFSET);
470 coords[14].setValue(-1.0f+sizex, -halfy, Z_OFFSET);
471 coords[15].setValue(-1.0f+sizex, halfy, Z_OFFSET);
472 }
473 coordnode->point.finishEditing();
474
475 coordnode = SO_GET_ANY_PART(this, "cornerScaleCoords", SoCoordinate3);
476 coordnode->point.setNum(16);
477 coords = coordnode->point.startEditing();
478 {
479 coords[0].setValue(1.0f, 1.0f, Z_OFFSET);
480 coords[1].setValue(1.0f-sizex, 1.0f, Z_OFFSET);
481 coords[2].setValue(1.0f-sizex, 1.0f-sizey, Z_OFFSET);
482 coords[3].setValue(1.0f, 1.0f-sizey, Z_OFFSET);
483
484 coords[4].setValue(1.0f, -1.0f, Z_OFFSET);
485 coords[5].setValue(1.0f, -1.0f+sizey, Z_OFFSET);
486 coords[6].setValue(1.0f-sizex, -1.0f+sizey, Z_OFFSET);
487 coords[7].setValue(1.0f-sizex, -1.0f, Z_OFFSET);
488
489 coords[8].setValue(-1.0f, -1.0f, Z_OFFSET);
490 coords[9].setValue(-1.0f+sizex, -1.0f, Z_OFFSET);
491 coords[10].setValue(-1.0f+sizex, -1.0f+sizey, Z_OFFSET);
492 coords[11].setValue(-1.0f, -1.0f+sizey, Z_OFFSET);
493
494 coords[12].setValue(-1.0f, 1.0f, Z_OFFSET);
495 coords[13].setValue(-1.0f, 1.0f-sizey, Z_OFFSET);
496 coords[14].setValue(-1.0f+sizex, 1.0f-sizey, Z_OFFSET);
497 coords[15].setValue(-1.0f+sizex, 1.0f, Z_OFFSET);
498 }
499 coordnode->point.finishEditing();
500 }
501
502 /*!
503 Not implemented.
504 */
505 void
getXYScreenLengths(SbVec2f & COIN_UNUSED_ARG (lengths),const SbMatrix & COIN_UNUSED_ARG (localtoscreen),const SbVec2s & COIN_UNUSED_ARG (winsize))506 SoTabPlaneDragger::getXYScreenLengths(SbVec2f & COIN_UNUSED_ARG(lengths),
507 const SbMatrix & COIN_UNUSED_ARG(localtoscreen),
508 const SbVec2s & COIN_UNUSED_ARG(winsize))
509 {
510 // FIXME: I found this method just defined in the header file, but
511 // not implemented (!). We should obviously implement it if it's
512 // useful. 20011127 mortene.
513 COIN_STUB();
514 }
515
516 /*! \COININTERNAL
517 Called when dragger is selected (picked) by the user.
518 */
519 void
dragStart(void)520 SoTabPlaneDragger::dragStart(void)
521 {
522 int i;
523 const SoPath *pickpath = this->getPickPath();
524 const SoEvent *event = this->getEvent();
525
526 SbBool found = FALSE;
527 SbVec3f startpt = this->getLocalStartingPoint();
528
529 this->constraintState = CONSTRAINT_OFF;
530
531 SbString str;
532 if (!found) {
533 for (i = 0; i < 4; i++) {
534 str.sprintf("edgeScaleTab%d", i);
535 if (pickpath->findNode(this->getNodeFieldNode(str.getString())) >= 0 ||
536 this->getSurrogatePartPickedName() == str.getString()) break;
537 }
538 if (i < 4) {
539 found = TRUE;
540 this->constraintState = i & 1 ? CONSTRAINT_X : CONSTRAINT_Y;
541 this->whatkind = WHATKIND_SCALE;
542 this->scaleCenter.setValue(-edgetab_lookup[i*2], -edgetab_lookup[i*2+1], 0.0f);
543 }
544 }
545 if (!found) {
546 for (i = 0; i < 4; i++) {
547 str.sprintf("cornerScaleTab%d", i);
548 if (pickpath->findNode(this->getNodeFieldNode(str.getString())) >= 0 ||
549 this->getSurrogatePartPickedName() == str.getString()) break;
550 }
551 if (i < 4) {
552 found = TRUE;
553 this->whatkind = WHATKIND_SCALE;
554 this->scaleCenter.setValue(-cornertab_lookup[i*2], -cornertab_lookup[i*2+1], 0.0f);
555 }
556 }
557 if (!found) {
558 assert(pickpath->findNode(this->getNodeFieldNode("translator")) >= 0 ||
559 this->getSurrogatePartPickedName() == "translator");
560 found = TRUE;
561 this->whatkind = WHATKIND_TRANSLATE;
562 }
563
564 if (this->whatkind == WHATKIND_SCALE) {
565 // startpt might have a non-zero z-component that could cause
566 // trouble when scaling down to very small sizes, so create a
567 // point equal to startpt, but with the z-component set to zero.
568 // scaleCenter already has a zero z-value.
569 SbVec3f linept(startpt[0], startpt[1], 0.0f);
570 this->lineProj->setLine(SbLine(this->scaleCenter, linept));
571 }
572 else { // translate
573 this->planeProj->setPlane(SbPlane(SbVec3f(0.0f, 0.0f, 1.0f), startpt));
574 this->constraintState = CONSTRAINT_OFF;
575 if (event->wasShiftDown()) {
576 this->getLocalToWorldMatrix().multVecMatrix(startpt, this->worldRestartPt);
577 this->constraintState = CONSTRAINT_WAIT;
578 }
579 }
580 }
581
582 /*! \COININTERNAL
583 Called when user drags the mouse after picking the dragger.
584 */
585 void
drag(void)586 SoTabPlaneDragger::drag(void)
587 {
588 if (this->whatkind == WHATKIND_SCALE) {
589 SbVec3f startpt = this->getLocalStartingPoint();
590 this->lineProj->setViewVolume(this->getViewVolume());
591 this->lineProj->setWorkingSpace(this->getLocalToWorldMatrix());
592 SbVec3f projpt = this->lineProj->project(this->getNormalizedLocaterPosition());
593
594 SbVec3f center = this->scaleCenter;
595 SbVec3f orgvec = startpt - center;
596 SbVec3f currvec = projpt - center;
597
598 // Ignore the possible z-component of the vectors
599 orgvec[2] = 0.0f;
600 currvec[2] = 0.0f;
601
602 float orglen = orgvec.length();
603 float currlen = currvec.length();
604 float scale = 0.0f;
605
606 if (orglen > 0.0f) scale = currlen / orglen;
607 if (scale > 0.0f && orgvec.dot(currvec) <= 0.0f) scale = 0.0f;
608
609 SbVec3f scalevec(scale, scale, 1.0f);
610 if (this->constraintState == CONSTRAINT_X) {
611 scalevec[1] = 1.0f;
612 }
613 else if (this->constraintState == CONSTRAINT_Y) {
614 scalevec[0] = 1.0f;
615 }
616 this->setMotionMatrix(this->appendScale(this->getStartMotionMatrix(),
617 scalevec,
618 center));
619
620 }
621 else { // translate
622 SbVec3f startpt = this->getLocalStartingPoint();
623 this->planeProj->setViewVolume(this->getViewVolume());
624 this->planeProj->setWorkingSpace(this->getLocalToWorldMatrix());
625 SbVec3f projpt = this->planeProj->project(this->getNormalizedLocaterPosition());
626
627 const SoEvent *event = this->getEvent();
628 SbBool reset = FALSE;
629 if (event->wasShiftDown() && this->constraintState == CONSTRAINT_OFF) {
630 this->constraintState = CONSTRAINT_WAIT;
631 this->setStartLocaterPosition(event->getPosition());
632 this->getLocalToWorldMatrix().multVecMatrix(projpt, this->worldRestartPt);
633 reset = TRUE;
634 }
635 else if (!event->wasShiftDown() && this->constraintState != CONSTRAINT_OFF) {
636 this->constraintState = CONSTRAINT_OFF;
637 reset = TRUE;
638 }
639 if (reset) {
640 this->saveStartParameters();
641 SbVec3f worldpt;
642 this->getLocalToWorldMatrix().multVecMatrix(projpt, worldpt);
643 this->setStartingPoint(worldpt);
644 startpt = projpt;
645 }
646 SbVec3f motion;
647 SbVec3f localrestartpt;
648 if (this->constraintState != CONSTRAINT_OFF) {
649 this->getWorldToLocalMatrix().multVecMatrix(this->worldRestartPt,
650 localrestartpt);
651 motion = localrestartpt - startpt;
652 }
653 else motion = projpt - startpt;
654 switch(this->constraintState) {
655 case CONSTRAINT_OFF:
656 break;
657 case CONSTRAINT_WAIT:
658 if (this->isAdequateConstraintMotion()) {
659 SbVec3f newmotion = projpt - localrestartpt;
660 int biggest = 0;
661 double bigval = fabs(newmotion[0]);
662 if (fabs(newmotion[1]) > bigval) {
663 biggest = 1;
664 }
665 motion[biggest] += newmotion[biggest];
666 this->constraintState = CONSTRAINT_X + biggest;
667 }
668 else {
669 return;
670 }
671 break;
672 case CONSTRAINT_X:
673 motion[0] += projpt[0] - localrestartpt[0];
674 break;
675 case CONSTRAINT_Y:
676 motion[1] += projpt[1] - localrestartpt[1];
677 break;
678 case CONSTRAINT_Z:
679 motion[2] += projpt[2] - localrestartpt[2];
680 }
681 this->setMotionMatrix(this->appendTranslation(this->getStartMotionMatrix(), motion));
682 }
683 }
684
685 /*! \COININTERNAL
686 Called when mouse button is released after picking and interacting
687 with the dragger.
688 */
689 void
dragFinish(void)690 SoTabPlaneDragger::dragFinish(void)
691 {
692 this->whatkind = WHATKIND_NONE;
693 }
694
695 /*! \COININTERNAL */
696 void
startCB(void *,SoDragger * d)697 SoTabPlaneDragger::startCB(void *, SoDragger * d)
698 {
699 SoTabPlaneDragger * thisp = static_cast<SoTabPlaneDragger *>(d);
700 thisp->dragStart();
701 }
702
703 /*! \COININTERNAL */
704 void
motionCB(void *,SoDragger * d)705 SoTabPlaneDragger::motionCB(void *, SoDragger * d)
706 {
707 SoTabPlaneDragger * thisp = static_cast<SoTabPlaneDragger *>(d);
708 thisp->drag();
709 }
710
711 /*! \COININTERNAL */
712 void
finishCB(void *,SoDragger * d)713 SoTabPlaneDragger::finishCB(void *, SoDragger * d)
714 {
715 SoTabPlaneDragger * thisp = static_cast<SoTabPlaneDragger *>(d);
716 thisp->dragFinish();
717 }
718
719 /*! \COININTERNAL */
720 void
metaKeyChangeCB(void *,SoDragger * d)721 SoTabPlaneDragger::metaKeyChangeCB(void *, SoDragger * d)
722 {
723 SoTabPlaneDragger * thisp = static_cast<SoTabPlaneDragger *>(d);
724 if (!thisp->isActive.getValue()) return;
725 if (!(thisp->whatkind == WHATKIND_TRANSLATE)) return;
726
727 const SoEvent *event = thisp->getEvent();
728 if (event->wasShiftDown() && thisp->constraintState == CONSTRAINT_OFF) {
729 thisp->drag();
730 }
731 else if (!event->wasShiftDown() && thisp->constraintState != CONSTRAINT_OFF) {
732 thisp->drag();
733 }
734 }
735
736
737 //
738 // this method is not as naughty as it sounds :-) It simply creates the parts
739 // it is not possible to configure through the dragger defaults file.
740 //
741 void
createPrivateParts(void)742 SoTabPlaneDragger::createPrivateParts(void)
743 {
744 SoMaterialBinding *mb = SO_GET_ANY_PART(this, "scaleTabMaterialBinding", SoMaterialBinding);
745 mb->value = SoMaterialBinding::OVERALL;
746 this->scaleTabMaterialBinding.setDefault(TRUE);
747
748 SoNormalBinding *nb = SO_GET_ANY_PART(this, "scaleTabNormalBinding", SoNormalBinding);
749 nb->value = SoNormalBinding::OVERALL;
750 this->scaleTabNormalBinding.setDefault(TRUE);
751
752 SoNormal *normal = SO_GET_ANY_PART(this, "scaleTabNormal", SoNormal);
753 normal->vector.setValue(SbVec3f(0.0f, 0.0f, 1.0f));
754 this->scaleTabNormal.setDefault(TRUE);
755
756 SoIndexedFaceSet *fs;
757 SbString str;
758 int idx = 0;
759 int i, j;
760 int32_t *ptr;
761
762 for (i = 0; i < 8; i++) {
763 if (i == 0 || i == 4) idx = 0;
764 if (i < 4)
765 str.sprintf("edgeScaleTab%d", i);
766 else
767 str.sprintf("cornerScaleTab%d", i-4);
768 fs = coin_assert_cast<SoIndexedFaceSet *>(this->getAnyPart(SbName(str.getString()), TRUE));
769 fs->coordIndex.setNum(5);
770
771 ptr = fs->coordIndex.startEditing();
772 {
773 for (j = 0; j < 4; j++) ptr[j] = idx++;
774 ptr[4] = -1;
775 }
776 fs->coordIndex.finishEditing();
777 fs->normalIndex.setValue(0);
778 fs->materialIndex.setValue(0);
779
780 SoField * f = this->getField(SbName(str.getString()));
781 assert(f);
782 f->setDefault(TRUE);
783 }
784
785 // turn off render caching since the geometry below this node might
786 // change very often.
787 SoSeparator *sep = SO_GET_ANY_PART(this, "scaleTabs", SoSeparator);
788 sep->renderCaching = SoSeparator::OFF;
789 sep->renderCaching.setDefault(TRUE);
790 // this is the default, so don't write it
791 this->scaleTabs.setDefault(TRUE);
792 }
793
794 //
795 // returns the node in the SoSFNode field fieldname
796 //
797 SoNode *
getNodeFieldNode(const char * fieldname)798 SoTabPlaneDragger::getNodeFieldNode(const char *fieldname)
799 {
800 SoField * field = this->getField(fieldname);
801 assert(field != NULL);
802 assert(coin_assert_cast<SoSFNode *>(field)->getValue() != NULL);
803 return coin_assert_cast<SoSFNode *>(field)->getValue();
804 }
805
806 // Undefine these again, as some of them are also used in other
807 // dragger sourcecode files (which causes trouble when using the
808 // compact build hack where all .cpp files are included into all.cpp).
809
810 #undef WHATKIND_NONE
811 #undef WHATKIND_SCALE
812 #undef WHATKIND_TRANSLATE
813 #undef CONSTRAINT_OFF
814 #undef CONSTRAINT_WAIT
815 #undef CONSTRAINT_X
816 #undef CONSTRAINT_Y
817 #undef CONSTRAINT_Z
818 #undef Z_OFFSET
819 #undef TABSIZE
820
821 #undef THISP
822 #endif // HAVE_DRAGGERS
823