[Closed] Loft
I have a little request from you guys:
Please tell me that I am mistaken about Lofts not being accessible by MSX.
I have about 110 Lofts and need to edit the ‘Width Repeat’ in the mapping (all to the same number). It can’t be true that I have to manually go through each and everyone of them to edit it…
Loft is notoriously bad supported through maxscript.
So your best change here is to try to persuade Zeboxx2 to write one of his scary window handle tool methinghetygizmo’s that will automagicly push buttons…
-Johan
which I need to finish my wrapper for ( nearly done, then 2 weeks ago happened )
here’s the raw and dirty code for this, at least
fn setWidthRepeat o val = (
WM_COMMAND = 0x0111
EN_CHANGE = 0x0300
EN_KILLFOCUS = 0x0200
WM_KILLFOCUS = 0x0008
mainHWND = windows.getDesktopHWND()
setCommandPanelTaskMode #modify
modPanel.setCurrentObject o
children = windows.getChildrenHWND mainHWND
local widthRepeatIndex
for i = 1 to children.count do ( if (children[i][5] == "Width Repeat:") then ( widthRepeatIndex = i ) )
-- Width Repeat spinner edit control is offset +3.
spinnerEditHWND = children[widthRepeatIndex+3][1]
spinnerEditParentHWND = UIAccessor.getParentWindow spinnerEditHWND
spinnerEditID = UIAccessor.getWindowResourceID spinnerEditHWND
UIAccessor.setWindowText spinnerEditHWND (val as string)
windows.sendMessage spinnerEditParentHWND WM_COMMAND ((bit.shift EN_CHANGE 16) + spinnerEditID) spinnerEditHWND
windows.sendMessage spinnerEditParentHWND WM_COMMAND ((bit.shift EN_KILLFOCUS 16) + spinnerEditID) spinnerEditHWND
windows.sendMessage spinnerEditHWND WM_KILLFOCUS 0 0
)
setWidthRepeat $ 3.0
Wow…that is one mean looking piece of code… :bowdown:
I understand about…mhh…nothing. Except the last line. I think that is all I need to make it work…
Thank you very much Richard. :applause:
It works (nearly) like a charm…all I had to change was adding quotation marks in the value handed to the function to be able to use fractural numbers (since MSX uses ‘.’ for floats and the UI uses ‘,’) and call the function inside a Loop.
Thanks again.
It appears you’ve written the entire lofting procedure… eh Richard? I’ve been thinking about that for years… very cool…
Exceedingly good point about the period vs comma thing – silly as I referenced that in a few posts not too long ago.
I do wish the world would standardize, though – preferably on the period
Kram: if ADSK could re-do Loft either by making Sweep as a proper replacement -or- by paramblock2’ing the existing Loft… that would be much, much preferable ;\
This saved my arse. Thank you a million times.
I needed to change the Length Repeat and lucky for me it was as easy as find and replace.
Below is how I used it in my scene of nearly 400 Lofts. It’s fun (the first few times) to watch it go through the array of objects one by one. Is there a faster way to do this?
fn setLengthRepeat o val = (
WM_COMMAND = 0x0111
EN_CHANGE = 0x0300
EN_KILLFOCUS = 0x0200
WM_KILLFOCUS = 0x0008
mainHWND = windows.getDesktopHWND()
setCommandPanelTaskMode #modify
modPanel.setCurrentObject o
subObjectLevel=0
children = windows.getChildrenHWND mainHWND
--print children
local LengthRepeatIndex
for i = 1 to children.count do ( if (children[i][5] == "Length Repeat:") then ( LengthRepeatIndex = i ) )
-- Length Repeat spinner edit control is still offset +3?
spinnerEditHWND = children[LengthRepeatIndex+3][1]
spinnerEditParentHWND = UIAccessor.getParentWindow spinnerEditHWND
spinnerEditID = UIAccessor.getWindowResourceID spinnerEditHWND
UIAccessor.setWindowText spinnerEditHWND (val as string)
windows.sendMessage spinnerEditParentHWND WM_COMMAND ((bit.shift EN_CHANGE 16) + spinnerEditID) spinnerEditHWND
windows.sendMessage spinnerEditParentHWND WM_COMMAND ((bit.shift EN_KILLFOCUS 16) + spinnerEditID) spinnerEditHWND
windows.sendMessage spinnerEditHWND WM_KILLFOCUS 0 0
)
lofts = #()
for m in objects where classof m == Loft do (
appendIfUnique lofts m
)
for n = 1 to lofts.count do (
setLengthRepeat lofts[n] 1.0
print n
)
--setLengthRepeat $ 1.0
Now I just need to turn off the Real-World Map Size checkbox. I’ll keep after it. Any clues would be primo. Is there a way to list the Class Names of the UI elements?..
fn setRWMSize o val = (
WM_COMMAND = 0x0111
EN_CHANGE = 0x0300
EN_KILLFOCUS = 0x0200
WM_KILLFOCUS = 0x0008
mainHWND = windows.getDesktopHWND()
setCommandPanelTaskMode #modify
modPanel.setCurrentObject o
children = windows.getChildrenHWND mainHWND
--print children
local RWMSizeIndex
for i = 1 to children.count do ( if (children[i][5] == "Real-World Map Size") then ( RWMSizeIndex = i ) )
-- I don't know quite where to start here or where to find help
spinnerEditHWND = children[RWMSizeIndex+3][1]
spinnerEditParentHWND = UIAccessor.getParentWindow spinnerEditHWND
spinnerEditID = UIAccessor.getWindowResourceID spinnerEditHWND
UIAccessor.setWindowText spinnerEditHWND (val as string)
windows.sendMessage spinnerEditParentHWND WM_COMMAND ((bit.shift EN_CHANGE 16) + spinnerEditID) spinnerEditHWND
windows.sendMessage spinnerEditParentHWND WM_COMMAND ((bit.shift EN_KILLFOCUS 16) + spinnerEditID) spinnerEditHWND
windows.sendMessage spinnerEditHWND WM_KILLFOCUS 0 0
)
lofts = #()
for m in objects where classof m == Loft do (
appendIfUnique lofts m
)
for n = 1 to lofts.count do (
setRWMSize lofts[n] false
print n
)
The bits in green could be pre-calculated so that they only run once. e.g. if you’re already in modify panel mode, no need to switch to that mode for every new object in the #lofts() array. Similarly, the index of that spinner edit isn’t going to change between lofts, so instead of looping over the array of children to find it, that could be hardcoded (but might break in other max versions).
Print out the children array from the above script e.g., while the Loft interface is visible:
(
mainHWND = windows.getDesktopHWND()
children = windows.getChildrenHWND mainHWND
print children
)
You should hit this entry:
#(88738904P, 41553030P, 41553030P, "Button", "Real-World Map Size")
Those three numbers are subject to change every time that UI gets displayed. Button is the ‘class name’ of the checkbox (buttons, checkboxes, radiobuttons, etc. are all ‘Button’ class UI elements), and the 5th element is the string on the UI element.
The first thing you’d have to look up is how to check/uncheck a checkbox. That requires some digging into MSDN, or search on these forums and find this post:
http://forums.cgsociety.org/showthread.php?f=98&t=670662
As we’re targeting the checkbox itself, we don’t need the +3 (that was only need for that spinner (some spinners require different offsets, too), to get to its ‘edittext’).
So going back to your function, you’d get something like…
fn setRWMSize o val = (
WM_COMMAND = 0x111 -- Windows Message: Command
BN_CLICKED = 0
BM_SETCHECK = 241 -- checkbutton toggle message ID
mainHWND = windows.getDesktopHWND()
setCommandPanelTaskMode #modify
modPanel.setCurrentObject o
children = windows.getChildrenHWND mainHWND
--print children
local RWMSizeIndex
for i = 1 to children.count do ( if (children[i][5] == "Real-World Map Size") then ( RWMSizeIndex = i ) )
checkboxHWND = children[RWMSizeIndex][1]
checkboxParentHWND = UIAccessor.getParentWindow checkboxHWND
checkboxID = UIAccessor.getWindowResourceID checkboxHWND
windows.sendMessage checkboxHWND BM_SETCHECK (if (val) then ( 1 ) else ( 0 )) 0
windows.sendMessage checkboxParentHWND WM_COMMAND ((bit.shift BN_CLICKED 16) + checkboxID) checkboxHWND
)
lofts = #()
for m in objects where classof m == Loft do (
appendIfUnique lofts m
)
for n = 1 to lofts.count do (
setRWMSize lofts[n] false
print n
)
Cool! Can’t wait to get back to work to try this out. I did get as far as printing all the items of the children array and searching for “world” to find the right string. Thanks for the line by line comments.
We do have the Max SDK and at least one license of Visual Studio. Can I add a reference in Visual Studio from the SDK so that I can find/filter through the max related ui elements/methods? or am I totally lost? I wish I had gone after a computer science degree while I had the chance.
In what little free time I have, I’m learning as much mxs, .net and VB as I can. VB mostly because the word “basic” is in there… but also because it seems like there will be more open integration with other languages besides C++ (hard) with things like the max.net wrapper thingy and… I should stop talking.
Thank you all for your input here, it is priceless.
I have no experience with this – hopefully somebody else will pick up on it
Yes, you can address any UI element that uses the standard windows interface. WPF, Flash, etc. are not quite so accessible as they just look like 1 big UI element to Windows.
Though if you wanted to send a company-wide e-mail, I’d say look into command-line utilities
This “control any windows ui element” capability of mxs is… dangerous but very useful. i assume I can send messages to elements outside of max too? Like sending a company-wide email from outlook… 😮