MaxScript Toolbar(beginner) 2

Stragalet
12 min readJan 27, 2024

--

In this second part I will show you how I make my own toolbars, and a a copy paste script that I find very usefull.

I will go slowly so feel free to jump if something feels too obvious.
At the end I posted in text format the code so you can use it from today!

Spoiler: copy paste tool between max sesions!

First Rollout

Lets create a little floating window with a button that does something.
Open a New Script window, this time the code we write will be persistant.

-- defines the rollout that will be created
rollout myToolbar "My new Toolbar" width:200 height:500
(
)

--creates the rollout
createdialog myToolbar

And now we will write the code above, and execute ( control+e )
It should display something like this:

my new Rollout toolbar has born!

Now you can close the rollout “myToolbar”. I will explain a bit what all this does but first, Save the script!! save it anywhere for now, I will call it MyToolbar_001.ms

The rollout code:

Seems quite straight forward but lets go over it step by step.

createdialog myToolbar

With this we call for the creation of a dialog, in this case a rollout dialog, named “myToolbar”
The name can change of course, but it should be consistant in the other parts of the code.

But if we just write that nothing will be created so, we have to define what needs to be created, and that, we add on top. ( Could be added on the bottom too, but it is best practice to add it to the top )

rollout myToolbar "My new Toolbar" width:200 height:500 
(
)

So there it is, we defined the rollout “myToolbar” here the name has to be exactly the same as the one in the create dialog, and the text to the right is just the title of the rollout, so you can writte anything there, even with spaces is fine. After that, width and height of the rollout in pixels.
and then ( ) inside those we can write some stuff and will pop up in our rollout.
But first… exectute the code and move “myToolbar” into a bit of the side of the screen, and execute the code again…

Yes, now we have two Rollout toolbars…
So we need a small line to say it should destroy “myToolbar” if it previously exists.

try (destroydialog myToolbar) catch() 

The line would be that, and we put it at the start.

Now it looks like this.
Try to exectute the code several times now and you will see how the previous toolbar disapear before creating the new one! easy!

This line of code is a bit peculiar, usually in programing, if you make the software to do something but it cannot be done because it doesn’t exist in the first place it would give an error, Maxscript has this cool code that is “try” “catch” that it will try to do it but it won’t crash if it didn’t find anything.

try 
(
destroydialog myToolbar
)
catch
(
)

This is exactly the same line but just in a more “traditional” way of formating, … because is so simple we just write it in a “one-liner” so we can save some precious space ( and possibly some bits too :D )

First Button

Lets add a button to this rollout.

button DoSomething "Do Something"

There you go, you know already where this line needs to go right?

exactly, between the ( ) of the rollout… I’m adding comments everywhere by the way.
yey!

We can define more things for this button, like, tooltip, width, height, border, alignment… this is actually true for almost every object in maxscript, so you better check the documentation and see what options those objects have or you can check some other people scripts to learn from. I’ll do that all the time.

button DoSomething "Do Something" width:180 height:30 tooltip:"a button that does something" border:true align:#center

here is a bunch of propierties for that button!

has a nice tooltip!

But this button does nothing yet, so to fix that we will define what the button will do in another line under the button definition.

 on DoSomething pressed do messageBox "hello world"

You already know from the previous lesson what “messageBox” does, it will open a popup with the text defined after.
The rest of the syntax seems quite straight forward again…
On “DoSomething” this needs to match precisely the name of the button, do something…

voilà!

First Function

So Now we are writting what the button does directly after the “do” but if the action was quite long that wouldn’t be practical at all, so instead of that I tend to separate the the actions from the UI itself so everything is better ordered and actually later on you can call those “actions” for several things.

First we will just copy the messageBox thing in a Function so you see how it works.

A function is like a room where to put things, and the room number is the text after “fn” in this case “myCopy”, by the way… fn is for function.

btw, use my function name for this time, “myCopy” we will use that later.

fn myCopy = 
(
messageBox "hello world"
)

There, after the Try Catch, but, that is not right, because we didn’t tell the button where it needs to go after pressed… now it also contains the messageBox text, so, we will remove that, and add the “room number” to the function we just created, so the function name.

on DoSomething pressed do myCopy ()

Now the button action definition will look like that.

Execture aaaand, it does the same as before, but trust me now is much more clean, and much more powerful!

Lets put that “something” in a function and call it back.

Add another Button

Ok so we got a button working with a function call! yay!
now lets duplicate some lines and change some texts and we will have 2 buttons!

3 things you need to duplicate,
The function entirely, the button, and the On Pressed, part.

On top of that I will change some text so matches with the Copy / Paste functions we are building… be carefull because the Buttons and the On Pressed Need to match!

Also I changed the message box text to “copy” and “Paste”

