/* Custom SetDrivenKeyWindow 0.9 Writen by Sebastian Woldanski (http://woold.w.interia.pl/eng.html) ...for the grain.S project by Ced+Sapo ( http://grain.s.free.fr ) WHY THIS TOOL?: no more boring selection before driver/driven keying, This script add sliders and input fields to control quickly the driven and driver attribut... LIMITATION : The driven slider works only when there is one attribut (but you can always control driver with this tool and control drivens by hand)... USAGE : put in on your script folder, and call the setDriven key command... */ // Copyright (C) 1997-2001 Alias|Wavefront, // a division of Silicon Graphics Limited. // // The information in this file is provided for the exclusive use of the // licensees of Alias|Wavefront. Such users have the right to use, modify, // and incorporate this code into other products for purposes authorized // by the Alias|Wavefront license agreement, without fee. // // ALIAS|WAVEFRONT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, // INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO // EVENT SHALL ALIAS|WAVEFRONT BE LIABLE FOR ANY SPECIAL, INDIRECT OR // CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, // DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER // TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. // // // Alias|Wavefront Script File // MODIFY THIS AT YOUR OWN RISK // // Creation Date: 9 February 1997 // // // // Procedure Name: // setDrivenKeyWindow // // Description: // Creates a window to allow the user // to set "driven keyframes" against // channels - IE: one channel is used // to drive another channel, rather than // having time drive the value changes. // // Input Arguments: // None. // // Return Value: // None. // // globals used to so that we can key against the flexor guide // but display the guide joint rather than the guide name // global int $driversAreGuides; global string $guideDrivers[]; // Fiven a string return the name that will be used as the // item to be keyed in the setDrivenKeyframe command. // // This is needed because the $object may be a plug // on a node, a component on a shape or simply a node. // global proc string getNodeName(string $object) { string $result; string $buffer[3]; $numTokens = tokenize($object,".",$buffer); if ($numTokens > 1) { string $isAnEntity[] = `ls -type entity $buffer[0]`; if (size($isAnEntity)) { $result = $object; } else { $result = $buffer[0]; } } else { $result = $object; } return $result; } global proc goToDrivenKeyCallback(string $advanceFlag) // // Description: // If a driven attribute is selected, use it as the // attribute to be advanced to the next/previous frame. // { string $cmd = ("advanceToNextDrivenKey "+$advanceFlag+" "); // Get a driven object, and one or more selected channels // for the driven object // string $driven[] = `textScrollList -q -si drivenObjects`; string $drivenChannel[] = `textScrollList -q -si drivenChannels`; if (1 == size($drivenChannel) && 1 == size($driven)) { string $drivenNode = getNodeName($driven[0]); $cmd += ($drivenNode+"."+$drivenChannel[0]); } else { // The "" tells the advanceToNextDrivenKey script that // it will operate on the selection list // $cmd += ("\"\""); } // evaluate the advanceToNextDrivenKey command // eval($cmd+"\n"); } // If string $str is in list $list, returns a non-zero number // indicating the *1*-based index into the array. // global proc int isStringInList(string $str, string $list[]) { int $ii; int $listSize = size($list); for ($ii = 0; $ii < $listSize; $ii++) { if ($list[$ii] == $str) { return ($ii+1); } } return 0; } // Special method used here to clear duplicate entries from the // list $list // global proc removeDuplicateStringsInList(string $list[]) { int $ii, $jj; int $listSize = size($list); for ($ii = 0; $ii < ($listSize-1); $ii++) { string $checkString = $list[$ii]; if ($checkString == "") { continue; } for ($jj = $ii+1; $jj < $listSize; $jj++) { if ($list[$jj] == $checkString) { $list[$jj] = ""; } } } } // given a plug name $object, strip out the $attrName // // global proc string[] sdkGetAttr(string $object) { string $result[1]; string $attrName = ""; string $buffer[3]; $numTokens = tokenize($object,".",$buffer); if ($numTokens > 1) { int $ii; for ($ii = 1; $ii < $numTokens; $ii++) { if ($ii != 1) { $attrName += "."; } $attrName += $buffer[$ii]; } } $result[0] = $attrName; return $result; } // Return a mel command appropriate for the given object. // If $driver is true, consider nonkeyable attributes in addition // to keyable. // global proc string genListAttrString(int $driver,string $object) { string $cmd; string $buffer[3]; $numTokens = tokenize($object,".",$buffer); string $isAnEntity[] = `ls -type entity $buffer[0]`; if ($numTokens > 1 && (0 == size($isAnEntity))) { // If the object name has embedded .'s and the $object type // is not an entity, the assumption here is that the $object // is a plug rather than a component on a shape. // // In this case we take the attribute name directly from the plug // since a listAttr command would list all the attributes instead of // only the selected attribute // $cmd = "sdkGetAttr "; } else { $cmd = "listAttr -sa -v -c -u -m -lf "; // only show the keyable attributes unless the showNonKeyable // option is true // int $showNonKeyable = `optionVar -query SDKshowNonKeyable`; if ($driver == 0 && ! $showNonKeyable) { $cmd += "-k "; } // because there are so many attributes on transforms, we only // list the keyable attributes for them when listing the driver // string $xforms[] = `ls -type transform $object`; if ($driver && size($xforms)) { $cmd += "-k "; } } $cmd += $object; return $cmd; } global proc generateSetDrivenCommand( ) // // Generate a setDrivenKeyframe command for // each of the selected channels in the driven channel // text scroll list. { global int $driversAreGuides; global string $guideDrivers[]; // Get a driver, and the selected channel for the driver // string $driver[] = `textScrollList -q -si driverObjects`; string $driverChannel[] = `textScrollList -q -si driverChannels`; // Get a driven object, and one or more selected channels // for the driven object // string $driven[] = `textScrollList -q -si drivenObjects`; string $drivenChannel[] = `textScrollList -q -si drivenChannels`; string $cmd; if (0 == size($driver) || 0 == size($driverChannel)) { error("Must select node and attribute to be the driver."); return; } if (0 == size($driven) || 0 == size($drivenChannel)) { error("Must select node and attribute to be driven."); } int $i, $j, $which; for ( $i=0; $i < size( $driven ); $i++ ) { string $drivenNode = getNodeName($driven[$i]); for( $j=0; $j < size( $drivenChannel ); $j++ ) { $cmd = "setDrivenKeyframe -cd "; if ($driversAreGuides) { // if a guide node is in the driver list, key against the // driver node rather than the joint // string $guides[] = `textScrollList -q -ai driverObjects`; $which = isStringInList($driver[0],$guides) - 1; $cmd = ( $cmd + $guideDrivers[$which] + "." + $driverChannel[0] + " " ); } else { $cmd = ( $cmd + $driver[0] + "." + $driverChannel[0] + " " ); } $cmd = ( $cmd + $drivenNode + "." + $drivenChannel[$j] ); // // Evaluate and echo the command for the users benefit // evalEcho( $cmd ); } } } global proc selectDriven( ) // // callback used to select all driven objects // { string $driven[] = `textScrollList -q -si drivenObjects`; if (size($driven) && $driven[0] != "< Nothing Selected >") { select -r $driven; } } global proc updateKeyButton( ) // // Called any time that selection are made in the // driver and driven channels textScrollLists, in order // to update the state of the "Key" button. The user // must select: a driver object, a driven object, and // channels for both driver and driven before the "Key" // button is enabled. { if( `textScrollList -q -nsi driverChannels` != 0 && `textScrollList -q -nsi drivenChannels` != 0 ) { button -e -enable true keyButton; } else { button -e -enable false keyButton; } } global proc updateChannels( string $list, string $channelList ) // // Called whenever a new object is selected in // either the driver or driven object textScrollList's, // in order to fill the corresponding channel list // with a list of keyable channels for the driver or // driven objects. { global int $driversAreGuides; global string $guideDrivers[]; int $driver = ($list == "driverObjects"); string $currChannels[] = `textScrollList -q -si $channelList`; string $object[] = `textScrollList -q -si $list`; if ($list == "driverObjects" && $driversAreGuides) { int $which; string $allObjects[] = `textScrollList -q -ai $list`; $which = isStringInList($object[0],$allObjects) - 1; if ($which > -1) $object[0] = $guideDrivers[$which]; } string $listAttrCmd = genListAttrString($driver, $object[0]); string $attrs[] = eval( $listAttrCmd ); removeDuplicateStringsInList($attrs); textScrollList -e -ra $channelList; int $ii, $jj; int $attrCount = size($attrs); for ($ii = 1; $ii < size($object); $ii++) { $listAttrCmd = genListAttrString($driver, $object[$ii]); string $attrs2[] = eval( $listAttrCmd ); for ($jj = 0; $jj < $attrCount; $jj++) { if ($attrs[$jj] == "") { continue; } if (! isStringInList($attrs[$jj],$attrs2)) { $attrs[$jj] = ""; } } } int $selectChannels = 0; string $selChannels = "textScrollList -e "; for( $item in $attrs ) { if ($item != "") { if (isStringInList($item,$currChannels)) { $selectChannels = 1; $selChannels += "-si "+$item+" "; } textScrollList -e -a $item $channelList; } } if ($selectChannels) { $selChannels += $channelList; eval($selChannels); } } global proc loadCurrentDriver() // // Query the currently selected driven object and if it has // any drivers, load them in the driver lists. // { global int $driversAreGuides = 0; global string $guideDrivers[]; string $driverNodes[]; string $currentNode; string $currentAttr; string $objects[] = `textScrollList -q -si drivenObjects`; string $attrs[] = `textScrollList -q -si drivenChannels`; textScrollList -e -ra driverObjects; textScrollList -e -ra driverChannels; if (size($objects) && ($objects[0] != "< Nothing Selected >") ) { string $queryString = "setDrivenKeyframe -q -dr "+$objects[0]; string $currentString = "setDrivenKeyframe -q -cd "+$objects[0]; if (size($attrs)) { $queryString += "."+$attrs[0]; $currentString += "."+$attrs[0]; } string $current[] = eval($currentString); string $drivers[] = eval($queryString); if ( size($drivers) && ($drivers[0] == "No drivers." || $drivers[0] == "") ) { $drivers = `setDrivenKeyframe -q -dr ($objects[0])`; $current = `setDrivenKeyframe -q -cd ($objects[0])`; } string $buffer[]; // tokenize the result into nodes and attrs // if ($current[0] != "No drivers.") { if (2 == tokenize($current[0], ".", $buffer)) { $currentNode = $buffer[0]; $currentAttr = $buffer[1]; } } int $ii; int $counter = 0; clear $guideDrivers; for ($ii = 0; $ii < size($drivers); $ii++) { if ($drivers[$ii] != "No drivers." && $drivers[$ii] != "") { if (2 == tokenize($drivers[$ii], ".", $buffer)) { string $cds[] = `textScrollList -q -ai driverObjects`; string $nameToUse; if (nodeType($buffer[0]) == "guide") { string $sArr[]; $sArr = `listConnections -d false ($buffer[0]+".jointXformMatrix")`; if (0 != size($sArr)) { $driversAreGuides = 1; $nameToUse = $sArr[0]; if ($buffer[0] == $currentNode) { $currentNode = $nameToUse; } } else { $nameToUse = $buffer[0]; } } else { $nameToUse = $buffer[0]; } if (! isStringInList($nameToUse,$cds) ) { textScrollList -e -a $nameToUse driverObjects; $guideDrivers[$counter] = $buffer[0]; $counter++; } } } } if ($currentNode != "") { textScrollList -e -si $currentNode driverObjects; updateChannels driverObjects driverChannels; textScrollList -e -si $currentAttr driverChannels; textScrollList -e -enable true driverObjects; } } } global proc selectListItems(string $list) // // Called whenever a new object is selected in // the driven object textScrollList. // If the select driven checkbox is selected, selects // the current driven item. // { if (`optionVar -q SDKselectListItems`) { string $objects[] = `textScrollList -q -si $list`; if (size($objects) && ($objects[0] != "< Nothing Selected >") ) { select -replace $objects; } } } proc fillObjectList( string $list, string $node, string $attr) // // Called by the updateSetDrivenWnd proc, in // order to fill the textScrollLists with a list // of available objects for each. // // If $node and $attr are not "", these items are used as the // driven items. Else if they are "", the selection list is used // to fill the specified text scroll list. // // If nothing is selected when the user performs this operation, // the textScrollList is disabled, and the string // < Nothing Selected > is put into the list. // { global int $driversAreGuides; global string $guideDrivers[]; // find current selection list // string $objects[20]; if (! (`optionVar -query SDKshowShapes`)) { $objects = `ls -sl`; } else { $objects = `listRelatives -shapes`; } // determine whether current list should be cleared // int $selectedSomething = 0; string $currObjects[] = `textScrollList -q -ai $list`; if (`optionVar -query SDKclearOnLoad`) { textScrollList -e -ra $list; if ($list == "driverObjects") $driversAreGuides = 0; } else if (1 == `textScrollList -q -ni $list` && "< Nothing Selected >" == $currObjects[0]) { textScrollList -e -ra $list; if ($list == "driverObjects") $driversAreGuides = 0; } else { textScrollList -e -da $list; } // find current contents of textScrollList // $currObjects = `textScrollList -q -ai $list`; int $counter = size($guideDrivers); // fill list // if ( $node == "" ) { if( `size( $objects )` == 0 ) // Nothing selected - disable the control, // and put in a string that informs the user // that they have nothing selected to load // into the textScrollList { textScrollList -e -ra $list; textScrollList -e -a "< Nothing Selected >" $list; textScrollList -e -enable false $list; button -e -enable false keyButton; return; } for( $item in $objects ) { textScrollList -e -enable true $list; if (! isStringInList($item,$currObjects)) { textScrollList -e -a $item $list; $guideDrivers[$counter] = $item; $counter++; } } if (1 == `textScrollList -q -ni $list`) { textScrollList -e -sii 1 $list; $selectedSomething = 1; } } else { textScrollList -e -a $node $list; int $listSize = `textScrollList -q -ni $list`; textScrollList -e -sii $listSize $list; $selectedSomething = 1; } if ($selectedSomething == 1) { if ($list == "drivenObjects") { updateChannels drivenObjects drivenChannels; if ($attr != "") { // $attr might be the name of a compound. If so, get something // we're actually listing in the string $listAttrCmd = genListAttrString( 0, "" ) + ($node+"."+$attr); string $resultAttrs[] = eval( $listAttrCmd ); if( size( $resultAttrs ) > 0 ) { textScrollList -e -si $resultAttrs[0] drivenChannels; } } } else { updateChannels driverObjects driverChannels; } } } global proc updateSetDrivenWnd( string $which, string $node, string $attr ) // // Called whenever the user clicks on either the // "Load Driver" or "Load Driven" buttons. This // proc will fill the driver and driven object // lists. { switch( $which ) { case "driver": textScrollList -e -ra driverChannels; fillObjectList("driverObjects","",""); button -e -enable false keyButton; break; case "driven": textScrollList -e -ra drivenChannels; fillObjectList("drivenObjects",$node,$attr); button -e -enable false keyButton; break; } } global proc buildSetDrivenKeyContextHelpItems(string $nameRoot, string $menuParent) { menuItem -label "Help on Set Driven Key..." -enableCommandRepeat false -command "showHelp SetDrivenKey"; } proc createSetDrivenWnd() // // Creates the setDriveKeyframe window, with // four textScrollLists, one for each of the driver // and driven objects, and their channels. // // Also creates a "Key" button to key the currently // selected items, "Load Driver" and "Load Driven" // buttons to load the selected objects into the // driver and driven lists, and a "Close" button, // to allow the user to close the window without // having to double click on the close box. // // If the window already exists, then the proc // simply shows the window, effectively popping it // to the top, if it's under other windows. { window -t "Set Driven Key" -retain -iconName "Set Driven" -mb true -s true -wh 390 530 setDrivenWnd; menu -l "Load" -to true; menuItem -l "Selected as Driver" -c "updateSetDrivenWnd(\"driver\",\"\",\"\")"; menuItem -l "Selected as Driven" -c "updateSetDrivenWnd(\"driven\",\"\",\"\")"; menuItem -l "Current Driver" -c "loadCurrentDriver"; setParent -m ..; optionVar -iv SDKclearOnLoad 1; optionVar -iv SDKshowShapes 0; optionVar -iv SDKselectListItems 1; optionVar -iv SDKshowNonKeyable 0; menu -l "Options" -to true; menuItem -l "Clear on Load" -cb 1 -c ("optionVar -iv SDKclearOnLoad #1;"); menuItem -l "Load shapes" -cb 0 -c ("optionVar -iv SDKshowShapes #1;"); menuItem -l "AutoSelect" -cb 1 -c ("optionVar -iv SDKselectListItems #1;"); menuItem -l "List Keyable Driven Attributes" -cb 1 -c ("optionVar -iv SDKshowNonKeyable (!(#1)); updateChannels drivenObjects drivenChannels"); setParent -m ..; // Mimic the Set Driven Key portion of the Key menu in AniKeyframeMenu.mel // menu -l "Key" -to true; menuItem -label "Set" -command "generateSetDrivenCommand" setDrivenKeyItem; menuItem -divider true; menuItem -label "Go to Previous" -command "goToDrivenKeyCallback -previous" previousDrivenKeyItem; menuItem -label "Go to Next" -command "goToDrivenKeyCallback -next" nextDrivenKeyItem; setParent -menu ..; menu -l "Select" -to true; menuItem -l "Driven Items" -c "selectDriven"; setParent -m ..; // Adds support for the Context Sensitive Help Menu. // addContextHelpProc "setDrivenWnd" "buildSetDrivenKeyContextHelpItems"; doHelpMenu "setDrivenWnd" "setDrivenWnd"; setParent -m ..; formLayout setDrivenForm; formLayout objectsForm; frameLayout -l "Driver" -bv true -bs "etchedIn" -la "center" -cl false -cll false -mh 10 -mw 10 driverLayout; formLayout driverForm; textScrollList -ams false -sc "updateChannels driverObjects driverChannels; selectListItems driverObjects; " driverObjects; textScrollList -ams false -sc "updateKeyButton;driverSliderUpdate;" driverChannels; setParent ..; formLayout -e -af driverObjects top 0 -af driverObjects left 0 -ap driverObjects right 0 50 -af driverObjects bottom 0 -af driverChannels top 0 -ac driverChannels left 0 driverObjects -af driverChannels right 0 -af driverChannels bottom 0 driverForm; setParent ..; frameLayout -l "Driven" -bv true -bs "etchedIn" -la "center" -cl false -cll false -mh 10 -mw 10 drivenLayout; formLayout driverForm; textScrollList -ams true -sc "updateChannels drivenObjects drivenChannels; selectListItems drivenObjects;" drivenObjects; textScrollList -sc "updateKeyButton;drivenSliderUpdate" -ams true drivenChannels; setParent ..; formLayout -e -af drivenObjects top 0 -af drivenObjects left 0 -ap drivenObjects right 0 50 -af drivenObjects bottom 0 -af drivenChannels top 0 -ac drivenChannels left 0 drivenObjects -af drivenChannels right 0 -af drivenChannels bottom 0 driverForm; setParent ..; setParent ..; formLayout -e -af driverLayout top 2 -af driverLayout left 2 -af driverLayout right 2 -ap driverLayout bottom 2 50 -ac drivenLayout top 2 driverLayout -af drivenLayout left 2 -af drivenLayout right 2 -af drivenLayout bottom 2 objectsForm; //////////////////// here is insertion by mel`n`cholic formLayout sliderRForm; columnLayout -adj 0 columnLayoutREASE; floatFieldGrp -numberOfFields 2 -label " drag RANGE" -extraLabel "total RANGE" -value1 10 -value2 100 -cl4 "left" "left" "left" "left" -cw4 77 50 50 85 -cc "floatSliderGrp -e -minValue (-1 * #1) driverSlider; floatSliderGrp -e -maxValue #1 driverSlider; floatSliderGrp -e -fieldMinValue (-1 * #2) driverSlider; floatSliderGrp -e -fieldMaxValue #2 driverSlider; floatSliderGrp -e -minValue (-1 * #1) drivenSlider; floatSliderGrp -e -maxValue #1 drivenSlider; floatSliderGrp -e -fieldMinValue (-1 * #2) drivenSlider; floatSliderGrp -e -fieldMaxValue #2 drivenSlider" borderValuesDriv ; separator -h 5 -st "none"; floatSliderGrp -label " DRIVER attr" -field true -minValue ( -1 * ( `floatFieldGrp -q -v1 borderValuesDriv`) ) -maxValue ( `floatFieldGrp -q -v1 borderValuesDriv`) -fieldMinValue ( -1 * ( `floatFieldGrp -q -v1 borderValuesDriv`) ) -fieldMaxValue ( `floatFieldGrp -q -v1 borderValuesDriv`) -value 0 -pre 4 -cw 1 75 -cw 2 50 -cal 1 "left" -cal 2 "left" -step 0.01 -fieldStep 0.01 -adj 3 driverSlider; floatSliderGrp -label " DRIVEN attr" -field true -minValue ( -1 * ( `floatFieldGrp -q -v1 borderValuesDriv`) ) -maxValue ( `floatFieldGrp -q -v1 borderValuesDriv`) -fieldMinValue ( -1 * ( `floatFieldGrp -q -v1 borderValuesDriv`) ) -fieldMaxValue ( `floatFieldGrp -q -v1 borderValuesDriv`) -value 0 -pre 4 -cw 1 75 -cw 2 50 -cal 1 "left" -cal 2 "left" -adj 3 -step 0.01 -fieldStep 0.01 drivenSlider; setParent ..; setParent ..; formLayout -e -af columnLayoutREASE top 0 -af columnLayoutREASE left 5 -af columnLayoutREASE right 5 -af columnLayoutREASE bottom 0 sliderRForm; ///////////////// formLayout buttonForm; button -l "Key" -enable false -annotation "Set key for current relationship of driver attribute to driven attribute" -c "generateSetDrivenCommand" keyButton; button -l "Load Driver" -annotation "Load selected as driver" -c "updateSetDrivenWnd(\"driver\",\"\",\"\")" updateDriver; button -l "Load Driven" -annotation "Load selected as driven" -c "updateSetDrivenWnd(\"driven\",\"\",\"\")" updateDriven; button -l "Close" -c "window -e -vis 0 setDrivenWnd" closeButton; setParent ..; formLayout -e -af keyButton left 2 -af keyButton top 5 -af keyButton bottom 5 -ac keyButton right 2 updateDriver -ap updateDriver left 5 25 -af updateDriver top 5 -af updateDriver bottom 5 -ap updateDriver right 1 50 -ap updateDriven left 1 50 -af updateDriven top 5 -af updateDriven bottom 5 -ap updateDriven right 5 75 -af closeButton top 5 -ac closeButton left 2 updateDriven -af closeButton right 2 -af closeButton bottom 5 buttonForm; setParent ..; formLayout -e -af buttonForm bottom 5 -af buttonForm left 5 -af buttonForm right 5 -af objectsForm top 5 -af objectsForm left 5 -af objectsForm right 5 -ac objectsForm bottom 5 sliderRForm -ac sliderRForm bottom 5 buttonForm setDrivenForm; } global proc driverSliderUpdate() { string $driverObj[] = `textScrollList -q -si driverObjects`; string $driverChan[] = `textScrollList -q -si driverChannels`; float $valueDriver = `getAttr ($driverObj[0] + "." + $driverChan[0])`; floatSliderGrp -e -v $valueDriver driverSlider; connectControl driverSlider ($driverObj[0] + "." + $driverChan[0]); } global proc drivenSliderUpdate() { string $driverObj[] = `textScrollList -q -si drivenObjects`; string $driverChan[] = `textScrollList -q -si drivenChannels`; float $valueDriver = `getAttr ($driverObj[0] + "." + $driverChan[0])`; floatSliderGrp -e -v $valueDriver drivenSlider; connectControl drivenSlider ($driverObj[0] + "." + $driverChan[0]); } global proc clearSDKwindow() { if( `window -exists setDrivenWnd` ) { updateSetDrivenWnd("driven","",""); updateSetDrivenWnd("driver","",""); } } global proc setDrivenKeyWindow(string $node, string $attr) { $driversAreGuides = 0; if( `window -exists setDrivenWnd` ) { showWindow setDrivenWnd; } else { // create the window // createSetDrivenWnd(); scriptJob -protected -parent "setDrivenWnd" -conditionTrue deleteAllCondition clearSDKwindow; } updateSetDrivenWnd("driven",$node,$attr); loadCurrentDriver; showWindow setDrivenWnd; }