Interfaces using MEL

To introduce the use of user interfaces using MEL we first have to have an idea of the kind of interface we wish to design.

For this example we are going to create an interface to implement the creation and options for a custom primitive, a pill, primitive.

First things first lets write a simple script to create a pill primitive.

Step 1: create a sphere

sphere -p 0 0 0 -ax 0 1 0 -r 1 -n tmpSphere; // new sphere radius 1, at the origin with Y as the up axis.


Step 2: select its middle isoparm and use it to split the sphere in two.

detachSurface -ch 1 -rpo 1 -n detSphere tmpSphere.u[2]; // split it down the centre


Step 3: move the halves equally above and below the axis

setAttr "detSphere.translateY" 1; // top hemisphere up by 1
setAttr "tmpSphere.translateY" -1; // bottom hemisphere down by 1


Step 4: attach the two halves into a pill shape

select -r detSphere.u[2] ; // top hemisphere isoparm
select -tgl tmpSphere.u[2] ; // bottom hemisphere isoparm
attachWithoutMoving;


Step 5: Clean up the surface and give it a name

makeIdentity -apply true -t 1 -r 1 -s 1 tmpSphere; // freeze transformations
xform -cp tmpSphere; // centre its pivot
rename "tmpSphere" "nurbsPill1";

 

Here is the code all together if you want to cut and paste it into the script editor

sphere -p 0 0 0 -ax 0 1 0 -r 1 -n tmpSphere;
detachSurface -ch 1 -rpo 1 -n detSphere tmpSphere.u[2];
setAttr "detSphere.translateY" 1;
setAttr "tmpSphere.translateY" -1;
delete -ch tmpSphere detSphere;

select -r detSphere.u[2] ;
select -tgl tmpSphere.u[2] ;
attachWithoutMoving;
xform -cp tmpSphere;
makeIdentity -apply true -t 1 -r 1 -s 1 tmpSphere;
rename "tmpSphere" "nurbsPill1";
delete detSphere;

With our script already working nicely we want to design a user interface that will allow us to specify the radius and length of the pill.

The first step in creating a user interface is to create a window. In MEL it is quite simply "window". In calling the window function we should also give it a name a title and tell Maya how big we want it to be, so we have thus;

window -w 400 -h 200 -title "NURBS Pill Options" pillWindow;
showWindow pillWindow;

This will create the following window.

There is a problem though here. If you close the window then repaste the code in you should get the following error.

  Error: Object's name is not unique: pillWindow

This is because although we have closed the window, it still exists deep within the bowels of Maya, so we need to flush it out first, before we can reuse this code. To do this we use a "deleteUI" command , with an initial test to see if it already exists.

if (`window -exists pillWindow`)
deleteUI pillWindow;

window -w 400 -h 200 -title "NURBS Pill Options" pillWindow;
showWindow pillWindow;

UI Layouts

Before we start to put things into our windows we need to create some kind of formatting of the window into rows and columns. The most simple kind of format is to simply say that the window consists of columns using the "columnLayout" command. It can have a multitude of parameters, but for now lets leave it simple. Without its options set it defaults to a single column layout and every new additional element is simply put onto the next row.

Now for some controls

So now we have our window we would like to create some controls that allow us to specify the radius and length of our pill.

To create a slider we can use the "floatSliderGrp" command labelled Radius

if (`window -exists pillWindow`)
deleteUI pillWindow;
window -w 400 -h 200 -title "NURBS Pill Options" pillWindow;
columnLayout;

floatSliderGrp -label "Radius "pillRadius;
showWindow pillWindow;

To add a field that allows us to see and modify the current value of the radius we can add the -field true flag

if (`window -exists pillWindow`)
deleteUI pillWindow;
window -w 400 -h 200 -title "NURBS Pill Options" pillWindow;
columnLayout;

floatSliderGrp -label "Radius" -field true pillRadius;
showWindow pillWindow;



The next thing we may wish to change is the maximum and minimum range of our slider. We do this by specifying maxValue and minValue flags. We may also wish to set a default value for the slider and this is done with the -value flag.