--try to destroy the rollout dialog if exists
try (destroydialog myToolbar) catch()

-- Function declaration
fn myCopy =
(
messageBox "Copy"
)
fn myPaste =
(
messageBox "Paste"
)


-- defines the rollout that will be created
rollout myToolbar "My new Toolbar" width:200 height:500
(
-- define the button type and looks
button btn_myCopy "Copy" width:180 height:30 tooltip:"a button that does something" border:true align:#center
button btn_myPaste "Paste" width:180 height:30 tooltip:"a button that does something" border:true align:#center

-- define what the button does when it is pressed.
on btn_myCopy pressed do myCopy ()
on btn_myPaste pressed do myPaste ()

)

--creates the rollout
createdialog myToolbar

Here is the code just in case you have some trouble with some spelling, spacing and such… you can always check the Listener to check for errors there, but programming can be tricky with the syntax sometimes, specially when you are not yet used to it.

This starts to look like something useful!

Things to care:

Two buttons cannot have the same name.

First super usefull script that will change your life!

Lets create some usefull script now…

The what? already?
Yes I promise this little script will change your workflow it is just so usefull and I can’t live without it anymore so I want you to have it too.

What is this script about?

Well the script is a copy paste between Max sessions, so you can move objects from one Max to another. It is super convenient to clean up models in a file and then move it to another, or just to test things in another Max.
We exploit the “merge” function for that… and you will see that the script is quite straight forward.

The Copy!

Because we already have the buttons, lets focus on the copy function:

What we will do here is, with the selected object, save selected into a Temporary file located in the 3dsMax Autoback directory.
For that we will use the “if” “then” commands among other things but it should be fairly simple.

I will break it in 3 easy “scripting steps”

  • check that there is actually a selection made.
  • search for the “autoback” folder in Max and define the filename.
  • and we will save selection in that file.

Check that there are objects selected:


fn myCopy =
(
if selection.count > 0 then
(
displayTempPrompt "There are objects selected" 1000
)
else
(
displayTempPrompt "No objects selected" 1000
)
)

First we will check if the “selection” of objects is valid, if not if it is it will display “there are objects selected” otherwise “ ther are no objects selected”
we check that by checking if selection.count is greater than 0, if so display one text, if it is not ( else ) then display another text.

You will see the answer in the bottom of 3dsmax with this method.
1000 is just the miliseconds that text will stay there…. 0 means it will stay there until another message comes out.

Search for the “autoback” folder in Max and Define the file name.

Now we will add some the line… first we need to define the variable.
A variable is an empty “box” you can fill with stuff, sometimes it know what type of info is inside some times we need to define ourselves what goes inside.

 theCopyPasteDir = getdir #autoback
theCopyPasteFile = "\myCopyPasteFile.max"
theCopyPasteString = theCopyPasteDir + theCopyPasteFile

We will add that before the functions, because both myCopy and myPaste will use that information so it needs to get defined first.

The code itself is quite simple again.
there are 3 variables, theCopyPasteDir ,theCopyPasteFile and theCopyPasteString.

So for the theCopyPasteDir we use a function called getdir that will get us the location of the folder where Autoback is.
For theCopyPasteFile we just type directly what is the name of the file we want, you can type any.
And then we put them toguether in another variable…

We will store different “strings of text” inside, Max automatically detects they are strings so we don’t need to add “as string” at the end, but is generally a good practice to know what type of variable are you storing ( integer, float, string… )

 theCopyPasteDir = getdir #autoback as string
theCopyPasteFile = "\myCopyPasteFile.max" as string
theCopyPasteString = theCopyPasteDir + theCopyPasteFile as string

So Like this would also work exactly the same.

There are other ways to do this, for instance you could do this more in a “one-liner” to keep it compact but sometimes is a bit harder to understand so I separated it.

