Two questions about the script editor


I’m aware that this question might be a futile one, because I know that there’s some major limitations to customizability in 3dsMax.

My first question is that when you open you script editor, you often find all the tabs of scripts that has been opened in the editor. Is there some way to automatically clear all of those tabs so that all you’re left with is the “1 Untitled” tab?

My second question is even more tricky, but I was wondering if there’s some way to specify the exact positioning of the script editor and the listener? I’ve attached an image of an example of how I would like it, is this possible? Or would you need to do some hacky shit that depend on screensize and resolution?

Here’s the example:


you can use mxseditor plugin to set mxs editor as extended viewport (this way you can put the editor in one view and the listener into another)
or if you still want it as a floating window use something like that

	g = (dotNetClass "Autodesk.Max.GlobalInterface").Instance
	g.slidewindow  (dotNetObject "system.intptr" g.theMXSEditorInterface.EditorGetMainHWND) 100 100
	g.slidewindow  (dotNetObject "system.intptr" g.TheListener.ListenerWindow) 100 (100 + (windows.getWindowPos g.theMXSEditorInterface.EditorGetMainHWND).h)
	windows.sendmessage g.theMXSEditorInterface.EditorGetMainHWND 0x111 IDM_CLOSEALL 0 -- don't know how to suppress popups for unsaved docs

upd auto press NO in unsaved docs popups

	g = (dotNetClass "Autodesk.Max.GlobalInterface").Instance
	g.slidewindow  (dotNetObject "system.intptr" g.theMXSEditorInterface.EditorGetMainHWND) 100 100
	g.slidewindow  (dotNetObject "system.intptr" g.TheListener.ListenerWindow) 100 (100 + (windows.getWindowPos g.theMXSEditorInterface.EditorGetMainHWND).h)
	fn OnPopup =
		local hwnd = DialogMonitorOPS.GetWindowHandle()
		if hwnd != undefined do
			local data = windows.getHWNDData hwnd

			if data[4] == "#32770" do
                index = 2     -- 1: Yes, 2: No, 3: Cancel
				UIAccessor.PressButton (windows.getChildrenHWND hwnd)[index ][1]
	DialogMonitorOPS.Enabled = true
	DialogMonitorOPS.RegisterNotification OnPopup id:#xxx42

	windows.sendmessage g.theMXSEditorInterface.EditorGetMainHWND 0x111 IDM_CLOSEALL 0

	DialogMonitorOPS.Enabled = false
	DialogMonitorOPS.UnRegisterNotification id:#xxx42


Thank you Serejah, you definitely pointed me in the right direction!

I did some more searching based on what you gave me, and I found out that the following code does all I want except auto-confirm not to save existing tabs in the Script Editor:

-- Open MXSEditor
actionMan.executeAction 0 "40839"
-- Open New a new script tab
actionMan.executeAction 0 "40469"
-- Open MAXScript Listener
actionMan.executeAction 0 "40472"

-- Position and size the Editor and the Listener (PosX, PosY, Width, Height)
globalMsxInterface = (dotNetClass "Autodesk.Max.GlobalInterface").Instance
(windows.setWindowPos (globalMsxInterface).theMXSEditorInterface.EditorGetMainHWND 2 100 900 500 true)
(windows.setWindowPos (globalMsxInterface).TheListener.ListenerWindow 2 590 900 400 true)

-- Close all existing tabs in the MXSEditor (still gets a prompt)
windows.sendMessage (globalMsxInterface).theMXSEditorInterface.EditorGetMainHWND 0x111 503 0

I did however try your updated attempt without success, don’t know why. It would be nice to find a way to automatically choose “No” to the save-prompt, but I’m already pretty happy with this though :slight_smile:

Thanks again main, much appreciated!

One last thing though, and this might be a hell of a lot harder challenge - but do you know if it’s possible to adjust the separator in the listener?


Separator? What’s that?

Auto close unsaved

hard to tell what could go wrong here… works in 2014 & 2020


The listener is actually splitted into two parts: one (the pink at the top) where every action is recorded, then the other (the white at the bottom) where the output of any executed scripts is printed:
If possible, I would really like to adjust that separator-position through MaxScript.

By the way, I see that it works for you. I have no idea why it doesn’t for me, but it’s really not a big deal. Coming to think of it, I do actually think it might be nice some times to be prompted before it removes anything :slight_smile:


You can try to do it like that, but maybe there’s another method exist. I don’t know
Unfortunately it resets back to its original size when you try to resize it manually afterwards.
Maybe some inner data has to be changed as well to make it work.

	windows.setWindowPos g.TheListener.MacrorecBox    0 0 500 100 true
	windows.setWindowPos g.TheListener.EditBox        0 100 500 200 true
	windows.setWindowPos g.TheListener.ListenerWindow 100 100 500 300 true

	b2 = g.box2.create()
	g.GetClientRectP (asptr g.TheListener.ListenerWindow) b2
	format "[%,%] [%,%]\n" b2.x b2.y b2.w b2.h
	g.GetClientRectP (asptr g.TheListener.MacrorecBox) b2
	format "[%,%] [%,%]\n" b2.x b2.y b2.w b2.h
	g.GetClientRectP (asptr g.TheListener.EditBox) b2
	format "[%,%] [%,%]\n" b2.x b2.y b2.w b2.h

Found that listener_split_ratio setting is saved in maxscrpt.dsk file found in appdata folder.
It loads just once on max startup so you can’t change the ratio for current max session.


Now it is enough to calc how many pixels up or down you need to drag macro window to resize it.

	fn makeparam w l =
		bit.or (bit.and w 0xFFFF) (bit.shift l 16)
	local size_macro = windows.getWindowPos g.TheListener.MacrorecBox	
    local diff = 20 -- enlarge macro window height by 20px

	local mouseParam = makeparam (size_macro.w / 2) size_macro.h
	windows.sendMessage g.TheListener.ListenerWindow 0x201 0x1 mouseParam -- WM_MOUSEDOWN
	mouseParam = makeparam (size_macro.w / 2) (size_macro.h + diff)
	windows.sendMessage g.TheListener.ListenerWindow 0x200 1 mouseParam -- WM_MOUSEMOVE
	windows.sendMessage g.TheListener.ListenerWindow 0x202 0 mouseParam -- WM_MOUSEUP


Dude, there are some wizards on this forum! I found out that if I duplicated the code with diff -1000 first then diff 150 afterwards it would consistently get correct.

But seriously, this kind of stuff is seriously cryptic to me, how the hell do you figure out how to do stuff like this? Even though I get the solution from you, I still can’t wrap my brain around how/why it actually works. The bitshifts for example, that’s basically alien to me.

My impresion is that people like yourself, denisT, Klvnk and miauu are people that almost exclusively find solutions to problems that noone else can figure out. It really makes me wonder what you occupations really are :smiley:

Anyway’s, thank you so much!


Bit shifts aren’t something complicated, you can see them being used a lot in window messages. But it is just a neat way to store and pass two values.



the rest of the people just have a job :rofl: