Notifications
Clear all

[Closed] macroscript UI state saved with maxfile

The more macros I write, the more often I’d like to be able to have the state of the UI of the macro (values,state of checkboxes etc) saved with the maxfile. I have a way to do this at the moment, by storing them in the custom file properties. But the way I’m doing it seems to be very long-winded and laborious. Not to mention convoluted

Below is a simple random wirecolor script with the technique that I use in it. Can anyone help me with a quicker, less verbose way to store UI state in a max file?

macroscript RandomWireColourHSV
  category: "CgRay"
  buttontext:"RwcHSV"
  Icon:#("CgRay-RandomWireColourHSV",1)
  (
  	clearlistener()
  	try (destroydialog RandomWirecolorHSV) catch()
  	
  	rollout RandomWirecolorHSV "Random Wirecolor HSV"
  	(	
  		progressbar col1 "" value:100 color:red height:8 width:38 align:#right offset:[26,0] across:2
  		progressbar col2 "" value:100 color:red height:8 width:38 align:#right offset:[0,0]
  		label huelabel "Hue Range" align:#left across:3
  		spinner spn_huelow range:[0,255,0] type:#integer width:40 align:#right 
  		spinner spn_huehigh range:[0,255,255] type:#integer width:40 align:#right
  		
  		label satlabel "Sat Range" align:#left across:3
  		spinner spn_satlow range:[0,255,0] type:#integer width:40 align:#right
  		spinner spn_sathigh range:[0,255,255] type:#integer width:40 align:#right
  		
  		label vallabel "Val Range" align:#left across:3
  		spinner spn_vallow range:[0,255,0] type:#integer width:40 align:#right
  		spinner spn_valhigh range:[0,255,255] type:#integer width:40 align:#right
  		
  		label randomise "Randomise:" align:#left across:3
  		button btn_selected "Selected" align:#right offset:[19,0] across:2
  		button btn_all "All" align:#right
  
  
  		fn checkLow &lowVal &highVal =
  		(	
  			if lowVal > highVal do
  			(	
  				highval = lowval
  			)
  		)	
  			
  		fn checkHigh &lowVal &highVal =
  		(	
  			if lowVal > highVal do
  			(	
  				lowval = highval
  			)
  		)
  			
  		fn hueChange =
  		(	
  			tempcol2 = RandomWirecolorHSV.col1.color
  			tempcol2.h = RandomWirecolorHSV.spn_huelow.value
  			RandomWirecolorHSV.col1.color = tempcol2
  			tempcol3 = RandomWirecolorHSV.col2.color
  			tempcol3.h = RandomWirecolorHSV.spn_huehigh.value
  			RandomWirecolorHSV.col2.color = tempcol3
  		)
  			
  		fn FilePropInit =
  		(	
  			HueLowIndex = fileProperties.findProperty #custom "HueLow"
  			HueHighIndex = fileProperties.findProperty #custom "HueHigh"
  			
  			SatLowIndex = fileProperties.findProperty #custom "SatLow"
  			SatHighIndex = fileProperties.findProperty #custom "SatHigh"
  			
  			ValLowIndex = fileProperties.findProperty #custom "ValLow"
  			ValHighIndex = fileProperties.findProperty #custom "ValHigh"
  	
  			
  			if HueLowIndex != 0 then
  			(	RandomWirecolorHSV.spn_huelow.value = fileProperties.getPropertyValue #custom HueLowIndex
  				hueChange()				
  			)
  			
  			if HueHighIndex != 0 then
  			(	RandomWirecolorHSV.spn_huehigh.value = fileProperties.getPropertyValue #custom HueHighIndex
  				hueChange()				
  			)
  			
  			if SatLowIndex != 0 then
  			(	RandomWirecolorHSV.spn_satlow.value = fileProperties.getPropertyValue #custom SatLowIndex
  			)
  			
  			if SatHighIndex != 0 then
  			(	RandomWirecolorHSV.spn_sathigh.value = fileProperties.getPropertyValue #custom SatHighIndex
  			)
  			
  			if ValLowIndex != 0 then
  			(	RandomWirecolorHSV.spn_vallow.value = fileProperties.getPropertyValue #custom ValLowIndex
  			)
  			
  			if ValHighIndex != 0 then
  			(	RandomWirecolorHSV.spn_valhigh.value = fileProperties.getPropertyValue #custom ValHighIndex
  			)
  			
  		)
  		
  		fn changeHueProp =
  		(
  			fileProperties.addProperty #custom "HueLow" (RandomWirecolorHSV.spn_huelow.value)
  			fileProperties.addProperty #custom "HueHigh" (RandomWirecolorHSV.spn_huehigh.value)
  		)
  
  		fn changeSatProp =
  		(
  			fileProperties.addProperty #custom "SatLow" (RandomWirecolorHSV.spn_satlow.value)
  			fileProperties.addProperty #custom "SatHigh" (RandomWirecolorHSV.spn_sathigh.value)
  		)
  
  		fn changeValProp =
  		(
  			fileProperties.addProperty #custom "ValLow" (RandomWirecolorHSV.spn_vallow.value)
  			fileProperties.addProperty #custom "ValHigh" (RandomWirecolorHSV.spn_valhigh.value)
  		)
  
  
  
  		on RandomWirecolorHSV open do
  		(	FilePropInit ()
  		)
  
  		on spn_huelow changed huelowval do
  		(	checkLow &spn_huelow.value &spn_huehigh.value
  			changeHueProp ()
  			hueChange ()
  		)
  			
  		on spn_huehigh changed huehighval do
  		(	checkHigh &spn_huelow.value &spn_huehigh.value
  			changeHueProp ()
  			hueChange ()
  		)
  			
  		on spn_satlow changed satlowval do
  		(	checkLow &spn_satlow.value &spn_sathigh.value
  			changeSatProp ()
  		)
  			
  		on spn_sathigh changed sathighval do
  		(	checkHigh &spn_satlow.value &spn_sathigh.value
  			changeSatProp ()
  		)
  			
  		on spn_vallow changed vallowval do
  		(	checkLow &spn_vallow.value &spn_valhigh.value
  			changeValProp ()
  		)
  			
  		on spn_valhigh changed valhighval do
  		(	checkHigh &spn_vallow.value &spn_valhigh.value
  			changeValProp ()
  		)
  			
  		on btn_selected pressed do
  		(	
  			if selection.count !=0 then 
  			(
  				for obj in selection do 
  				(	
  					hue = (random spn_huelow.value spn_huehigh.value)
  					sat = (random spn_satlow.value spn_sathigh.value)
  					val = (random spn_vallow.value spn_valhigh.value)
  					tempColor = color 0 0 0
  					tempColor.v = val
  					tempColor.s = sat
  					tempColor.h = hue
  					obj.wirecolor = tempColor
  				)
  			)
  			else
  			(
  				messagebox "Select something first"
  			)
  		)
  		
  		on btn_all pressed do
  		(	
  			if objects.count !=0 then 
  			(	
  				for obj in objects do 
  				(	
  					hue = (random spn_huelow.value spn_huehigh.value)
  					sat = (random spn_satlow.value spn_sathigh.value)
  					val = (random spn_vallow.value spn_valhigh.value)
  					tempColor = color 0 0 0
  					tempColor.v = val
  					tempColor.s = sat
  					tempColor.h = hue
  					obj.wirecolor = tempColor
  				)
  			)
  			else
  			(
  				messagebox "No objects in scene"
  			)
  			
  		)
  
  	)
  		
  		
  	createdialog RandomWirecolorHSV 185 110
  )
