Notifications
Clear all

[Closed] RC Menu

I’m trying to make a dynamic RC menu which is organized based on the subfolders of the target ed directory. I’ve come across a script on Raphael Insanto’s website which does not seem to be executing at all. This is his snippet of code. http://graph.net84.net/ under “Dynamic RC Menu Function”

Aside from that snippet I’ve attached an image to help explain what I’m after.


(
   fn makeDirRCMenu dir:"" =
   (
      if doesFileExist dir do
      (
         local def = ""

         def+="
"+"rcmenu dirRCMenu"
         def+="
"+"("
         def+="
"+"   fn flt = ("+ true as string +")"
         def+="
"+"   menuItem expOpen "Open in Explorer" checked:false"
         def+="
"+"   separator sep1 filter:flt"
         def+="
"+"   menuItem add2favs "Add to Favourites" checked:false"
         def+="
"+"   menuItem remVfavs "Remove from Favourites" checked:false"
         def+="
"+"   separator sep2 filter:flt"
         def+="
"+"   on expOpen picked do"
         def+="
"+"   ("
         def+="
"+"      shellLaunch @\"" + dir + "\" \"\""
         def+="
"+"   )"
         def+="
"+"   on add2favs picked do"
         def+="
"+"   ("
         def+="
"+"      shellLaunch @\"" + dir + "\" \"\""
         def+="
"+"   )"
         def+="
"+"   on remVfavs picked do"
         def+="
"+"   ("
         def+="
"+"      shellLaunch @\"" + dir + "\" \"\""
         def+="
"+"   )"
         def+="
"+")--END RCMenu"
         def+="
"+"PopupMenu dirRCMenu"

         print def --DEV/DEBUG ONLY

         try
         (
            execute def
         )
         catch
         (
            print (getCurrentexception())
         )
      )
      return OK
   )--END makeDirRCMenu FN

   makeDirRCMenu dir:@"$scripts"
)


14 Replies

use dontet “ContextMenu” :


(
	form = dotnetobject "MaxCustomControls.Maxform"
	form.Text = "Dynamic ContextMenu"
	cm = dotNetObject "ContextMenu"
	form.ContextMenu = cm
	
		items = #("Create Object", "Delete Object", "-", "Select")
		
		for i in items do
		(
			item = cm.menuitems.add i
			item.name = i
		)
		fn addObject s e = with undo "Create *Object*" on (box pos:(random [-100,-100,-100] [100,100,100]))
		fn delObject s e = with undo "Delete *Object*" on (if objects.count > 0 do delete objects[objects.count])
		dotnet.addEventHandler cm.menuitems.item[0] "Click" addObject
		dotnet.addEventHandler cm.menuitems.item[1] "Click" delObject
		
	fn onPopup s e = 
	(
		i = (s.menuitems.Find "Delete Object" off)[1]
		i.enabled = (objects.count > 0)

		i = (s.menuitems.Find "Select" off)[1]
		i.menuitems.clear()
		
		fn selObject s e = with undo "Select *Object*" on 
		(
			select (maxops.getnodebyhandle (s.name as integer))
		) 

		if objects.count > 0 then 
		(
			for n in objects do
			(
				item = i.menuitems.add n.name
				item.name = n.inode.handle as string
				dotnet.addEventHandler item "Click" selObject
			)
		)
		else 
		(
			item = i.menuitems.add "No Objects"
			item.enabled = off
		)
	)
	dotnet.addEventHandler cm "Popup" onPopup
	form.showmodeless()
)

This is great. I’m not to familiar with dotNet stuff. I’ve been slowly trying to learn it more and more. It has some great controls. Many far better than maxscript. The only problem I’m having now is how to actually run the script when its selected in list of items?


