MAXScript Tools and Interaction with 3ds Max > Change Handlers and Callbacks > Trackbar Key Filter Callback Functions >

# Exploring the Trackbar Filter Callback Functions

To understand the way the filter function callback works, you can register a test function to explore the argument passed by the callback:

SCRIPT
    fn testCallbackFilterFunction theAnimatable theParent theSubAnimIndex theGrandParent theNode=(
    format "theAnimatable: %\n" theAnimatable
    format "theParent: %\n" theParent
    format "theSubAnimIndex: %\n" theSubAnimIndex
    format "theGrandParent: %\n" theGrandParent
    format "theNode: %\n\n" theNode
    true ) --always returns true, means show all keys
    fn testCallbackAdditionFunction arg1 arg2 = (true)
    theInterface = maxOps.trackbar
    theIndex = theInterface.registerFilter testCallbackFilterFunction\
    callbackAdditionFunction "Test Filter" 8 active:true stopTraversal:false

If you select for example a Sphere scene node called "Sphere01", the callback will traverse all its sub-anim tracks and call the function multiple times. The function will print all arguments to the Listener.

Let's take a look at some of them for better understanding:

    theAnimatable: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
    theParent: undefined
    theSubAnimIndex: 1
    theGrandParent: undefined
    theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

In this case, the scene node Sphere01 is being filtered. There is no grand parent, there is no parent either, the animatable to be filtered is the node itself, the subAnim Index is 1. This is the "top level" of the node.

    theAnimatable: Controller:Bezier_Float
    theParent: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
    theSubAnimIndex: 1
    theGrandParent: undefined
    theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

In this case, there is no grand parent, the parent is the sphere node itself, the animatable to be filtered is the subAnim with Index 1 which is the Bezier Controller of the Visibility track. This shows that the visibility of this sphere has been animated! Otherwise, theAnimatable would be undefined.

    theAnimatable: undefined
    theParent: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
    theSubAnimIndex: 2
    theGrandParent: undefined
    theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

In this case, there is no grand parent, the parent is the sphere node itself, the animatable to be filtered is the subAnim with Index 2 which is undefined. Track 2 of every node is the Space_Warps subAnim track. You can verify by typing in the Listener:

    $Sphere01[2]
    $Sphere01[2].controller
    --results:
    SubAnim:Space_Warps
    undefined
    theAnimatable: Controller:Position_Rotation_Scale
    theParent: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
    theSubAnimIndex: 3
    theGrandParent: undefined
    theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

In this case, there is no grand parent, the parent is the sphere node itself, the animatable to be filtered is the subAnim with Index 3 which is the Transformation controller, in this case a Position_Rotation_Scale controller.

    theAnimatable: Controller:Position_XYZ
    theParent: Controller:Position_Rotation_Scale
    theSubAnimIndex: 1
    theGrandParent: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
    theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

Now we go one level deeper: The grand parent is the Sphere, the parent is Transformation controller (Position_Rotation_Scale), the subAnim index inside the parent is 1 which corresponds to the Position track, in this case a Position_XYZ controller. For comparison, try typing in the Listener:

    $Sphere01[3][1].controller
    Controller:Position_XYZ
    theAnimatable: Controller:Bezier_Float
    theParent: Controller:Position_XYZ
    theSubAnimIndex: 1
    theGrandParent: Controller:Position_Rotation_Scale
    theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

Now we go even deeper, the grand parent is the node Transformation track (the PRS controller), the parent is the Position track (the Position_XYZ), the animatable to be filtered is the subAnim with Index 1 which is the Bezier controller assigned to the X axis of the node position.

    theAnimatable: Controller:Bezier_Float
    theParent: Controller:Position_XYZ
    theSubAnimIndex: 2
    theGrandParent: Controller:Position_Rotation_Scale
    theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
    theAnimatable: Controller:Bezier_Float
    theParent: Controller:Position_XYZ
    theSubAnimIndex: 3
    theGrandParent: Controller:Position_Rotation_Scale
    theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

Same with these two tracks which are the Y and Z sub-controllers of the Position track with indices 2 and 3 respectively. This is the same as accessing

    $Sphere01[3][1][3].controller
    --result
    Controller:Bezier_Float
    theAnimatable: Controller:Euler_XYZ
    theParent: Controller:Position_Rotation_Scale
    theSubAnimIndex: 2
    theGrandParent: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
    theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