18 Replies

why not store them in a custom attribute block (set on the sceneroot object (has issues in older max versions), or a track view node, or anywhere that’s got a maxwrapper really)?

if nothing else, you could abstract the file properties function and call it more directly from the UI event handlers and such; but I really don’t think file properties is an appropriate spot for such storage anyway

it’s possible to add your states into a persistant array. I don’t know if it’s the best way to do it, but it works.

I think one of the problems with a persistent global was that if you started to load a file, but then didn’t actually load it (or merge it), then your global variable would still be overwritten.

It does have the major advantage of being able to store almost any maxscript data in any combination you want… whereas with CA’s, you’re stuck with the parameter types allowed and there’s no mixing them.

I haven’t gotten a chance to play with it much but Rob has a ui manager script on tech-artists as part of their Community scripts initiative.

From the script header:


This code is in the public domain.  Published and maintained by www.tech-artists.org
*************************/
/*
The basic idea of iniMgr is scripters can place a single line in a their rollout events to save and load ini settings.
"on theRollout open do (iniMgr.load( ) )" would load the rollout settings last saved.
"on theRollout close do (iniMgr.save() ) would save the rollout settings to an ini file.
This sort of integration is ideal for scripters, who will not need to worry about dynamically saving/loading settings
	specified for each rollout.
The idea is NOT to save ALL rollout data.  Just the CONTROL PROPERTIES that the user can change via the UI.
	We will NOT store properties NOT ACCESSABLE through the UI (such as height, width, etc.)
Support can be provided at a later date to write ALL UI data but this will have to be done on a per-control
	basis by passing them to initMgr.save and initMgr.load
*/