(
	dir = @"C:\Users\Desktop	rash\scripts" --//Main Scripts directory
	dirArray = GetDirectories (dir+"/*") --//Get subfolders in directory
	foldersArray = for d in dirArray collect (trimright (filenameFromPath d) "\\") --//Array which stores just the names of the subfolders
	
	form = dotnetobject "MaxCustomControls.Maxform"
	form.Text = "Dynamic ContextMenu"
	cm = dotNetObject "ContextMenu"
	form.ContextMenu = cm

	for i in foldersArray do
	(
		item = cm.menuitems.add i
		item.name = i
	)
		
	fn onPopup s e = 
	(
		for b = 1 to foldersArray.count do (
			i = (s.menuitems.Find (foldersArray[b] as string) off)[1]
			i.menuitems.clear()
			
			sFiles = #()
			sFiles = getFiles (dirArray[b] + "\\*.ms*")
			
			fn fnRunScript s e = --Run the selected script 
			(
		
			) 
			
			if sFiles.count > 0 then --//Add the scripts to appropriate list
			(
				for n in sFiles do
				(
					scriptName = getFIleNameFile n
					item = i.menuitems.add scriptName
					
					dotnet.addEventHandler item "Click" fnRunScript
				)
			)
			else
			(
				item = i.menuitems.add "No Scripts"
				item.enabled = off
			)
		)		
	)
	dotnet.addEventHandler cm "Popup" onPopup
	form.showmodeless()
)

Nearly complete.
I’ve updated the code posted above this post.
I’m not exactly sure how to add and even handle that will execute the maxscript (.ms)?

fn fnRunScript s e = --Run the selected script 
			(
				format "s.name: %
" s.name
			) 
			
			if sFiles.count > 0 then --//Add the scripts to appropriate list
			(
				for n in sFiles do
				(
					scriptName = getFIleNameFile n
					item = i.menuitems.add scriptName
					item.name = scriptName
					dotnet.addEventHandler item "Click" fnRunScript
				)
			)

The format in fnRunScript will print the name of the selected ms file. Use fileIn() with full path to start the script.

This work for me, but I think that this is not the right approach.

(
   	local fullPath = undefined
   	dir = @"C:\" --//Main Scripts directory
   	dirArray = GetDirectories (dir+"/*") --//Get subfolders in directory
   	foldersArray = dirArray--for d in dirArray collect (trimright  (filenameFromPath d) "\\")/ --//Array which stores just the names of the subfolders
   
   	form = dotnetobject "MaxCustomControls.Maxform"
   	form.Text = "Dynamic ContextMenu"
   	cm = dotNetObject "ContextMenu"
   	form.ContextMenu = cm
   
   	for i in foldersArray do
   	(
   		item = cm.menuitems.add i
   		item.name = i
   	)
   		
   	fn onPopup s e = 
   	(
   		
   		for b = 1 to foldersArray.count do
   		(
   			i = (s.menuitems.Find (foldersArray[b] as string) off)[1]
   			i.menuitems.clear()
   			
   			sFiles = #()
   			sFiles = getFiles (dirArray[b] + "\\*.ms*")
   			
   			fn fnRunScript s e = --Run the selected script 
   			(
   				fileIn (fullPath+s.name+".ms")
   			) 
   			
   			if sFiles.count > 0 then --//Add the scripts to appropriate list
   			(
   				for n in sFiles do
   				(
   					fullPath = getFilenamePath n
   					scriptName = getFileNameFile n
   					item = i.menuitems.add scriptName
   					item.name = scriptName
   					
   					dotnet.addEventHandler item "Click" fnRunScript
   				)
   			)
   			else
   			(
   				item = i.menuitems.add "No Scripts"
   				item.enabled = off
   			)
   		)		
   	)
   	dotnet.addEventHandler cm "Popup" onPopup
   	form.showmodeless()
   )

Edit: You can use your code with this:


  			fn fnRunScript s e = --Run the selected script 
  			(
  				fileIn s.name
  			) 
  			if sFiles.count > 0 then --//Add the scripts to appropriate list
  			(
  				for n in sFiles do
  				(
  					scriptName =  n
  					item = i.menuitems.add scriptName
  					item.name = scriptName
  					
  					dotnet.addEventHandler item "Click" fnRunScript
  				)
  			)

but in the RCmenu will be dysplayed full path to the ms files.
Also, this is not work for me:

foldersArray = for d in dirArray collect (trimright  (filenameFromPath d) "\\")/

Here what listener return:
[/b]

dir = @"C:\" 
  -- "C:\"
dirArray = GetDirectories (dir+"/*")
  -- #("C:\\Documents and Settings\", "C:\\New Folder\", "C:\\Program Files\", "C:\\RECYCLER\", "C:\\System Volume Information\", "C:\\WINDOWS\")