theCopyPasteString = (getdir #autoback) + "\myCopyPasteFile.max" as string

In here instead of 3 variables, I’m just typing everything in just one…
It is a bit less procedural this way so we will use the other.

Also notice I added a “print” to just check that when we click we can see the string in the Listener.
You can execute now and try pressing Copy.

This should popup in the listener.

Save selection in that file.

The last step!
Now we need to actually save the files…

   saveNodes $ theCopyPasteString
displayTempPrompt "Copy Completed" 6000
--try to destroy the rollout dialog if exists
try (destroydialog myToolbar) catch()


-- we define the CopyPaste directory by getting the Autoback forlder as string
theCopyPasteDir = getdir #autoback

-- we define the name of the file
theCopyPasteFile = "\myCopyPasteFile.max"

-- we build the full string, the filename and the name of the file
theCopyPasteString = theCopyPasteDir + theCopyPasteFile

-- Function declaration
-- the copy function
fn myCopy =
(


if selection.count > 0 then
(
-- we save the selected nodes in the file string we defined earlier.
saveNodes $ theCopyPasteString

-- we print the string in the listener to check the path.
print theCopyPasteString

--we display a promt message in the bottom.
displayTempPrompt "Copy Completed" 6000
)
else
(
displayTempPrompt "No objects selected" 1000
)
)

--the paste function
fn myPaste =
(
messageBox "Paste"
)


-- defines the rollout that will be created
rollout myToolbar "My new Toolbar" width:200 height:500
(
-- define the button type and looks
button btn_myCopy "Copy" width:180 height:30 tooltip:"a button that does something" border:true align:#center
button btn_myPaste "Paste" width:180 height:30 tooltip:"a button that does something" border:true align:#center

-- define what the button does when it is pressed.
on btn_myCopy pressed do myCopy ()
on btn_myPaste pressed do myPaste ()

)

--creates the rollout
createdialog myToolbar

There is the new line of code and after there is the full script code again.. Those are some lines of code already!

I changed some of the messages when the copy is performed and added comments to everything.

That is done! now for the Paste.

Tips:

  • Be carefull with the “” strings of text needs them but calling a variable name doesn’t.
  • Keep it clean and ordered.
  • Comment stuff, you won’t remember tomorrow why you did yesterday.

The Paste!

Now lets add the code for the paste! It should be fairly simple.

  mergemaxfile (theCopyPasteString) #select
displayTempPrompt "Paste Complete" 6000

See that we added a #select there so the new objects will be selected so it is easy to move them aside.

Here is the complete code:

--try to destroy the rollout dialog if exists
try (destroydialog myToolbar) catch()

-- we define the CopyPaste directory by getting the Autoback forlder as string
theCopyPasteDir = getdir #autoback

-- we define the name of the file
theCopyPasteFile = "\myCopyPasteFile.max"

-- we build the full string, the filename and the name of the file
theCopyPasteString = theCopyPasteDir + theCopyPasteFile

-- Function declaration
-- the copy function
fn myCopy =
(
if selection.count > 0 then
(
-- we save the selected nodes in the file string we defined earlier.
saveNodes $ theCopyPasteString

-- we print the string in the listener to check the path.
print theCopyPasteString

--we display a promt message in the bottom.
displayTempPrompt "Copy Completed" 6000
)
else
(
displayTempPrompt "No objects selected" 1000
)
)

--the paste function
fn myPaste =
(
print theCopyPasteString
mergemaxfile (theCopyPasteString) #select
displayTempPrompt "Paste Complete" 6000
)


-- defines the rollout that will be created
rollout myToolbar "My new Toolbar" width:200 height:500
(
-- define the button type and looks
button btn_myCopy "Copy" width:180 height:30 tooltip:"Copy" border:true align:#center
button btn_myPaste "Paste" width:180 height:30 tooltip:"Paste" border:true align:#center

-- define what the button does when it is pressed.
on btn_myCopy pressed do myCopy ()
on btn_myPaste pressed do myPaste ()

)

--creates the rollout
createdialog myToolbar

All done!

Seems long but really without the comments is not that much… but just leave there the comments!


try (destroydialog myToolbar) catch()

theCopyPasteDir = getdir #autoback
theCopyPasteFile = "\myCopyPasteFile.max"
theCopyPasteString = theCopyPasteDir + theCopyPasteFile

fn myCopy =
(
if selection.count > 0 then
(
saveNodes $ theCopyPasteString
print theCopyPasteString
displayTempPrompt "Copy Completed" 6000
)
else
(
displayTempPrompt "No objects selected" 1000
)
)

fn myPaste =
(
print theCopyPasteString
mergemaxfile (theCopyPasteString) #select
displayTempPrompt "Paste Complete" 6000
)

rollout myToolbar "My new Toolbar" width:200 height:500
(
button btn_myCopy "Copy" width:180 height:30 tooltip:"Copy" border:true align:#center
button btn_myPaste "Paste" width:180 height:30 tooltip:"Paste" border:true align:#center

on btn_myCopy pressed do myCopy ()
on btn_myPaste pressed do myPaste ()
)

createdialog myToolbar

Congratulations you have your first Copy / Paste Script that works between Max sesions! ( as it is, only between the same versions of Max)

I use this all the time to clean models in one Max and then copy into the good scene after I worked on materials for instance, or debugging stuff.

In the next step we will increase the level a bit,
Talk about Structs, make the bar dockable, send data inside functions and how to do another cool tool that I find very useful!

Part 1 here!
Part 1

Part 3 here!

part 3!

If you found this usefull please leave a comment!

--

--

Stragalet

ストラガレットです! I like making 3DCG stuff OC. Indie Game dev