Notifications
Clear all

[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…

12 Replies
 JHN

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
 )
1 Reply
(@zeboxx2)
Joined: 11 months ago

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

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.

1 Reply
(@zeboxx2)
Joined: 11 months ago

Posts: 0

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… 😮

Page 1 / 2