[Closed] Control some option in viewport config through Script
Thanks Richard,
very interesting, in cases where MAXScript is otherwise locked out, this seems to be a viable method to get things done anyway!
But what the heck is that last line doing?!
Also, BN_CLICKED is undefined. What value should I use?
– MartinB
To an extent
Whoops. BN_CLICKED should be 0 (zero). Adjusted the script in my post.
Haha… I wonder that myself sometimes.
The first sendMessage line changes the checked state of the UI control; this does not actually signal the UI that its state changed. The proper way to do that, next, is to simulate a user interaction; in our case, a click.
However, you can’t just ‘click’ the checkbox (control_hwnd).
Oh no, no, no…
You have to
- signal (WM_COMMAND | Windows Message)
- to the parent dialog (controlParent) that
- the UI element with the given ID (controlID)
- was clicked (BN_CLICKED | Button Notification. Yes, a checkbox is a type of button*. Don’t look at me, MSFT designed that. )
And - for good measure we pass it the handle (control_hwnd) as a parameter again so that if controlParent wanted to do something with that, it could.
3 and 4 have to be combined somehow as there’s only so many parameters you can pass (wParam, lParam) – but thankfully either can only be 16bit, by design, so we can stick one if the first 16bits and the other in the last 16bits of a 32bit value.
- And with that realization finally snapping into my head… at least for checkbuttons, you could also use UIAccessor’s PressButton and/or PressButtonByName (get the parent hwnd first).
BN_CLICKED = 0
BM_SETCHECK = 241
fn getModifyPanelControl str = (
max_hwnd = windows.getMAXHWND()
max_children = windows.getChildrenHWND max_hwnd
modifyPanelFound = false
for el in max_children do (
if (el[4] == "ModifyTask") then ( modifyPanelFound = true )
if (modifyPanelFound) then ( -- ignore if we haven't found the modify panel!
if (el[5] == str) then ( exit with el )
if (el[4] == "HierarchyTask") then ( exit with undefined ) -- hierarchy panel, no luck.
)
)
)
hemiSphere_ui = getModifyPanelControl "Hemisphere"
if (hemiSphere_ui != undefined) do (
control_hwnd = hemiSphere_ui[1]
controlParent = hemiSphere_ui[2]
controlID = UIAccessor.GetWindowResourceID hemiSphere_ui[1]
windows.sendMessage control_hwnd BM_SETCHECK 1 0 -- 0 0 to uncheck
UIAccessor.pressButton control_hwnd -- that's much prettier ^.^'
)
Thanks very much. That makes it a bit clearer. I guess it would help if one had experience in programming Windows?
Thanks again, I stored these examples away, in case I encounter non-scriptable UI elements again.
– MartinB
Just to do the pressButtonByName bit and some further processing…
-- for each rollout in the modify panel
-- returns the hwnd to the actual rollout client dialog, plus the title of the rollout
fn getModifyPanelRollouts = (
theRollouts = #()
max_hwnd = windows.getMAXHWND()
max_children = windows.getChildrenHWND max_hwnd
modifyPanelFound = false
for i = 1 to max_children.count do (
el = max_children[i]
if (el[4] == "ModifyTask") then ( modifyPanelFound = true )
if (modifyPanelFound) then (
if (el[4] == "RollupPanel") then (
append theRollouts #(max_children[i+2][1],max_children[i+1][5])
)
if (el[4] == "HierarchyTask") then ( exit )
)
)
theRollouts
)
modPanelRollouts = getModifyPanelRollouts()
#(#(29361592P, "Pick Boolean"), #(25561248P, "Parameters"), #(26609968P, "Display/Update"))
UIAccessor.pressButtonByName modPanelRollouts[1][1] "Pick Operand B"
true
Another useful example, thank you! I figured it runs when an old Boolean object is selected and the Modify panel is active. Interesting that I had to change modPanelRollouts[1][1] to modPanelRollouts[3][1] on my 3ds Max 2009 64bit. Maybe the order in which the children are reported is not reliable or changes with versions of 3ds Max?
– MartinB
oh, quite possibly, Martin – but that’s why I included the title of the rollout in the result as well; just didn’t bother to actually utilize it in the one-liner