if (`window -exists pillWindow`)
deleteUI pillWindow;
window -w 400 -h 200 -title "NURBS Pill Options" pillWindow;
columnLayout;

floatSliderGrp -label "Radius"
-field true -minValue 0 -maxValue 1 -value 1 pillRadius;
showWindow pillWindow;

We can repeat this now for a slider that will specify the pill's length. Note that by not specifying the maxValue the slider can reach values up to 100.

if (`window -exists pillWindow`)
deleteUI pillWindow;
window -w 400 -h 200 -title "NURBS Pill Options" pillWindow;
columnLayout;

floatSliderGrp -label "Radius "
-field true -minValue 0 -maxValue 1 -value 1 pillRadius;
floatSliderGrp -label "Length" -field true -minValue 0 -value 1 pillLength;

showWindow pillWindow;

Finally we need some buttons to control the creation of our pill. Before we create our button, lets add some more formatting. We will use a rowLayout command now with 5 columns and a width of 500. In each column of the row we will create a columnLayout that spans the buttons over the column, creates a spacer of 10 pixels between the sliders and the buttons, a 5 pixel spacer between each button

if (`window -exists pillWindow`)
deleteUI pillWindow;
window -w 500 -h 200 -title "NURBS Pill Options" pillWindow;
columnLayout ;

floatSliderGrp -label "Radius "
-field true -minValue 0 -maxValue 1 -value 1 pillRadius;
floatSliderGrp -label "Length" -field true -minValue 0 -value 1 pillLength;
rowLayout -numberOfColumns 5 -width 500 MainRow;
columnLayout -columnAttach "both" 5 -rowSpacing 10 -parent MainRow Column1; // A Spacer
columnLayout -columnAttach "both" 5 -rowSpacing 10 -parent MainRow Column2;
button;
columnLayout -columnAttach "both" 5 -rowSpacing 10 -parent MainRow Column3;
button;
columnLayout -columnAttach "both" 5 -rowSpacing 10 -parent MainRow Column4;

button
;

columnLayout -columnAttach "both" 5 -rowSpacing 10 -parent MainRow Column5; // A Spacer
showWindow pillWindow;

Now we want to give each of the buttons a function. The first will call our initial pill creation script, the second will reset the Radius and Length to 1 and the last one will close the window. The functions of the buttons are carried out by assigning a "command" flag to the button.

To close the window, we can assign a deleteUI command to the close button

button -label "Close" -command "deleteUI pillWindow";

To reset the sliders we will have to set the floatSliderGrp value flags both to 1.

button -label "Reset" -command "floatSliderGrp -e -value 1 pillLength; floatSliderGrp -e -value 1 pillRadius";

And finally we need to call our create pill procedure when we click the "create" button.

button -label "Create" -command "createPill";

With the createPill procedure being

proc createPill()
{
float $Rad = `floatSliderGrp -q -value pillRadius`; // query the slider as to the current radius
float $Len = `floatSliderGrp -q -value pillLength`; // query the slider as to the current length
print("create a pill of radius "+$Rad+" and length "+$Len);
// Insert the rest of the Pill code here...
}

The entire code now becomes thus

if (`window -exists pillWindow`)
deleteUI pillWindow;
window -w 500 -h 200 -title "NURBS Pill Options" pillWindow;
columnLayout ;
floatSliderGrp -label "Radius " -field true -minValue 0 -maxValue 1 -value 1 pillRadius;
floatSliderGrp -label "Length" -field true -minValue 0 -value 1 pillLength;
rowLayout -numberOfColumns 5 -width 500 MainRow;
columnLayout -columnAttach "both" 5 -rowSpacing 10 -parent MainRow Column1; // A Spacer
columnLayout -columnAttach "both" 5 -rowSpacing 10 -parent MainRow Column2;
button -label "Create" -command "createPill";
columnLayout -columnAttach "both" 5 -rowSpacing 10 -parent MainRow Column3;
button -label "Reset" -command "
floatSliderGrp -e -value 1 pillLength; floatSliderGrp -e -value 1 pillRadius"; // Reset
columnLayout -columnAttach "both" 5 -rowSpacing 10 -parent MainRow Column4;
button -label "Close" -command "deleteUI pillWindow"
; // Close the dialog
columnLayout -columnAttach "both" 5 -rowSpacing 10 -parent MainRow Column5; // A Spacer
showWindow pillWindow;

