PDA

View Full Version : Loft


Piflik
03-26-2009, 07:57 PM
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...

JHN
03-26-2009, 08:15 PM
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

ZeBoxx2
03-26-2009, 08:55 PM
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

Piflik
03-26-2009, 09:20 PM
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...:D

Thank you very much Richard. :applause:

Piflik
03-29-2009, 08:38 PM
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. :beer:

Kramsurfer
03-30-2009, 05:07 PM
It appears you've written the entire lofting procedure.. eh Richard? I've been thinking about that for years.... very cool..

ZeBoxx2
04-02-2009, 09:06 AM
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 ;\

jonahhawk
06-11-2009, 03:30 AM
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
)

ZeBoxx2
06-11-2009, 04:24 AM
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



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).

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?...
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
)

jonahhawk
06-11-2009, 07:45 AM
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 (http://www.ephere.com/projects/MaxDotNet/index.html) wrapper thingy and... I should stop talking.

Thank you all for your input here, it is priceless.

jonahhawk
06-11-2009, 04:55 PM
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... :eek:

ZeBoxx2
06-11-2009, 05:24 PM
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.
I have no experience with this - hopefully somebody else will pick up on it :)

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... :eek:
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 :)

jonahhawk
06-11-2009, 05:33 PM
Though if you wanted to send a company-wide e-mail, I'd say look into command-line utilities :)

Don't encourage me!

Thanks for all your help ZeBoxx, you saved me a ton of monotony this morning, and I learned a bit along the way too. The next pint is on me.

CGTalk Moderation
06-11-2009, 05:33 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.