[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"
)
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]