foldersArray = for d in dirArray collect (trimright  (filenameFromPath d) "\\")
  -- #("", "", "", "", "", "") 

[b]

From mxs reference:
[/b][left][/left]

[left]filenameFromPath <filename_string>
[/left]
[left]Returns the file name and extension of a full file name, useful for labeling file buttons in rollout panels.[/left]

[left]
[/left]
[left]but you use it with folder names, not with files.
[/left]
[left]This work for me:
[/left]
[left]

foldersArray = for d in dirArray collect (trimright  d "\\")

[/left]

That is a great solution.
Kostadin I appreciate you help on this. It’s definitely getting closer and closer.

It seems to work in the way I’d like it to. The only problem is that it displays the full filepath which becomes super long across the screen.

I’d like to figure out a way to display just the filename and foldname, not the entire path.

Would it be easier to return an integer for the subfoler and then and integer for the script.
So it would be for example (2,5)
which would be the 2nd subfolder of scripts and the 5 script in that category. I could see it being a problem though at the same time…

There has to be a way to keep the display simple like the image above.

Aside from everything this is what I’ve got so far.
Just need to figure out a way to display just the script name for example:
Wirecolor.ms
rather than the entire filepath…

I use the trimRight otherwise all the foldernames for as:
Animation
Rendering\


(
   	local fullPath = undefined
   	dir = @"C:\Users\Crabs User\Desktop	estScripts" --//Main Scripts directory
   	dirArray = GetDirectories (dir+"/*") --//Get subfolders in directory
   	foldersArray = for d in dirArray collect (trimright (filenameFromPath d) "\\") --//Array which stores just the names of the subfolders
   
   	form = dotnetobject "MaxCustomControls.Maxform"
   	form.Text = "Dynamic ContextMenu"
   	cm = dotNetObject "ContextMenu"
   	form.ContextMenu = cm
   
   	for i in foldersArray do
   	(
   		item = cm.menuitems.add i
   		item.name = i
   	)
   		
   	fn onPopup s e = 
   	(
   		for b = 1 to foldersArray.count do
   		(
   			i = (s.menuitems.Find (foldersArray[b] as string) off)[1]
   			i.menuitems.clear()
   			
   			sFiles = #()
   			sFiles = getFiles (dirArray[b] + "\\*.ms*")
   			
  			fn fnRunScript s e = --Run the selected script 
  			(
  				fileIn s.name
  			) 
  			if sFiles.count > 0 then --//Add the scripts to appropriate list
  			(
  				for n in sFiles do
  				(
  					scriptName = n --getFIleNameFile n
  					item = i.menuitems.add scriptName
  					item.name = scriptName
					-- variable "n" contains the fullpath extention
  					
  					dotnet.addEventHandler item "Click" fnRunScript
  				)
  			)
   			else
   			(
   				item = i.menuitems.add "No Scripts"
   				item.enabled = off
   			)
   		)		
   	)
   	dotnet.addEventHandler cm "Popup" onPopup
   	form.showmodeless()
   )

To display only the name of the script use this code:

(
     	   local fullPath = undefined
     	   dir = @"C:\" --//Main Scripts directory
     	   dirArray = GetDirectories (dir+"/*") --//Get subfolders in directory
     	   foldersArray = dirArray--for d in dirArray collect (trimright  (filenameFromPath d) "\\")/ --//Array which stores just the names of the subfolders
        
     	   form = dotnetobject "MaxCustomControls.Maxform"
     	   form.Text = "Dynamic ContextMenu"
     	   cm = dotNetObject "ContextMenu"
     	   form.ContextMenu = cm
        
     	   for i in foldersArray do
     	   (
     		   item = cm.menuitems.add i
     		   item.name = i
     	   )
     		   
     	   fn onPopup s e = 
     	   (
     		   
     		   for b = 1 to foldersArray.count do
     		   (
     			   i = (s.menuitems.Find (foldersArray as string) off)[1]
     			   i.menuitems.clear()
     			   
     			   sFiles = #()
     			   sFiles = getFiles (dirArray[b] + "\\*.ms*")
     			   
     			   fn fnRunScript s e = --Run the selected script 
     			   (
     				   fileIn (fullPath+s.name+".ms")
     			   ) 
     			   
     			   if sFiles.count > 0 then --//Add the scripts to appropriate list
     			   (
     				   for n in sFiles do
     				   (
     					   fullPath = getFilenamePath n
     					   scriptName = getFileNameFile n
     					   item = i.menuitems.add scriptName
     					   item.name = scriptName
     					   
     					   dotnet.addEventHandler item "Click" fnRunScript
     				   )
     			   )
     			   else
     			   (
     				   item = i.menuitems.add "No Scripts"
     				   item.enabled = off
     			   )
     		   )		
     	   )
     	   dotnet.addEventHandler cm "Popup" onPopup
     	   form.showmodeless()
        )
  (the first example of my previous post). You use it with 
