Mel

UI Introduction


main index



Introduction

Implementing a graphical user interface (GUI or UI for short) that meets professional standards, even for an apparently trivial task such as the one presented in this tutorial, requires a great deal of coding effort and familiarity not only with Mel but also with the practice of interface design. For a very good "walk-through" of the process of implementing a professional UI it is hightly recommended the reader refers to,

Profession MEL Solutions for Production
    by Kevin Mannens & Ed Caspersen
    WordWare Applications Library
    ISBN-13:978-1-59822-066-7
    ISBN-10:1-59822-066-7

In broad terms, a UI is implemented either for personal use or so that a tool can be used by other artists. In the former case, idiosyncratic or even quirky appearance/behaviour of the UI can be tolerated. The scripts shown in listings 1 and 2 fit that category. However, UI's intended for use by other artists require implementation to much higher standards of usability.


Grid Model

Listings 1 and 2 (partially) implement a simple tool, figure 1, for creating a trivial 2D grid of spheres - figure 2.



Figure 1



Figure 2

The funcionality that would enable the "Row" and "Columns" sliders to interactively modify a grid has not been implemented. The other sliders do allow a grid to interactively modified.


Listing 1 (GridModelUI.mel)


//GridModelUI.mel
  
global string $wn;
global string $xSldr;
global string $ySldr;
global string $zSldr;
global string $sphSldr;
global string $rowSldr;
global string $colSldr;
  
//--------------------------------------------------------
// Main proc for creating the UI
//--------------------------------------------------------
global proc GridModelUI()
{
global string $wn;
global string $xSldr;
global string $ySldr;
global string $sphSldr;
global string $rowSldr;
global string $colSldr;
  
// Avoid duplicate windows
if(`window -exists $wn`)
    deleteUI $wn;
  
// Our main window
$wn = `window -w 400 -h 250 -title "my window"`;
columnLayout;
  
$rowSldr = `intSliderGrp    -min 1 -max 15 -value 5 -field true
                            -cw 1 100 -label "Rows"`;
  
$colSldr = `intSliderGrp    -min 1 -max 15 -value 5 -field true
                            -cw 1 100 -label "Columns"`;
  
$sphSldr = `floatSliderGrp  -changeCommand changeRadius
                            -dragCommand "dragRadius $sphSldr radius"
                            -min 0.1 -max 2 -value 0.5 -field true
                            -cw 1 100 -label "Sphere Radius"`;
  
$xSldr = `floatSliderGrp    -dragCommand "dragSpacing"
                            -min 0.1 -max 10 -value 1 -field true
                            -cw 1 100 -label "X Spacing"`;
  
$ySldr = `floatSliderGrp    -dragCommand "dragSpacing"
                            -min 0.1 -max 10 -value 1 -field true
                            -cw 1 100 -label "Y Spacing"`;
                            
$form = `formLayout`;                            
$but1 = `button  -label "Make Grid" -command "makeGridModel"`;
$but2 = `button  -label "Restore Default Spacing" 
                 -command "restoreDefaultSpacing"`;
formLayout -edit
    -attachForm $but1 "top" 10    // top margin
    -attachForm $but2 "top" 10    // top margin
    -attachForm $but1 "left" 50 // left margin
    -attachControl $but2 "left" 10 $but1 // 10 pixels between buttons
    $form;
showWindow $wn;
}
  
GridModelUI();
  
//--------------------------------------------------------
// Queries the UI elements and uses their values to create
// the geometry for the model
//--------------------------------------------------------
global proc makeGridModel()
{
global string $rowSldr, $colSldr, $sphSldr;
global string $xSldr, $ySldr;
global string $groupName;
  
int $rows = `intSliderGrp -q -v $rowSldr`;
int $cols = `intSliderGrp -q -v $colSldr`;
float $xSpace = `floatSliderGrp -q -v $xSldr`;
float $ySpace = `floatSliderGrp -q -v $ySldr`;
float $rad = `floatSliderGrp -q -v $sphSldr`;
  
GridModel($rows, $cols, $xSpace, $ySpace, $rad);
}
  
//--------------------------------------------------------
// Sets the spacing sliders and applies the results to the
// model.
//--------------------------------------------------------
global proc restoreDefaultSpacing() 
{ 
global string $xSldr, $ySldr;
  
floatSliderGrp -edit -value 1.0 $xSldr;
floatSliderGrp -edit -value 1.0 $ySldr;
applySpacing(1,1);
}
  
//--------------------------------------------------------
// 
//--------------------------------------------------------
global proc dragSpacing()
{
global string $xSldr, $ySldr;
  
float $xSpace = `floatSliderGrp -q -v $xSldr`;
float $ySpace = `floatSliderGrp -q -v $ySldr`;
applySpacing($xSpace, $ySpace);
}
  
