Updating a Node's Attribute when Manipulating a Master Controller Widget


In order for a Master Controller widget to have any effect on an element in the scene, it must be programmed to set the value of an attribute for an element when the widget is being manipulated by the user.

Master Controller widgets emit a signal when they are manipulated. You can control what happens when they are manipulated by creating a function that handles the value given by the widget, and connect that function to the valueChanged signal of the widget.

// Callback function for when the slider value changes function mySliderValueChanged(newSliderValue) { MessageLog.trace("The value of the slide changed to " + newSliderValue); } Controller.onShowControl = function() { Controller.controls = []; Controller.controls.push(new SliderWidget()); // Connect the valueChanged signal to the sliderValueChanged // function Controller.controls[0].valueChanged.connect(mySliderValueChanged); }

Then, functions in the Harmony scripting interface must be used to affect the attributes of elements in the scene based on the value provided with the widget's signal. In this example, we use the slider widget's value to make the horizontal position of a peg named My_Peg_A , located in the scene's top level, vary between 0 and 2 fields. The horizontal position of a peg is stored in the attribute POSITION.X.

  • You can easily obtain the names of a node's attributes for scripting by enabling Publish Attribute Mode in the Node View and opening a node's Layer Properties dialog. For more information, see Accessing Node Attribute Names for Scripting.
  • While position attributes for a peg are stored in the POSITION attribute group, position attributes for a drawing layer are stored in the OFFSET attribute group.
function mySliderValueChanged(newSliderValue) { var percentage = newSliderValue / 100.0; // make the slider sets a My_Peg_A x position between 0 and 2 fields var newXValue = percentage * 2; node.setTextAttr("Top/My_Peg_A", "POSITION.X", frame.current(), newXValue); }

Widgets that can be manipulated will call the valueChanged signal when the user manipulates them. Other widgets, such as the Line2dDisplayWidget, cannot be manipulated and are only designed to display useful information to the user, so they do not support this signal.

Most widgets handle transforming manipulations done to them by the user into attribute value changes on their own through their valueChanged signal. For example, a SliderWidget that has a minimum value between 0 and 100 will convert manipulations done to its handle into a value between 0 and 100 and pass that value through the signal. The CustomWidget, on the other hand, allows the user to program specific algorithms to handle manipulations done to it by using dragStarted, drag and dragEnded signals. Although this is particularly useful for the CustomWidget, those events are inherited by widgets from the WidgetBase class, and are hence available to all widgets.

To create custom actions for drag manipulations, simply connect a callback to one of these signals.

Controller.onShowControl = function() { var c = new CustomWidget( { data : "TranslationX", drag_manipulator : "SCRIPT", painter : "ARROW_X", picker : "MONO", local_transformation : "TRANSLATION_X", attribute : "DOUBLE" } ); // Register drag callback functions c.dragStarted.connect(onDragStart); c.drag.connect(onDrag); }

In the callback function, convert the mouse position from the world coordinates system into the Master Controller's OpenGL model coordinates.

var myController = Controller; var drag_offset = new Vector3d; var drag_offsetZ = new Vector3d; function onDragStart(context) { // The context drag point is expressed in world coordinates. // Convert the point in model coordinates and project it // on the Master Controller XY plane. var projectedPoint = context.projectToModelPlane(context.dragPoint()); var modelPickingPoint = projectedPoint; if(myController.controls.length > 0) { // If other script widgets affecting the local transformation of // the Master Controller are registered after the current widget, // they may affect the position // of the current widget. Take their transformations into account. modelPickingPoint = context.multiplyByPostMatrix(modelPickingPoint); } // Compute the delta between the controlled Peg position and the picked point. var pegPosition = node.getAttr(getPegPath(),frame.current(), "POSITION").pos3dValue(); var modelOriginPoint = scene.toOGL(pegPosition); drag_offset = modelOriginPoint.minus(modelPickingPoint); } function onDragTransX(context) { var projectedPoint = context.projectToModelPlane(context.dragPoint()); var localPoint = projectedPoint; if(myController.controls.length > 0) { localPoint = context.multiplyByPostMatrix(projectedPoint); } var fieldPoint = scene.fromOGL(localPoint.add(drag_offset)); var newValue = fieldPoint.x; node.setTextAttr(myController.node, "TranslationX", frame.current(), newValue); node.setTextAttr(getPegPath(), "POSITION.X", frame.current(), newValue); }