PDA

View Full Version : Control some option in viewport config through Script


ghostlake114
06-06-2008, 02:32 PM
This is some option I want to control in viewport config
http://i35.photobucket.com/albums/d152/ghostlake114/pare.jpg

However, I can not find them in manual, there is no line in manual about these option. So how could I control them

Thanks for any help

DaveWortley
06-06-2008, 03:08 PM
Shade Selected Faces is the shortcut key "F2"

Selection Brackets is "J"

Not sure about the last one... Why would you want to control these via scripting?

Kramsurfer
06-06-2008, 04:13 PM
enable your listener.. all the options.. and as you press the hot keys, you'll see. stuff like this...

actionMan.executeAction 0 "370" -- Tools: Show Selection Bracket Toggle

You can use this code to toggle the state... How to read the state is another issue...

Good luck

ghostlake114
06-06-2008, 04:29 PM
Thanks :)

But I dont want to mess with the tongle thing, I want to set it ON or OFF
like this for example command

viewport.showbracket = 0

But can not find this kind of type in manual, no info in viewport page

JHaywood
06-06-2008, 04:54 PM
Not every option is available in MaxScript. If you've looked for it and couldn't find it, then you probably can't set it through script. I've run into this before and it's frustrating that not everything is scriptable, but there's not much we can do about it beyond posting a message to the wishlist forum in The Area: http://area.autodesk.com/index.php/forums/viewforum/32/

ghostlake114
06-06-2008, 05:29 PM
I see
Maybe we can not control it :|. No info in manual so I guess there is no script for this little check box

ZeBoxx2
06-06-2008, 06:00 PM
naw, -everything- is scriptable if you try hard enough and are insane enough. Either via the crazy dialogMonitorOps + UIAccessor + Windows. + sendMessage, or via a third party utility (for example, to change as string; as I still haven't figured out how one might go about creating a string buffer and get a pointer index for it back).

Anyway... using the first-mentioned:


BM_SETCHECK = 241 -- checkbutton toggle message ID
dialogMonitorOPS.UnRegisterNotification id:#test -- remove any old instance
dialogMonitorOps.enabled = true -- enable the monitor
fn test = (
hwnd = DialogMonitorOPS.GetWindowHandle() -- check the dialog that popped up
hwnd_title = UIAccessor.GetWindowText hwnd
if (hwnd_title == "Viewport Configuration") then ( -- the viewport config dialog
controls = windows.getChildrenHWND hwnd -- get all controls for this dialog
shadeSel = controls[335][1] -- get the appropriate controls
selBrackets = controls[336][1]
edgedFaces = controls[337][1]
UIAccessor.SendMessage shadeSel BM_SETCHECK 1 0 -- 0 0 == unchecked
UIAccessor.SendMessage selBrackets BM_SETCHECK 1 0
UIAccessor.SendMessage edgedFaces BM_SETCHECK 1 0
UIAccessor.PressButtonByName hwnd "OK"
)
true
)
dialogMonitorOPS.RegisterNotification test id:#test -- register the monitor
max vptconfig -- pop up the viewport config dialog (see above function for what happens next)
dialogMonitorOPS.UnRegisterNotification id:#test -- remove the monitor
dialogMonitorOps.enabled = false -- disable the monitor



You could abstract this into a function that essentially allows you to poke at any checkbox in that, or any other, dialog.. 'll leave that as an excercise for the reader (it's fairly trivial).

The above only works in 3ds Max 2008+ or 3ds Max r9+ with the AVGuard extension installed ( need it for "windows.getChildrenHWND" )

ghostlake114
06-07-2008, 02:19 AM
I dont get much, maybe It is not a traditional script but hacking thing :arteest:

BUt I will try to look into, thanks :D

martinB
06-10-2008, 12:28 PM
naw, -everything- is scriptable if you try hard enough and are insane enough. Either via the crazy dialogMonitorOps + UIAccessor + Windows. + sendMessage