//--------------------------------------------------------
// Does nothing if the $master refers to a non-exising node.
//--------------------------------------------------------
global proc dragRadius(string $slider,string $attr) 
{
global string $master[];
global string $groupName;
global string $input;
  
if(size($master) == 0 || nodeExists($master[0]) == 0)
    return;
applySubdivisions(4,4);
float $rad = `floatSliderGrp -q -v $slider`;
setAttr ($input + "." + $attr) $rad;
}
  
global proc changeRadius()
{
applySubdivisions(-1,-1);
}


Listing L (GridModel.mel)


 //GridModel.mel
  
global string  $master[];    // instances refer to this sphere
global string  $input;        // reference to the inputs
global string  $groupName;    // group = master + instances
global int     $numRows, 
               $numCols,
               $divAxis,
               $divHeight;
//--------------------------------------------------------
// To prevent the accumulation of "orphan" groups any
// empty instances of "GMGroup" are deleted from the scene.
//--------------------------------------------------------
global proc GridModel(int $rows, int $cols,
                    float $xSpace, float $ySpace, float $sphRad)
{
global string $groupName;
global string $master[];
global string $input;
global int    $numRows, $numCols, $divAxis, $divHeight;
  
deleteEmptyGMGroups();
$divAxis = 8;
$divHeight = 8;
  
// Create the master sphere
$master = `polySphere -r $sphRad -sh $divHeight -sa $divAxis`; 
$input = getShapeInput($master[0]);
$numRows = $rows;
$numCols = $cols;
  
string  $items[], $inst[];
int     $n = 0, $x, $y;
for($x = 0; $x < $cols; $x++) {
    for($y = 0; $y < $rows; $y++) {
        $inst = `instance`;
        $items[$n] = $inst[0];
        move ($xSpace * $x) ($ySpace * $y) 0;
        $n++;
        }
    }
// Ensure the first item in the group is the master sphere.
$groupName = `group -n "GMGroup" $master $items`;
setAttr ($master[0] + ".visibility") 0;
}
  
//--------------------------------------------------------
// Applies XY spacing to all members of the current group.
//--------------------------------------------------------
global proc applySpacing(float $xSpace, float $ySpace)
{
global string $groupName;
global int       $numRows, $numCols;
  
if(nodeExists($groupName) == 0) {
    print("A new Grid must be made.\n");
    return;
    }
string  $items[] = `listRelatives -c $groupName`;
if(size($items) > 0)
    select $groupName;
int     $n = 1, $x, $y;
for($x = 0; $x < $numCols; $x++) {
    for($y = 0; $y < $numRows; $y++) {
        move ($xSpace * $x) ($ySpace * $y) 0 $items[$n];
        $n++;
        }
    }
}
  
//--------------------------------------------------------
// 
//--------------------------------------------------------
global proc applySubdivisions(int $sa, int $sh)
{
global int    $divAxis, $divHeight;
global string $input;
  
if($sa == -1 || $sh == -1) {
    $sa = $divAxis;
    $sh = $divHeight;
    }
setAttr ($input + ".sa") $sa;
setAttr ($input + ".sh") $sh;
}
  
//--------------------------------------------------------
// Receives the name of the transform node. For example,
// given "pSphere1" will return "polySphere1".
//--------------------------------------------------------
global proc string getShapeInput(string $tnode)
{
// get the shape node
string $shp[] = `listRelatives -shapes $tnode`;
string $cons[] = `listConnections $shp[0]`;
if(size($cons) == 0)
    return "";
int $lastIndex = size($cons) - 1;
return $cons[$lastIndex];
}
  
//--------------------------------------------------------
// Utility to remove empty (orphan) groups
//--------------------------------------------------------
global proc deleteEmptyGMGroups()
{
string $GMGroups[] = `ls "GMGroup*"`;
  
for($n = 0; $n < size($GMGroups); $n++) {
    string     $gmGroup = $GMGroups[$n];
    string     $items[] = `listRelatives -c $gmGroup`;
    if(size($items) == 0 || size($items) == 1) {
        print("Deleting empty group: " + $gmGroup + "\n");
        delete $gmGroup;
        }
    }
}
  
//--------------------------------------------------------
// Simple check to see if an "object" is in the scene.
//--------------------------------------------------------
global proc int nodeExists(string $name)
{
string $item[] = `ls $name`;
if(size($item) == 0)
    return 0;
else
    return 1;
}

© 2002- Malcolm Kesson. All rights reserved.