Now we go back one level and get to the second subAnim index of the PRS controller which is the Rotation track. It has an Euler_XYZ controller assigned. The following 3 calls will traverse the X, Y and Z sub-controllers of the rotation:

    theAnimatable: Controller:Bezier_Float
    theParent: Controller:Euler_XYZ
    theSubAnimIndex: 1
    theGrandParent: Controller:Position_Rotation_Scale
    theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
    theAnimatable: Controller:Bezier_Float
    theParent: Controller:Euler_XYZ
    theSubAnimIndex: 2
    theGrandParent: Controller:Position_Rotation_Scale
    theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
    theAnimatable: Controller:Bezier_Float
    theParent: Controller:Euler_XYZ
    theSubAnimIndex: 3
    theGrandParent: Controller:Position_Rotation_Scale
    theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

We go back one level again and get to the third subAnim index of the PRS controller which is the Scale track. It has a Bezier_Scale controller assigned which does not have sub-controllers:

    theAnimatable: Controller:Bezier_Scale
    theParent: Controller:Position_Rotation_Scale
    theSubAnimIndex: 3
    theGrandParent: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
    theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
    theAnimatable: Sphere
    theParent: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
    theSubAnimIndex: 4
    theGrandParent: undefined
    theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

We are back to the Sphere object level and check the 4 th subAnim index which is the Sphere object.

Try this in the Listener:

    $Sphere01[4]
    $Sphere01[4].controller
    --results:
    SubAnim:Object__Sphere
    undefined
    theAnimatable: ReferenceTarget:ParamBlock
    theParent: Sphere
    theSubAnimIndex: 1
    theGrandParent: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
    theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

Now we are inside the ParamBlock of the sphere. The grand parent is the Sphere node itself, the parent is the sphere, the subAnim index is 1 and the animatable track is the Parameter Block. It does not have any keys, so we can go on and traverse its subAnim tracks which contain the animatable parameters of the Sphere

    theAnimatable: undefined
    theParent: ReferenceTarget:ParamBlock
    theSubAnimIndex: 1
    theGrandParent: Sphere
    theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

This is the first subAnim of the ParamBlock which is the Radius of the sphere. The radius of this sphere was not animated, so there is no controller assigned - theAnimatable parameter is passed as undefined.

Compare to the Listener:

    $Sphere01[4][1]
    $Sphere01[4][1].controller
    --results:
    SubAnim:Radius
    undefined
    theAnimatable: Controller:Bezier_Float
    theParent: ReferenceTarget:ParamBlock
    theSubAnimIndex: 2
    theGrandParent: Sphere
    theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

This is the second subAnim of the ParamBlock which is the Segments count of the sphere. The Segments of this sphere have been animated, so there is a Bezier_Float controller assigned!

Compare to the Listener:

    $Sphere01[4][2]
    $Sphere01[4][2].controller
    --results:
    SubAnim:Segments
    Controller:Bezier_Float

This following calls traverse the remaining tracks of the ParamBlock and of the Sphere itself but do not find any controllers assigned - they all return undefined as theAnimatable:

    theAnimatable: undefined
    theParent: ReferenceTarget:ParamBlock
    theSubAnimIndex: 3
    theGrandParent: Sphere
    theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
    theAnimatable: undefined
    theParent: ReferenceTarget:ParamBlock
    theSubAnimIndex: 4
    theGrandParent: Sphere
    theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
    theAnimatable: undefined
    theParent: ReferenceTarget:ParamBlock
    theSubAnimIndex: 5
    theGrandParent: Sphere
    theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
    theAnimatable: undefined
    theParent: ReferenceTarget:ParamBlock
    theSubAnimIndex: 6
    theGrandParent: Sphere
    theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
    theAnimatable: undefined
    theParent: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
    theSubAnimIndex: 5
    theGrandParent: undefined
    theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
    theAnimatable: undefined
    theParent: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
    theSubAnimIndex: 6
    theGrandParent: undefined
    theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
    theAnimatable: undefined
    theParent: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]
    theSubAnimIndex: 7
    theGrandParent: undefined
    theNode: $Sphere:Sphere01 @ [-40.683792,-17.994026,0.000000]

Our test function always returns true. Now that we know how it is being called, we could change it to perform actual filtering.

See Trackbar Filter Callback Function Examples for some ideas for filter functions incl. a way to limit the number of displayed keys in the trackbar to increase interaction speed with the 3ds MaxUI.

#### See Also

- Trackbar Filter Callback Function Examples

- Trackbar Interface