////////////////////////////////////////////////////////////////////////
//
// Description:
//    Constructor
//
SoTranslate2Dragger::SoTranslate2Dragger()
//
////////////////////////////////////////////////////////////////////////
{
    SO_KIT_CONSTRUCTOR(SoTranslate2Dragger);

    isBuiltIn = TRUE;

    // Put this stuff under the geomSeparator so it will draw more
    // efficiently.
    SO_KIT_ADD_CATALOG_ENTRY(translatorSwitch, SoSwitch, TRUE,
				geomSeparator,\x0,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(translator, SoSeparator, TRUE,
				translatorSwitch,\x0,TRUE);
    SO_KIT_ADD_CATALOG_ENTRY(translatorActive, SoSeparator, TRUE,
				translatorSwitch,\x0,TRUE);
    SO_KIT_ADD_CATALOG_ENTRY(feedbackSwitch, SoSwitch, TRUE,
				geomSeparator,\x0,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(feedback, SoSeparator, TRUE,
				feedbackSwitch,\x0,TRUE);
    SO_KIT_ADD_CATALOG_ENTRY(feedbackActive, SoSeparator, TRUE,
				feedbackSwitch,\x0,TRUE);
    SO_KIT_ADD_CATALOG_ENTRY(axisFeedbackSwitch, SoSwitch, TRUE,
				geomSeparator,\x0,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(xAxisFeedback, SoSeparator, TRUE,
				axisFeedbackSwitch,\x0,TRUE);
    SO_KIT_ADD_CATALOG_ENTRY(yAxisFeedback, SoSeparator, TRUE,
				axisFeedbackSwitch,\x0,TRUE);

    // read geometry for shared parts
    if (SO_KIT_IS_FIRST_INSTANCE())
	readDefaultParts("translate2Dragger.iv", geomBuffer, sizeof(geomBuffer) );

    SO_KIT_ADD_FIELD(translation, (0.0, 0.0, 0.0));

    SO_KIT_INIT_INSTANCE();

    // create the parts...
   setPartAsDefault("translator",      "translate2Translator");
   setPartAsDefault("translatorActive","translate2TranslatorActive");
   setPartAsDefault("feedback",        "translate2Feedback");
   setPartAsDefault("feedbackActive",  "translate2FeedbackActive");
   setPartAsDefault("xAxisFeedback",  "translate2XAxisFeedback");
   setPartAsDefault("yAxisFeedback",  "translate2YAxisFeedback");

    // Set the switches to 0...
    setSwitchValue( translatorSwitch.getValue(), 0 );
    setSwitchValue( feedbackSwitch.getValue(), 0 );

    // Set the axis feedback switch to SO_SWITCH_NONE
    // They're only displayed while dragging
    setSwitchValue( axisFeedbackSwitch.getValue(), SO_SWITCH_NONE );

    // Create the line projector
    planeProj = new SbPlaneProjector();

    // add the callbacks to perform the dragging
    addStartCallback(  &SoTranslate2Dragger::startCB );
    addMotionCallback( &SoTranslate2Dragger::motionCB );
    addFinishCallback(   &SoTranslate2Dragger::finishCB );

    // add callback to respond to the shift key, for constraining motion
    // to a line within the plane.
    addOtherEventCallback( &SoTranslate2Dragger::metaKeyChangeCB );

    // Updates the translation field when the motionMatrix is set.
    addValueChangedCallback( &SoTranslate2Dragger::valueChangedCB );

    // Updates the motionMatrix when the translation field is set.
    fieldSensor = new SoFieldSensor( &SoTranslate2Dragger::fieldSensorCB, this);
    fieldSensor->setPriority( 0 );

    setUpConnections( TRUE, TRUE );
}
////////////////////////////////////////////////////////////////////////
//
// Description:
//    Constructor
//
SoDragPointDragger::SoDragPointDragger()
//
////////////////////////////////////////////////////////////////////////
{
    SO_KIT_CONSTRUCTOR(SoDragPointDragger);

    isBuiltIn = TRUE;

    SO_KIT_ADD_CATALOG_ENTRY(noRotSep, SoSeparator, FALSE,
				topSeparator, geomSeparator,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(xTranslatorSwitch, SoSwitch, FALSE, 
				noRotSep,\x0,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(xTranslator, SoTranslate1Dragger, TRUE, 
				xTranslatorSwitch,\x0,TRUE);
    SO_KIT_ADD_CATALOG_ENTRY(xyTranslatorSwitch, SoSwitch, FALSE, 
				noRotSep,\x0,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(xyTranslator, SoTranslate2Dragger, TRUE, 
				xyTranslatorSwitch,\x0,TRUE);

    SO_KIT_ADD_CATALOG_ENTRY(rotXSep, SoSeparator, FALSE,
				topSeparator, geomSeparator,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(rotX, SoRotation, TRUE, 
				rotXSep,\x0,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(xzTranslatorSwitch, SoSwitch, FALSE, 
				rotXSep,\x0,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(xzTranslator, SoTranslate2Dragger, TRUE, 
				xzTranslatorSwitch,\x0,TRUE);

    SO_KIT_ADD_CATALOG_ENTRY(rotYSep, SoSeparator, FALSE,
				topSeparator, geomSeparator,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(rotY, SoRotation, TRUE, 
				rotYSep,\x0,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(zTranslatorSwitch, SoSwitch, FALSE, 
				rotYSep,\x0,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(zTranslator, SoTranslate1Dragger, TRUE, 
				zTranslatorSwitch,\x0,TRUE);
    SO_KIT_ADD_CATALOG_ENTRY(yzTranslatorSwitch, SoSwitch, FALSE, 
				rotYSep,\x0,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(yzTranslator, SoTranslate2Dragger, TRUE, 
				yzTranslatorSwitch,\x0,TRUE);

    SO_KIT_ADD_CATALOG_ENTRY(rotZSep, SoSeparator, FALSE,
				topSeparator, geomSeparator,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(rotZ, SoRotation, TRUE, 
				rotZSep,\x0,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(yTranslatorSwitch, SoSwitch, FALSE, 
				rotZSep,\x0,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(yTranslator, SoTranslate1Dragger, TRUE, 
				yTranslatorSwitch,\x0,TRUE);

    SO_KIT_ADD_CATALOG_ENTRY(xFeedbackSwitch, SoSwitch, FALSE, 
				topSeparator, geomSeparator,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(xFeedbackSep, SoSeparator, FALSE,
				xFeedbackSwitch,\x0,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(xFeedbackTranslation, SoTranslation, FALSE,
				xFeedbackSep,\x0,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(xFeedback, SoSeparator, TRUE,
				xFeedbackSep,\x0,TRUE);

    SO_KIT_ADD_CATALOG_ENTRY(yFeedbackSwitch, SoSwitch, FALSE, 
				topSeparator, geomSeparator,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(yFeedbackSep, SoSeparator, FALSE,
				yFeedbackSwitch,\x0,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(yFeedbackTranslation, SoTranslation, FALSE,
				yFeedbackSep,\x0,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(yFeedback, SoSeparator, TRUE,
				yFeedbackSep,\x0,TRUE);

    SO_KIT_ADD_CATALOG_ENTRY(zFeedbackSwitch, SoSwitch, FALSE, 
				topSeparator, geomSeparator,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(zFeedbackSep, SoSeparator, FALSE,
				zFeedbackSwitch,\x0,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(zFeedbackTranslation, SoTranslation, FALSE,
				zFeedbackSep,\x0,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(zFeedback, SoSeparator, TRUE,
				zFeedbackSep,\x0,TRUE);

    SO_KIT_ADD_CATALOG_ENTRY(planeFeedbackSep, SoSeparator, FALSE,
				topSeparator, geomSeparator,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(planeFeedbackTranslation, SoTranslation, FALSE,
				planeFeedbackSep,\x0,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(planeFeedbackSwitch, SoSwitch, FALSE, 
				planeFeedbackSep,\x0,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(yzFeedback, SoSeparator, TRUE,
				planeFeedbackSwitch,\x0,TRUE);
    SO_KIT_ADD_CATALOG_ENTRY(xzFeedback, SoSeparator, TRUE,
				planeFeedbackSwitch,\x0,TRUE);
    SO_KIT_ADD_CATALOG_ENTRY(xyFeedback, SoSeparator, TRUE,
				planeFeedbackSwitch,\x0,TRUE);

    // read geometry for shared parts
    if (SO_KIT_IS_FIRST_INSTANCE())
	readDefaultParts("dragPointDragger.iv",geomBuffer,sizeof(geomBuffer) );

    // The field that reflects where the dragger has been translated to
    SO_KIT_ADD_FIELD(translation, (0.0, 0.0, 0.0));

    SO_KIT_INIT_INSTANCE();

    // Cached values to make updating the feedback geometry more efficient
    oldXAxisNode = NULL;
    oldYAxisNode = NULL;
    oldZAxisNode = NULL;

    //******************
    // Set up the parts.
    //******************

    // Set up the rotations to orient the draggers correctly.
    SoRotation *myRotX = new SoRotation;
    SoRotation *myRotY = new SoRotation;
    SoRotation *myRotZ = new SoRotation;
    myRotX->rotation = SbRotation( SbVec3f(1,0,0), 1.57079 );
    myRotY->rotation = SbRotation( SbVec3f(0,1,0), 1.57079 );
    myRotZ->rotation = SbRotation( SbVec3f(0,0,1), 1.57079 );
    setAnyPartAsDefault("rotX", myRotX );
    setAnyPartAsDefault("rotY", myRotY );
    setAnyPartAsDefault("rotZ", myRotZ );

    // CREATE THE CHILD DRAGGERS.
    // Create the translate1Draggers...
    SoTranslate1Dragger *myXTrans, *myYTrans, *myZTrans;
    myXTrans = SO_GET_ANY_PART(this,"xTranslator",SoTranslate1Dragger);
    myYTrans = SO_GET_ANY_PART(this,"yTranslator",SoTranslate1Dragger);
    myZTrans = SO_GET_ANY_PART(this,"zTranslator",SoTranslate1Dragger);

    // Create the translate2Draggers...
    SoTranslate2Dragger *myYZTrans, *myXZTrans, *myXYTrans;
    myYZTrans = SO_GET_ANY_PART(this,"yzTranslator",SoTranslate2Dragger);
    myXZTrans = SO_GET_ANY_PART(this,"xzTranslator",SoTranslate2Dragger);
    myXYTrans = SO_GET_ANY_PART(this,"xyTranslator",SoTranslate2Dragger);

    //******************
    // The feedback parts jump around as the limit box changes. That is, they
    // stay fixed in space while the dragger moves around.
    // However, they jump to a new location when the dragger nears the edge.
    // These parts a separate translation node, since they move differently
    // than the dragger itself.
    //******************

    //******************
    // The feedback parts jump around as the limit box changes. That is, they
    // stay fixed in space while the dragger moves around.
    // However, they jump to a new location when the dragger nears the edge.
    // These parts a separate translation node, since they move differently
    // than the dragger itself.
    //
    // Only one plane or one axis is shown at a time, depending on which
    // translator has initiated the dragging.
    //******************

   setPartAsDefault("xFeedback",      "dragPointXFeedback");
   setPartAsDefault("yFeedback",      "dragPointYFeedback");
   setPartAsDefault("zFeedback",      "dragPointZFeedback");

   setPartAsDefault("yzFeedback", "dragPointYZFeedback");
   setPartAsDefault("xzFeedback", "dragPointXZFeedback");
   setPartAsDefault("xyFeedback", "dragPointXYFeedback");

    //********************
    // initialize state, limitbox, gesture variables
    //********************

    // To begin with, only the yTranslator and xzTranslators are turned on.
    // You can switch between pairs of line/plane draggers by hitting the 
    // CONTROL key
    setSwitchValue(xTranslatorSwitch.getValue(),   SO_SWITCH_NONE );
    setSwitchValue(yTranslatorSwitch.getValue(),   0 );
    setSwitchValue(zTranslatorSwitch.getValue(),   SO_SWITCH_NONE );
    setSwitchValue(yzTranslatorSwitch.getValue(),   SO_SWITCH_NONE );
    setSwitchValue(xzTranslatorSwitch.getValue(),   0 );
    setSwitchValue(xyTranslatorSwitch.getValue(),  SO_SWITCH_NONE );

    // ??? Would be cool to be able to choose a free
    // axis, rotate it around to whatever direction, maybe even
    // have it snap to things in the scene, then constrain
    // dragging to that line.

    // Start off inactive
    currentDragger = NULL;

    // The state of the modifier keys
    shftDown = FALSE;

    // Need to initialize since checkBoxLimits will look at it...
    startLocalHitPt.setValue(0,0,0);

    // The jump axes will jump when the edit point gets within
    // 10% of their ends
    jumpLimit = .1;

    // makes the offsetWorkLimit box
    limitBox.makeEmpty();

    updateLimitBoxAndFeedback();

    // These will be called by the child draggers after they call
    // their own callbacks...
    addStartCallback( &SoDragPointDragger::startCB );
    addMotionCallback( &SoDragPointDragger::motionCB );
    addFinishCallback( &SoDragPointDragger::finishCB );

    // When modify keys are released, we need to turn off any constraints.
    addOtherEventCallback( &SoDragPointDragger::metaKeyChangeCB );

    // Updates the translation field when the motionMatrix is set.
    addValueChangedCallback( &SoDragPointDragger::valueChangedCB );

    // Updates the motionMatrix when the translation field is set.
    fieldSensor = new SoFieldSensor( &SoDragPointDragger::fieldSensorCB, this);
    fieldSensor->setPriority( 0 );

    setUpConnections( TRUE, TRUE );
}
////////////////////////////////////////////////////////////////////////
//
// Description:
//    Constructor
//
SoRotateDiscDragger::SoRotateDiscDragger()
//
////////////////////////////////////////////////////////////////////////
{
    SO_KIT_CONSTRUCTOR(SoRotateDiscDragger);

    isBuiltIn = TRUE;

    // Put this stuff under the geomSeparator so it will draw more
    // efficiently.
    SO_KIT_ADD_CATALOG_ENTRY(rotatorSwitch, SoSwitch, TRUE,
				geomSeparator,\x0,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(rotator, SoSeparator, TRUE,
				rotatorSwitch,\x0,TRUE);
    SO_KIT_ADD_CATALOG_ENTRY(rotatorActive, SoSeparator, TRUE,
				rotatorSwitch,\x0,TRUE);
    SO_KIT_ADD_CATALOG_ENTRY(feedbackSwitch, SoSwitch, TRUE,
				geomSeparator,\x0,FALSE);
    SO_KIT_ADD_CATALOG_ENTRY(feedback, SoSeparator, TRUE,
				feedbackSwitch,\x0,TRUE);
    SO_KIT_ADD_CATALOG_ENTRY(feedbackActive, SoSeparator, TRUE,
				feedbackSwitch,\x0,TRUE);

    // read geometry for shared parts
    if (SO_KIT_IS_FIRST_INSTANCE())
	readDefaultParts("rotateDiscDragger.iv", geomBuffer, sizeof(geomBuffer) );

    SO_KIT_ADD_FIELD(rotation, (0.0, 0.0, 0.0, 1.0));

    SO_KIT_INIT_INSTANCE();

    // create the parts...
   setPartAsDefault("rotator",       "rotateDiscRotator");
   setPartAsDefault("rotatorActive", 
			 "rotateDiscRotatorActive"); 
   setPartAsDefault("feedback",      "rotateDiscFeedback");
   setPartAsDefault("feedbackActive",
			 "rotateDiscFeedbackActive");

    // Set the switches to 0...
    setSwitchValue( rotatorSwitch.getValue(), 0 );
    setSwitchValue( feedbackSwitch.getValue(), 0 );

    // our humble projector
    planeProj = new SbPlaneProjector();

    // add the callbacks to perform the dragging
    addStartCallback(  &SoRotateDiscDragger::startCB );
    addMotionCallback( &SoRotateDiscDragger::motionCB );
    addFinishCallback( &SoRotateDiscDragger::doneCB );

    // Updates the scaleFactor field when the motionMatrix is set.
    addValueChangedCallback( &SoRotateDiscDragger::valueChangedCB );

    // Updates the motionMatrix when the scaleFactor field is set.
    fieldSensor 
	= new SoFieldSensor(&SoRotateDiscDragger::fieldSensorCB, this);
    fieldSensor->setPriority( 0 );

    setUpConnections( TRUE, TRUE );
}
TranslateRadialDragger::
TranslateRadialDragger()
{
  SO_KIT_CONSTRUCTOR(TranslateRadialDragger);

  SO_KIT_ADD_CATALOG_ENTRY(validitySwitch, SoBlinker, TRUE,
                           geomSeparator, , FALSE);

  SO_KIT_ADD_CATALOG_ENTRY(materialSwitch, SoSwitch, TRUE,
                           validitySwitch, , FALSE);

  // Put this under geomSeparator so it draws efficiently.
  SO_KIT_ADD_CATALOG_ENTRY(translatorSwitch, SoSwitch, TRUE,
                           geomSeparator, , FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(translator, SoSeparator, TRUE,
                           translatorSwitch, , TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(translatorActive, SoSeparator, TRUE,
                           translatorSwitch, , TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(feedbackRotate, SoRotation, TRUE,
                           geomSeparator, , TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(feedbackSwitch, SoSwitch, TRUE,
                           geomSeparator, , FALSE);
  SO_KIT_ADD_CATALOG_ENTRY(feedback, SoSeparator, TRUE,
                           feedbackSwitch, , TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(feedbackActive, SoSeparator, TRUE,
                           feedbackSwitch, , TRUE);


  SO_KIT_ADD_CATALOG_ENTRY(materialPlaced, SoMaterial, TRUE,
                           materialSwitch, , TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(materialNormal, SoMaterial, TRUE,
                           materialSwitch, , TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(materialActive, SoMaterial, TRUE,
                           materialSwitch, , TRUE);
  SO_KIT_ADD_CATALOG_ENTRY(materialInvalid, SoMaterial, TRUE,
                           validitySwitch, , TRUE);

  // Read geometry resources. Only do this the first time we
  // construct one.  'geomBuffer' contains our compiled in
  // defaults. The user can override these by specifying new
  // scene graphs in the file:
  // $(SO_DRAGGER_DIR)/translateRadialDragger.iv
  if(SO_KIT_IS_FIRST_INSTANCE())
    readDefaultParts("translateRadialDragger.iv", geomBuffer,
                     sizeof(geomBuffer) - 1);

  // Field that always shows current position of the dragger.
  SO_KIT_ADD_FIELD(translation, (0.0, 0.0, 0.0));

  // Creates the parts list for this nodekit
  SO_KIT_INIT_INSTANCE();

  // Create the parts of the dragger. This dragger has five
  // parts that we need to create: "translator",
  // "translatorActive", "feedback," and "feedbackActive" will
  // be created using the resource mechanism. They are looked
  // up in the global dictionary.
  // "rotator," used to position the feedback so it points in
  // the direction selected by the user, will just be a plain
  // old SoRotation node.
  // We call 'setPartAsDefault' because we are installing
  // default geometries from the resource files. By calling
  // 'setPartAsDefault' instead of 'setPart', we insure that
  // these parts will not write to file unless they are
  // changed later.
  setPartAsDefault("translator",
                   "translateRadialTranslator");
  setPartAsDefault("translatorActive",
                   "translateRadialTranslatorActive");
  setPartAsDefault("feedback",
                   "translateRadialFeedback");
  setPartAsDefault("feedbackActive",
                   "translateRadialFeedbackActive");
  setPartAsDefault("materialNormal",
                   "translateNormalMaterial");
  setPartAsDefault("materialActive",
                   "translateActiveMaterial");
  setPartAsDefault("materialPlaced",
                   "translatePlacedMaterial");
  setPartAsDefault("materialInvalid",
                   "translateInvalidMaterial");

  // Set the switch parts to 0 to display the inactive parts.
  // The parts "translatorSwitch" and "feedbackSwitch"
  // are not public parts. (i.e., when making the catalog, the
  // isPublic flag was set FALSE, so users cannot access them)
  // To retrieve the parts we must use the SO_GET_ANY_PART
  // macro which calls the protected method getAnyPart().
  SoSwitch *sw;
  sw = SO_GET_ANY_PART(this, "translatorSwitch", SoSwitch);
  setSwitchValue(sw, 0);
  sw = SO_GET_ANY_PART(this, "feedbackSwitch", SoSwitch);
  setSwitchValue(sw, 0);
  sw = SO_GET_ANY_PART(this, "materialSwitch", SoSwitch);
  setSwitchValue(sw, 0);
  sw = SO_GET_ANY_PART(this, "validitySwitch", SoBlinker);
  setSwitchValue(sw, 0);

  // This dragger does motion along a line,
  // so we create a line projector.
  lineProj = new SbLineProjector();

  // Add the callback functions that will be called when
  // the user clicks, drags, and releases.
  addStartCallback(&TranslateRadialDragger::startCB);
  addMotionCallback(&TranslateRadialDragger::motionCB);
  addFinishCallback(&TranslateRadialDragger::finishCB);

  // Updates the translation field when the dragger moves.
  addValueChangedCallback(&TranslateRadialDragger::valueChangedCB);

  // Updates the motionMatrix (and thus moves the dragger
  // through space) to a new location whenever the translation
  // field is changed from the outside.
  fieldSensor = new SoFieldSensor(
      &TranslateRadialDragger::fieldSensorCB, this);
  fieldSensor->setPriority(0);
  setUpConnections(TRUE, TRUE);
}