proc createPill()
{
float $Rad = `floatSliderGrp -q -value pillRadius`;
float $Len = `floatSliderGrp -q -value pillLength`;
print("create a pill of radius "+$Rad+" and length "+$Len);
// Insert the rest of the Pill code here...
}

All we have to do now is to modify our script into a procedure that has both the radius and length as parameters. Radius is simple, we just substitute this value into the sphere command. The length on the other hand needs a bit of thought. When length = 1, we have a special case, ie, a sphere. In this case the translations of the hemispheres will be 0. For all other cases, the length will be divided by 2 and added/subtracted from the upper and lower hemispheres respectively. So the operation would be to first subtract 1 from the height, and use half of the remainder to add/subtract respectively. This raises an exception for the sliders. We must therefore force a minimum length of 1 not 0 as before.

sphere -p 0 0 0 -ax 0 1 0 -r $Rad -n tmpSphere;
detachSurface -ch 1 -rpo 1 -n detSphere tmpSphere.u[2];
setAttr "detSphere.translateY" ($Len-1)/2;
setAttr "tmpSphere.translateY" -($Len-1)/2;
delete -ch tmpSphere detSphere;

select -r detSphere.u[2] ;
select -tgl tmpSphere.u[2] ;
attachWithoutMoving;
xform -cp tmpSphere;
makeIdentity -apply true -t 1 -r 1 -s 1 tmpSphere;
rename "tmpSphere" "nurbsPill1";
delete detSphere;

So now our final code will be thus

=============================================================================================

if (`window -exists pillWindow`)
deleteUI pillWindow;

window -w 500 -h 200 -title "NURBS Pill Options" pillWindow;
columnLayout ;
floatSliderGrp -label "Radius " -field true -minValue 0 -maxValue 1 -value 1 pillRadius;
floatSliderGrp -label "Length" -field true -minValue 0 -value 1 pillLength;
rowLayout -numberOfColumns 5 -width 500 MainRow;
columnLayout -columnAttach "both" 5 -rowSpacing 10 -parent MainRow Column1; // A Spacer
columnLayout -columnAttach "both" 5 -rowSpacing 10 -parent MainRow Column2;
button -label "Create" -command "createPill";
columnLayout -columnAttach "both" 5 -rowSpacing 10 -parent MainRow Column3;
button -label "Reset" -command "
floatSliderGrp -e -value 1 pillLength; floatSliderGrp -e -value 1 pillRadius"; // Reset
columnLayout -columnAttach "both" 5 -rowSpacing 10 -parent MainRow Column4;
button -label "Close" -command "deleteUI pillWindow"
; // Close the dialog
columnLayout -columnAttach "both" 5 -rowSpacing 10 -parent MainRow Column5; // A Spacer

showWindow pillWindow;

proc createPill()
{
float $Rad = `floatSliderGrp -q -value pillRadius`;
float $Len = `floatSliderGrp -q -value pillLength`;
sphere -p 0 0 0 -ax 0 1 0 -r $Rad -n tmpSphere;
detachSurface -ch 1 -rpo 1 -n detSphere tmpSphere.u[2];
setAttr "detSphere.translateY" (($Len-1)/2);
setAttr "tmpSphere.translateY" (-($Len-1)/2);
delete -ch tmpSphere detSphere;
select -r detSphere.u[2] ;
select -tgl tmpSphere.u[2] ;
attachWithoutMoving;
xform -cp tmpSphere;
makeIdentity -apply true -t 1 -r 1 -s 1 tmpSphere;
rename "tmpSphere" "nurbsPill1";
delete detSphere;

}

=============================================================================================

A simple application of how we can create a custom MEL command interface.