Notifications
Clear all

[Closed] macroscripts inside a structure

this is not a question. this is not a solution. i just want to let you know how cool it is.

28 Replies
 PEN

Oh come on Denis, you have to share more then that.

Are you creating Macro Scripts from within a structure? Does this not just create a macro script off in the userMacros folder for you?

2 Replies
(@denist)
Joined: 11 months ago

Posts: 0

that is super cool. i fount it couple months ago (honestly it was 5 months ago. but any way…)…

many years i did the same package. a script + a launcher(macroscript). which means two files. but the problem is that the launcher has to know exact place of the launched script. you know what i’m talking about, don’t you?
so… my goal was to find a solution to have only one file with the script and its launcher. and this file has to be free to be placed to any place. why?

… be continued.

(@jsnb)
Joined: 11 months ago

Posts: 0

This is an interesting problem. I usually provide two scripts as you said you did many years ago. One script is the tool itself while the other generates the macroscript and pushes an icon to the toolbar (or removes/changes the macroscript and button from the toolbar if an ‘uninstall’ or ‘update’ is requested.) I do this instead of providing an MCR specifically to allow the system to handle the placement of the mcr into the user’s script folder.

Although relatively pathed to a project folder, i do provide the specific location of the main tool.

For your solution, are you just generating the script location on the fly to determine the initial install? Or are you suggesting something more complicated where the MCR is already generated and then the script is moved – how does it now know its new location? Are you searching for the script each time?

 PEN

Sounds great so far. Can’t wait to see what you have come up with. I know the problems well that you are talking about but I usually use the paths in Max to make sure that they are finding them.

before i continue the main topic i would like to tell a little about Private and Public members in structures…
many of you know about it but many really know how to use it. the max help doesn’t tell too much about this matter. let’s see:
“When defining members (variables and functions) in a struct,the qualifiers public and private can be used to control the member’s visibility to users and the Debugger”…

it’s probably cool to hide something but private members can be used smarter way.
check the sample:


    global HelloWorld 
    (
    	struct HelloWorldStruct
    	(
    	private
    		title = "Hello World"
    	)
    	HelloWorld = HelloWorldStruct()
    	ok
    )
    

    HelloWorld.title
    -- Runtime error: Attempting to access private member: "title" in: (HelloWorldStruct)
    
that's what we were expecting. fine. let's try this:

    global HelloWorld 
    (
    	struct HelloWorldStruct
    	(
    	private
    		title = "Hello World",
    	public
    		pos = [800,200],
    		size = [200,60],
    		dialog = 
    		(
    			rollout dialog ""
    			(
    				on dialog open do 
    				(
    					dialog.title = HelloWorld.title
    				)
    			)
    		),
    		on create do createdialog dialog pos:pos size:size
    	)
    	HelloWorld = HelloWorldStruct()
    	ok
    )
    
    >> MAXScript Rollout Handler Exception:
    -- Runtime error: Attempting to access private member: "title"
    
no luck again... hmm. change title to public and it will work. but it's not a point... 
let's do this:

    global HelloWorld 
    (
    	struct HelloWorldStruct
    	(
    	private
    		title = "Hello World",
    	public
    		fn getTitle = title,
    		pos = [800,200],
    		size = [200,60],
    		dialog = 
    		(
    			rollout dialog ""
    			(
    				on dialog open do 
    				(
    					dialog.title = HelloWorld.getTitle()
    				)
    			)
    		),
    		fn open = createdialog dialog pos:pos size:size
    	)
    	HelloWorld = HelloWorldStruct()
    	HelloWorld.open()
    	ok
    )
    
hey! it works now. it means every function in struct sees all private members.
well but what if i want to change the title. the making it public will help but that's not a point (see above). when we know that all private members are visible for other members of the same structure let's set the title more clever way:

    global HelloWorld 
    (
    	struct HelloWorldStruct
    	(
    	private
    		title = "Hello World",
    	public
    		fn getTitle = title,
    		pos = [800,200],
    		size = [200,60],
    		dialog = 
    		(
    			rollout dialog ""
    			(
    				on dialog open do 
    				(
    					dialog.title = HelloWorld.getTitle()
    				)
    			)
    		),
    		fn setTitle new = 
    		(
    			title = new
    			if dialog.open do dialog.title = title
    		),
    		fn open = createdialog dialog pos:pos size:size
    	)
    	HelloWorld = HelloWorldStruct()
    	HelloWorld.open()
    	ok
    )
    /*
    HelloWorld.setTitle "Bye World"
    */
    
