[Closed] Find all controllers on an object
I’m trying to generate a controller list like the one that’s generated during the wire parameter operation, where you click on an object and a menu pops up (with sub-menus) that shows you the all the controllers you can wire to.
I'm looking in to a recursive .numSubs function like they use in the help file but I'm not sure how best to search for cases where the object may have custom attributes like $.modifiers[1].custAttributes[1].numSubs, or when the baseObject has undefined Sub-Anims. I can't think of a clean way to search for all the sub-anims.
/* modified from the help file*/
float_props = #()
fn getFloatProps theObject =
(
if try(isKindOf theObject.controller FloatController)catch(false) do
append animated_props theObject
for i = 1 to theObject.numSubs do
getFloatProps theObject[i]
)
getFloatProps $
So the above function works but doesn't "see" any undefined floats such as bend.angle or box.length, and it also doesn't look deep enough in to an Attribute_Holder for custom attributes, etc.
What would be a good way to do this?
i’ve already showed on this forum exactly this code -> collect all controllers and show them in rc menu
Found it! (posting in case someone else needs it)
[ http://forums.cgsociety.org/showthread.php?f=98&t=1094659&page=1&pp=15&highlight=collect+controllers ]( http://forums.cgsociety.org/showthread.php?f=98&t=1094659&page=1&pp=15&highlight=collect+controllers)
This is exactly what I was looking for. Though it still isn't finding the custom attributes on my object.
theObject
∟Transform
__∟Modified Object
____∟Modifier
____∟Rectangle
______∟Custom Attribute (on baseObject) <== This guy
_________∟Float
_________∟Float
_________∟Float
_________∟Float
But then I found this one that does find the Custom Attribute:
http://forums.cgsociety.org/showthread.php?f=98&t=919504&highlight=collect+controllers+menu
No RC Menu, though.
So I think between the two I have what I need. Thanks for the help!
here is a toy to play with:
try(destroydialog subAnimsInspector) catch()
rollout subAnimsInspector "Find SubAnims with denisT" width:240
(
fn dotcolor c darker:0.4 = (dotnetclass "System.Drawing.Color").FromArgb (c.r*darker) (c.g*darker) (c.b*darker)
fn getNodeColor node tvnode: =
(
fn colorbyname name c: asdotnet:on =
(
maxOps.colorById (gethashvalue (name as string) 10227) &c
if asdotnet then dotcolor c else c
)
case of
(
(iscontroller node.controller): tvnode.forecolor = colorbyname (superclassof node.controller)
(isvalidnode node): tvnode.forecolor = colorbyname (superclassof node)
(iskindof node modifier): tvnode.forecolor = colorbyname (superclassof node)
(iskindof node material): tvnode.forecolor = colorbyname (classof node)
(iskindof node subanim and node.value != undefined): tvnode.forecolor = colorbyname (classof node.value)
(iskindof node subanim and node.controller == undefined): tvnode.forecolor = dotcolor (color 250 250 250)
)
)
fn collectSubAnims node tvnode: =
(
if iskindof node subanim do
(
tvnode.nodes.add (tvnode = dotnetobject "TreeNode" node.name)
getNodeColor node tvnode:tvnode
)
for k=1 to node.numsubs do collectSubAnims node[k] tvnode:tvnode
)
dotnetcontrol tv "TreeView" pos:[4,4] width:232 height:490
button search_bt "Find Subs" width:232 align:#right offset:[9,0]
on search_bt pressed do if (node = selection[1]) != undefined do
(
tv.BeginUpdate()
tv.Sorted = true
tv.nodes.clear()
root = dotnetobject "TreeNode" node.name
getNodeColor node tvnode:root
collectSubAnims node tvnode:root
tv.nodes.add root
tv.ExpandAll()
tv.EndUpdate()
)
on subAnimsInspector open do search_bt.pressed()
)
createdialog subAnimsInspector
Cool Denis. Thanks for the example. The color coding of the subAnim type is a really nice touch. I still wasn’t getting the Custom Attributes to show up though so after studying it for a while I made the changes in yellow. Recursion makes my head hurt but eventually I got the CA’s displaying correctly in the tree view.
try(destroydialog subAnimsInspector) catch()
rollout subAnimsInspector "Find SubAnims with denisT" width:240 -- guest appearance by Pacermike :)
(
fn dotcolor c darker:0.4 = (dotnetclass "System.Drawing.Color").FromArgb (c.r*darker) (c.g*darker) (c.b*darker)
fn getNodeColor node tvnode: =
(
fn colorbyname name c: asdotnet:on =
(
maxOps.colorById (gethashvalue (name as string) 10227) &c
if asdotnet then dotcolor c else c
)
case of
(
(iscontroller node.controller): tvnode.forecolor = colorbyname (superclassof node.controller)
(isvalidnode node): tvnode.forecolor = colorbyname (superclassof node)
(iskindof node modifier): tvnode.forecolor = colorbyname (superclassof node)
(iskindof node material): tvnode.forecolor = colorbyname (classof node)
(iskindof node subanim and node.value != undefined): tvnode.forecolor = colorbyname (classof node.value)
(iskindof node subanim and node.controller == undefined): tvnode.forecolor = dotcolor (color 250 250 250)
)
)
fn collectSubAnims node tvnode: =
(
if iskindof node subanim or iskindof node attributeDef do
(
tvnode.nodes.add (tvnode = dotnetobject "TreeNode" node.name)
getNodeColor node tvnode:tvnode
)
total = (subs= node.numsubs) + (custAtt= try(node.custAttributes.count)catch(0))
for k=1 to total do
(
if k <= total - custAtt then collectSubAnims node[k] tvnode:tvnode
else collectSubAnims node.custAttributes[(k-subs)] tvnode:tvnode
)
)
dotnetcontrol tv "TreeView" pos:[4,4] width:232 height:490
button search_bt "Find Subs" width:232 align:#right offset:[9,0]
on search_bt pressed do if (node = selection[1]) != undefined do
(
tv.BeginUpdate()
tv.Sorted = false
tv.nodes.clear()
root = dotnetobject "TreeNode" node.name
getNodeColor node tvnode:root
collectSubAnims node tvnode:root
tv.nodes.add root
tv.ExpandAll()
tv.EndUpdate()
)
on subAnimsInspector open do search_bt.pressed()
)
createdialog subAnimsInspector
And here it is (mostly) working with your rcMenu code. My mod is kind of ugly and it's not working perfect, either. It adds the CA subanims to the subanims of the object the CA is applied to, instead of branching them under the CA def name's heading, but when the CA's in an Attribute Holder modifier it looks right with out having the def name. So I'm not really sure the best way to get it to know the difference between the two situations but I'll keep working on it... maybe I should just stick with the tree view.
try(form.close()) catch()
(
global form = dotnetobject "MaxCustomControls.Maxform"
form.ShowInTaskbar = form.MinimizeBox = form.MaximizeBox = off
form.StartPosition = form.StartPosition.Manual
form.Bounds = dotnetobject "System.Drawing.Rectangle" 800 200 100 60
cm = dotNetObject "ContextMenu"
fn makeSubAnimItem node: =
(
local item
fn onClick s e = (format "picked: %
" s.tag.value)
if node != undefined and node.Name != ": None" do
(
total = (subs= node.numsubs) + (custAtt= try(node.custAttributes.count)catch(0))
item = dotnetobject "MenuItem" node.name
item.tag = dotnetmxsvalue node
if total == 0 do dotnet.addEventHandler item "Click" onClick
for k=1 to total do
(
if k <= total - custAtt then i = makeSubAnimItem node:(getSubAnim node k)
else
(
for j= 1 to node.custAttributes[(k-subs)].numSubs do
(
i = makeSubAnimItem node:(getSubAnim node.custAttributes[(k-subs)] j)
if i != undefined do item.menuitems.add i
)
)
if i != undefined do item.menuitems.add i
)
)
item
)
fn onPopup s e = if not isvalidnode (node = selection[1]) then s.menuitems.Clear() else
(
s.menuitems.add (makeSubAnimItem node:node)
)
fn onCollapse s e = s.menuitems.Clear()
dotnet.addEventHandler cm "Popup" onPopup
dotnet.addEventHandler cm "Collapse" onCollapse
form.ContextMenu = cm
form.showmodeless()
)