the main site: http://tech-artists.org/

the uiMgr repository: http://tech-artists.org/hg/tao_official/mxs_uimgr/

But now that i read the actual question, i see that you’re looking PER MAXFILE, and this is PER SCRIPT

shouldn’t be an issue to make it per-maxfile if it loops over e.g. .controls, get the control type, then gets/sets its value accordingly. only ‘problem’ is that you often don’t really want all controls to be enumerated in that manner (could exclude them by naming them separately to begin with) – but yes, 3rd will have to decide how/where he wants to store things, first

Thanks everyone. I think I’ll go with the persistent globals option as they seem to do the trick for me. I know I could just use the premade script from tech-artists, but then I wouldn’t learn how to do it myself. I just had a play around with the advice from ZeBoxx2 and never having used the controls array before, I am pleasantly surprised. I came up with the code below. Is this sort of what you were talking about ZeBoxx2?


      for i = 1 to (RandomWirecolorHSVDialog.controls.count) do 
   (
   	currentControl = RandomWirecolorHSVDialog.controls[i]
   	if (classof currentControl == SpinnerControl)  then 
   	(
   		pgName = ("perGlobUI_" + currentControl.name)
   		if (execute(pgName)==undefined) then
   		(
   			execute ("persistent global " + pgName + " = " + (currentControl.value as string))
   			format "Making Persistent Global %
"pgName
   		)
   	)
   )
      )
 Cheers,
 
 Cg.

yep, something like that

just a thought, couldn’t you implement a preset file (like an ini, or xml) that is named the same as the file itself and stored in a dedicated folder somewhere. You could then, when opening the script, check if a preset exists the same as the maxfilename, and load it. Might be a problem it you are using hundreds of maxfiles but the preset file would be tiny. You could also save one when exiting the script if there wasnt one present. Perhaps an option without having to use persistent globals ick :argh:

1 Reply
(@polimeno)
Joined: 11 months ago

Posts: 0
    totally agree !!!
 
 quick test ( using [i].ini[/i] ) :

        YourFolder_Inside_MaxRoot = "Custom_User_Settings"
        --eg C:\Arquivos de programas\Autodesk\3ds Max 9\Custom_User_Settings
        
        YourScript_Name = "YourScript_Settings" +   (".ini")
        
        global YourIniFile = getDir #maxroot + "\\" + YourFolder_Inside_MaxRoot + "\\" + YourScript_Name
        
        testVal = [0,10,40]
        testType = "Category"
        testControl = "Controller"
        
        setIniSetting YourIniFile testTypey testControl (testVal as string)
        execute (getIniSetting YourIniFile testType testControl)
        
        

i strongly recomend you to check outthis Bobo´s DVD, because describes it in step-by-step using .ini files.

ps
would be cool if someone can post an example using XML file !

persistent globals are far less ‘ick’ than having to track another file (2010’s asset tracking enhancements might make that slightly more feasible – but I’ve not looked into that).

The only thing I’ve found ick about persistent globals is that potential overwrite issue* and that plugins can’t access data stored within the persistent globals (which is not an issue if you don’t intend to have anything but your script(s) access it anyway).

I think there were other issues (bobo explained them in a thread on here once… ‘ll search for it in a bit), but…

  • a persistent global will store e.g. #(true,1.0,“hello world”). A custom attribute block will not (not without setting up 3 parameters of types #boolean, #float and #string, and assigning to those)
  • a persistent global will store, say, a struct. No can do in custom attributes, meaning that any struct data would have to be copied piece-wise (again to different parameters where appropriate)
  • for that matter… a persistent global will store any MaxScript value including references to any MaxWrappers. A CA will store most of the maxwrappers, but an ini file, xml file, etc. most certainly wouldn’t.

Unless there’s another method to store MaxScript values in a max scene file so that they can be reloaded with ease, persistent globals are sometimes maybe not the best, but certainly the most convenient solution.

Still can’t find the post with all the pros/cons of persistent globals… maybe it wasn’t Bobo’s :\

Page 1 / 2