fileIn s.name
   (wich give you the long filePath+fileName)instead of:
fileIn (fullPath+s.name+".ms")
   Try the code above and you will have only the name of the script in the RCMenu(like in the image you show). 

You can change this line:

scriptName = getFileNameFile n

– return welder.you have to use (fileIn (fullPath+s.name+”.ms”))
to:

scriptName = filenameFromPath n

return welder.ms to use

fileIn (fullPath+s.name)

Would it be easier to return an integer for the subfoler and then and integer for the script.
So it would be for example (2,5)

denistT return integer to SelectObj function because inode.handle is an integer and maxops.getNodeByHandle need an integer as an argument to select object. Here the returned value is a file name(string).May be it is possible to return two integers, but I think that @denisT, @lo or somebody else can can show you how to do it or can show you a better solution.

The latest version you posted only works if I replace what you have for line 23 with this line
Mainly just adding the [b] to it.


i = (s.menuitems.Find (foldersArray[b] as string) off)[1]

Aside from putting that in there the actual script don’t open correctly because there fullPath is not correct. If i print the fullpath of the script it’s printed path is different from its actual location.


(
   	local fullPath = undefined
   	dir = @"C:\Users\Crabs User\Desktop	estScripts" --//Main Scripts directory
   	dirArray = GetDirectories (dir+"/*") --//Get subfolders in directory
   	foldersArray = for d in dirArray collect (trimright (filenameFromPath d) "\\") --//Array which stores just the names of the subfolders
   
   	form = dotnetobject "MaxCustomControls.Maxform"
   	form.Text = "Dynamic ContextMenu"
   	cm = dotNetObject "ContextMenu"
   	form.ContextMenu = cm
   
   	for i in foldersArray do
   	(
   		item = cm.menuitems.add i
   		item.name = i
   	)
   		
   	fn onPopup s e = 
   	(
   		for b = 1 to foldersArray.count do
   		(
   			i = (s.menuitems.Find (foldersArray[b] as string) off)[1]
   			i.menuitems.clear()
   			
   			sFiles = #()
   			sFiles = getFiles (dirArray[b] + "*.ms*")
   			
  			fn fnRunScript s e = --Run the selected script 
  			(
  				fileIn s.name
  			) 
  			if sFiles.count > 0 then --//Add the scripts to appropriate list
  			(
  				for n in sFiles do
  				(
  					scriptName = n --getFIleNameFile n
  					item = i.menuitems.add scriptName
  					item.name = scriptName
					-- variable "n" contains the fullpath extention
  					
  					dotnet.addEventHandler item "Click" fnRunScript
  				)
  			)
   			else
   			(
   				item = i.menuitems.add "No Scripts"
   				item.enabled = off
   			)
   		)		
   	)
   	dotnet.addEventHandler cm "Popup" onPopup
   	form.showmodeless()
   )

This should help us develop what it is we are after.

I had talked to Paul Neal about this and this is what he responded with.

So here is a neat trick.

The problem that you are having is you have a menu item but once you display it you really don’t know where it came from. So store the path to the file in the menu item. For every dotNet Object there is a Tag property, in that tag property you can store what ever you want. Use the dotNetMXSValue object to store anything that is not a dotNet object. It is a container to store them in. You can also store a struct in there with many channels of data that you can retrieve later. by accessing the .tag.value property. So if you store the path to the file all you need to do is execute something like this if you didn’t use a struct to store the path and just stuffed it right in the tag using dotNetMXSValue.

[pseudoCode]execute theMenuItem.tag.value[/pseudoCode]

Page 1 / 2