Dynamic Maya Shelf [MEL]

For you MEL gurus out there…

I’m creating a small window tool in maya which allows users to drag shelf items into a shelf on the tool. I want to be able to cycle through the current list of commands on the shelf with one keystroke. I also want the currently selected tool to be highlighted via a “Button Background.”

I believe the only way to get this working is to save out the script once they have placed the shelf items in the tools shelf, and edit the file(background color for the currently selected script) and reload the shelf. Correct me if I’m wrong, but I can’t seem to find any other way to accomplish this.

Also, I can’t seem to find a way to reload the saved out shelf. I found the “loadNewShelf” command, but when I try to load the shelf I saved out, it loads the shelf with no contained items.

Any ideas?

Just throwing ideas in the dark here but…

What if your tool window had a bunch of null shelf buttons, which had no picture and called a null command? Then when a user drags one on, you just replace the icon/command for that shelf button, rather than creating a new one.

Make every single button ALSO call a “highlight/unhighlight” mel script which changes its background color when clicked. This can all be setup even before user starts dragging and dropping, no?

I guess it depends on how you are capturing all the user drag/drop information tho…

Any chance we can see your code as it is now, so we can start playing with it?

Not sure I follow you here, but if you want to turn on/off the background color of the icons on shelf buttons you can do that directly with something like this:

shelfButton -e -ebg $createCubeActive "createCubeButton";

Thanks for the replies guys. Here the code.

// Test Window for Shelves
// Shawn Kirsch
// 2/22/2011

//-----------------------------------------------------------------Save Shelf Proc
global proc saveExampleShelf(string $shelf)
{
    string $tempDir = `internalVar -userTmpDir`;
    string $tempDir = $tempDir + "testshelf";
    saveShelf $shelf $tempDir;
    print ("saved shelf to: " + $tempDir + ".mel
");
}

//----------------------------------------------------------------Load Shelf Proc
global proc loadExampleShelf(string $shelf)
{
    string $tempDir = `internalVar -userTmpDir`;
    string $tempDir = $tempDir + "newshelf.mel";
    loadNewShelf "";//$tempDir;
    print ("loaded shelf from: " + $tempDir + ".mel
");
}

//Window Creation
string $windowUI = "ShelfTest";

if ( `window -exists $windowUI` )
    deleteUI -window $windowUI;
    
window -title "ShelfTest" -iconName "ShelfTest" -wh 200 300 $windowUI;

columnLayout -adjustableColumn true;
string $shelf = `shelfLayout -h 120 -childArray`;
setParent..;

columnLayout -adjustableColumn true;
button -l "Save Shelf" -c "saveExampleShelf $shelf;";
button -l "Load Shelf" -c "loadExampleShelf $shelf;";
setParent..;

showWindow $windowUI;

Basically at this point I have a few issues.

1)I can’t load a file I just saved out. (What am I missing??? My idea for this is, if I can save out the file, edit the “Enable Background” field to true, then load this back in. Although this may be too much loading and saving…which brings me to number 2…)
2)If I can get a reference to the current buttons in my shelf, I can just enable the “Background color” as @wolfsong said, which is obviously much more efficient.

Just started looking at this, but just a quick design note, you shouldn’t have this remove the shelf icon from a standard shelf when you drag it, at least not by default. If I build a custom shelf for, say, what I’m doing today, I still want the original shelf to be there and unchanged when I’m no longer using the custom shelf.

I’ll let you know what I find in the code.

EDIT: Also, you want the primary functionality of the script (opening the custom shelf) to be in a function as well, so that to open the shelf, you source it and then run the function. It’s a good practice, and it makes it easier for me to bring up the shelf once I’ve closed it (I just have to run the function again).

your code:

//-----------------------------------------------------------------Save Shelf Proc
global proc saveExampleShelf(string $shelf)
{
    string $tempDir = `internalVar -userTmpDir`;
    string $tempDir = $tempDir + "testshelf";
    saveShelf $shelf $tempDir;
    print ("saved shelf to: " + $tempDir + ".mel
");
}

//----------------------------------------------------------------Load Shelf Proc
global proc loadExampleShelf(string $shelf)
{
    string $tempDir = `internalVar -userTmpDir`;
    string $tempDir = $tempDir + "newshelf.mel";
    loadNewShelf "";//$tempDir;
    print ("loaded shelf from: " + $tempDir + ".mel
");

First off,

You’re hardcoding in file names here, which is generally not the most advisable route, and the file names you are hardcoding are wrong.

string $tempDir = $tempDir + "testshelf";
    saveShelf $shelf $tempDir;

will save the shelf to testshelf.mel in the temp directory, but your load function

string $tempDir = $tempDir + "newshelf.mel";
    loadNewShelf "";//$tempDir;

doesn’t look for testshelf.mel, or any file at all. Additionally, from your string, it looks like you would have it looking for newshelf.mel.

I’m going to keep plugging away at this, I think I’ve got most of the major code issues figured out, but that’s the first status report I’ve got.

There are some design issues I didn’t see before here (saving to the temp directory, when some people might want to keep these shelves for long term use, etc). but I’ll try to knock out the code issues first, since they will hinder any implementation of this sort of thing :slight_smile:

yea, the issue with deleting the UI when it’s copied is BAD! I want that changed.

Also, I figured out how to accomplish it without saving/loading. Although I would like to be able to save it when I exit, and load the same shelf up when I start it back up.

Anyways, here’s the code. I believe everything is contained in those 2 lines to make it work.


//grab the array buttons in the shelf
shelfLayout -q -childArray $shelf;

//set "shelfButton103" to enable background
shelfButton -e -ebg true "shelfButton103";

You’re hardcoding in values again. You want to return the buttons to an array, and then iterate over it to work on the buttons.

I think you should focus first on getting the shelf saving and loading. The background highlighting problem seems to be secondary (not unimportant, mind you, but it’s not as important as getting the shelf saving and loading).

Are you then thinking that you save out the parameters of all of the buttons to a text file/MEL file and then use that to reconstruct on re-opening maya/re-opening the shelf? If so, this seems like a reasonable approach

I’ve got a crit for thesis to get to, so I’ll get back to this later this afternoon. Hopefully everything is cleared up by then, but if not I’ll take another crack at it

-t

This is deceptively tricky to do right, or with little of maya’s built-in shelf functions i’ve found. Currently, I have tools that do exactly what you’re trying to do but it’s not what you may call simple, neither am I a mel “guru” for that matter :wink:.

I have a blog post that illustrates some code I wrote a while ago to dynamically load a floating shelf UI upon startup of Maya. Read that if you want an example, although i’ve changed the code quite a bit for my purposes from what’s on the post.

I agree with what someone said earlier that you need to put the shelf into its own function though for ease of calling it later if the UI gets deleted or for reloading the shelf. Also, the tricky part is to have buttons to save and edit the shelf automatically. Thinking down the road, along with the highlighting feature you’re talking about, you’re going to want to group controls in additional shelves or shelf tabs preferably so you’re going to want to have a pretty modular set of code to start with.

Here’s an example bit of code for programming a button “on the fly” as a command wrapper of sorts for making a button for saving the shelf UI.

First, saving which takes a shelfLayout name and a shelf save path location, and creates a command that you can attach to your shelf button. It uses the maya function for saving the shelf called “saveShelf” because it’s more convenient than coding it myself.

//A save shelf command to automatically save a shelf from a custom floating window.
global proc string saveShelfCommand (string $name, string $location) {
string $command = ("//

// Result: Save Shelf //\r"
+“global proc saveThisShelf(){
"
+” string $ja_sh = shelfLayout -q -p " +$name+ ";
"
+" string $shelf = tabLayout -q -selectTab $ja_sh;
"
+" string $tempDir = “” +$location+ “”;
"
+" string $name = (“shelf_” + $shelf);
"
+" $path = ($tempDir + $name + “.mel”);
"
+"\r if (!filetest -f $path) {
"
+" warning ($path + " does not exist, creating…");
"
+" int $fileid = fopen($path, “w”);
"
+" fprint($fileid, “”);
"
+" fclose($fileid);
"
+" }
"
+"\r saveShelf($shelf, ($tempDir + $name));
"
+" print ($shelf + " was saved");
"
+"}
"
+"
saveThisShelf()")
;

return $command;

}

As an example, attach it to your shelf button inside a makeShelf() function like this:


shelfButton
-enableCommandRepeat 1
-enable 1
-width 34
-height 34
-manage 1
-visible 1
-preventOverride 0
-align “center”
-label “Save This Shelf”
-labelOffset 0
-font “tinyBoldLabelFont”
-imageOverlayLabel “save”
-image “commandButton.xpm”
-image1 “commandButton.xpm”
-style “iconOnly”
-marginWidth 1
-marginHeight 1
-annotation (“Use this button to save this shelf to a desired location.
"
+” Currently that location is “” +$sh_loc+ “”
")
-command saveShelfCommand $sh_name $sh_loc
;

This is compatible with Maya2009 so there is no background image functionality but hopefully the principles are being illustrated. Hope this helps! Believe me, you can get pretty creative when creating shelves like this.

haven’t forgotten about this, swamped with my work right now, If I don’t get to it before then, I’ll tackle this on the plane to SF :slight_smile:

Man! I love this feedback.

@Ishindenshin sweet blog!

I actually have a solution that works, I finished it thursday, but have been so busy I forgot to post. @h6x6n, want me to post it, or you wanna try figuring it out?

Of course, I think it’s inefficient and not clever, so when I post it, we can dissect it, if anyone wants…

post it up Unc, if I had more free time I’d say I’ll go back and figure out how I’d do it from scratch, but since that isn’t the case, I’ll just try to see where I can improve it.

Ok, theres 3 files…

WindowCreation

global string $gShelfRef;

global proc string CreateToggleShelf()
{
    //Window Creation
    string $windowUI = "toggleShelfWindow";
    
    if ( `window -exists $windowUI` )
        deleteUI -window $windowUI;
    
    window -title $windowUI -iconName $windowUI -wh 200 300 $windowUI;
    
    columnLayout -adjustableColumn true;
    string $toggleShelf = `shelfLayout -h 120`;
    setParent..;
    
    columnLayout -adjustableColumn true;
    button -l "Print $toggleCounter" -c "print $toggleCounter";
    button -l "Print $shelfCount" -c "int $count = ReturnShelfCount($gShelfRef); print $count;";
    button -l "Reset $toggleCounter" -c "$toggleCounter = 0";
    setParent..;
    
    showWindow $windowUI;
    
    return $toggleShelf;
}

global proc string[] ReturnCurrentShelfItems(string $shelfName)
{
    return `shelfLayout -q -childArray $shelfName`;   
}

global proc int ReturnShelfCount(string $shelfName)
{
    return size(`shelfLayout -q -childArray $shelfName`);
}

//Create the Shelf and return a reference to the shelf
$gShelfRef = CreateToggleShelf();

Driver

//Grab the current items in Shelf
string $shelfContents[] = ReturnCurrentShelfItems($gShelfRef);

//Return num of itmes in the shelf
int $shelfCount = ReturnShelfCount($gShelfRef);

//if shelf contents have changed, reset toggle counter to 0
if($shelfCount <= $toggleCounter)
    $toggleCounter = 0;

//------------------------------------------------------------------------------------toggling

if($toggleCounter >= ($shelfCount-1))
{
    if($shelfCount != 0)
    {
        //unhighlight the last one
        shelfButton -e -ebg false $shelfContents[$toggleCounter];
        
        //change to first indice
        $toggleCounter = 0;    
        
        //highlight it
        shelfButton -e -ebg true $shelfContents[0];
        
        //set current command to current icon!
        string $currCommand = `shelfButton -q -c $shelfContents[0]`;
        eval($currCommand);        
        
        print $toggleCounter;
    }        
}
else
{
    //increase counter
    $toggleCounter += 1;
        
    //unhighlight the last one
    shelfButton -e -ebg false $shelfContents[($toggleCounter-1)];        
    
    //highlight the current one
    shelfButton -e -ebg true $shelfContents[$toggleCounter];  
    
    //set the command to the current icon
    string $currCommand = `shelfButton -q -c $shelfContents[$toggleCounter]`;
    eval($currCommand);
           
    print $toggleCounter;
}

Setup

//a global variable to iterate through the shelf items
global string $toggleCounter = 0;

The last file can be run each time you open maya, or you can set it up as a startup file, I believe it’s UserSetup.mel (inside the scripts directory.)

There are still a few things I haven’t done yet.
a)don’t delete the item off the old shelf.
b)create a back button. (should be very easy)
c)some errors if you try to run the same command without switching through.
d)load/save the current shelf.

What do you think?

[QUOTE=UncCheezy;9266]Man! I love this feedback.

@Ishindenshin sweet blog!

I actually have a solution that works, I finished it thursday, but have been so busy I forgot to post. @h6x6n, want me to post it, or you wanna try figuring it out?

Of course, I think it’s inefficient and not clever, so when I post it, we can dissect it, if anyone wants…[/QUOTE]

Thanks! Also, I haven’t been posting here though i’ve been hanging around for quite a while. But I thought i’d use your post to sort of dive in. I will look into your script, i’d like to know if it works for me as well.