What a hack... ;-)

How do always you get the correct IDs for the buttons and stuff from a dialog?!
I.e. how do you know it is controls[335] that is the Shade Selected Faces toggle? And how do you know the ID of the message to send?

Can you also use dialogMonitorOps for UI elements in the Modify Tab rollout?

-- MartinB

ZeBoxx2
06-10-2008, 12:56 PM
What a hack... ;-)
It's not nearly as hacky as some other methods %)

How do always you get the correct IDs for the buttons and stuff from a dialog?!
The command that gets all the controls in a dialog returns a large array of small arrays. These small arrays contains the hwnd of the control as the first element, then other stuff, and the label on the control as the last element.

I.e. how do you know it is controls[335] that is the Shade Selected Faces toggle?
Hasn't changed in ages; but yes, if you want to be safe, see the previous; find the correct control directly.

And how do you know the ID of the message to send?
msdn is your friend there :)

Can you also use dialogMonitorOps for UI elements in the Modify Tab rollout?
I don't think that opens as a dialog and as such, you can't get the hwnd for that to play with directly. I guess you could get the main max hwnd and get its child windows and whatnot; I've certainly not tried, but as long as you can get at the dialog the control is in, and the control itself, you can do pretty much anything with standard windows messages.

ZeBoxx2
06-10-2008, 01:10 PM
here you go... quicky code

Edit: forgot to mention; you'll need some object with a Hemisphere checkbox in the modify panel, obviously


BN_CLICKED = 0
0
BM_SETCHECK = 241
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.
)
)
)
getModifyPanelControl()
hemiSphere_ui = getModifyPanelControl "Hemisphere"
#(123079254P, 30083334P, 30083334P, "Button", "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
windows.sendMessage controlParent WM_COMMAND ((bit.shift BN_CLICKED 16) + controlID) control_hwnd
)


Edit: durrr... and this doesn't work; I keep forgetting this. This only checks the UI checkbox, but it doesn't signal to windows that the checkbox state changed. So the (in my case) GeoSphere remains happily non-hemisphere. 'll have to dig up the proper message for this (it works in the viewport config dialog because it applies its values when you OK the dialog).

Edit2: Ohhhhh brimey, broody breeding herr. I forgot how annoying that was. Anyway, see the end of the new code up above.

martinB
06-10-2008, 03:40 PM
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
windows.sendMessage controlParent WM_COMMAND ((bit.shift BN_CLICKED 16) + controlID) control_hwnd
)



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

ZeBoxx2
06-10-2008, 04:59 PM
very interesting, in cases where MAXScript is otherwise locked out, this seems to be a viable method to get things done anyway!
To an extent :)

Also, BN_CLICKED is undefined. What value should I use?
Whoops. BN_CLICKED should be 0 (zero). Adjusted the script in my post.

But what the heck is that last line doing?!
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
1. signal (WM_COMMAND | Windows Message)
2. to the parent dialog (controlParent) that
3. the UI element with the given ID (controlID)
4. was clicked (BN_CLICKED | Button Notification. Yes, a checkbox is a type of button*. Don't look at me, MSFT designed that. )
And
5. 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 ^.^'
)

ZeBoxx2
06-10-2008, 05:14 PM
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

martinB
06-12-2008, 01:50 PM
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
1. signal (WM_COMMAND | Windows Message)
2. to the parent dialog (controlParent) that
3. the UI element with the given ID (controlID)
4. was clicked (BN_CLICKED | Button Notification. Yes, a checkbox is a type of button*. Don't look at me, MSFT designed that. )
And
5. 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.


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

martinB
06-12-2008, 01:52 PM
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()
UIAccessor.pressButtonByName modPanelRollouts[1][1] "Pick Operand B"


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

ZeBoxx2
06-12-2008, 03:45 PM
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 :)

CGTalk Moderation
06-12-2008, 03:45 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.