so we don't allow to set title just by assigning new value directly to the property because it can't change our dialog's title automatically anyway...

is it not cool? :)
 PEN

Looks like you are having fun, wondering where this is going of course.

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

it’s going to be more funny… when we will start associate the dialog with a macros

I use this way for any of my tools, indeed.

  • a global struct (with a very specific name to be unique)
  • a rollout in the struct
  • a boolean to identity if the dialog is open or not
  • two public functions open and close which set the boolean to true or false
  • many others private function and members to be hidden in that struct

It is mainly useful to hide your code, as I had to do with some scripts I had to sell.
Anyway, it can be useful to put in evidence some design errors in your code (if you need to make a variable public to workaround some error, it often means you didn’t think well your tools dependencies).

To come back to the subject, you can have one file for the tool :

global g_myVeryGreatTool ;

struct myVeryGreatTool
(
    public
    isWindowOpen = false,

    private
    somePrivateVar = "someValue";
    somePrivateVar2 = "someValue2";

    public roll_Main = rollout roll_Main
    (
        ...
        // notice that in order to access your private functions from the rollout, you have to use "myVeryGreatTool.someFirstPrivateFunc();"
    ),

    private function someFirstPrivateFunc =
    (
        // use this to get rid of functions order !
        this.someSecondPrivateFunc();
    ),

    private function someSecondPrivateFunc =
    (
        print somePrivateVar;
    ),

    public function openTool =
    (
        if (NOT isWindowOpen) then
        (
            createDialog roll_Main ;
            isWindowOpen = true;
        )
    ),

    public function closeTool =
    (
        ...
        closeDialog roll_Main ;
        isWindowOpen = false;
    )
)
g_myVeryGreatTool = myVeryGreatTool()

And the macroscript like this :

macroScript macro_myVeryGreatTool
(
    global g_myVeryGreatTool;
    g_myVeryGreatTool.openTool();
)

Now you can put your macroFile anywhere you want !
Isn’t what you meant, Denis ?

no.the way that you is probably most popular for today. only two years ago i was using the similar file structure. today i use a different concept. where the tool, and its luancher, and ui for max all in the same file, and all in the same local structure.

I have a system of tools that all link to a bunch of .ms files that variously get fileIn’d. I’m looking at converting it all to a structure, but it might be a bit of a pain as the script actually generates scripts – as part of getting dependencies on backburner working, I’ve got a system where a cmdjob.exe job is submitted which effectively opens up max, makes some changes to the scene, and submits the job. This includes the file to load, of course, (as well as other data like which servers to use and all that stuff) and as such, each submission generates a new script to load. So these scripts can’t be part of the structure, as they change every time the script is used to submit a job to BB.

That said, it’s not that important that this bit of it be structured anyway, since the nodes just load max, run the script, then close max straight away.

look at shortcomings of code above:
#1 we have two globals (tool and strcuture) where can have only one
#2 there is a property isWindowOpen… it’s public. but we set its value to ON or OFF it doesn’t change anything. the Dialog will not be open or close.
#3 when we manually close the Dialog the isWindowOpen state doesn’t update

try to solve these problems:


 global HelloWorld  
(
	struct HelloWorldStruct
	(
	private
		title = "Hello World",
		pos = [800,200],
		size = [200,40],
		opened = off,
	public
		dialog = 
		(
			rollout dialog ""
			(
				on dialog open do if isstruct HelloWorld do
				(
					dialog.title = HelloWorld.getTitle()
					HelloWorld.open()
				)
				on dialog close do if isstruct HelloWorld do
				(
					HelloWorld.close()
				)
			)
		),
		fn isOpen = (iskindof dialog RolloutClass and opened),
		fn open = 
		(
			opened = on
			createdialog dialog pos:pos size:size
		),
		fn close = 
		(
			opened = off
			destroydialog dialog
		),
		fn getTitle = title,
		fn setTitle new = 
		(
			title = new
			if isOpen() do dialog.title = title
		)
	)
	HelloWorld = HelloWorldStruct()
	ok
)
 

next spet is to add ‘launcher’ to the struct.

Page 1 / 3