# This is an example mel template for use with mkScript.pl.
#
# The line "ext:" is used to set the file extension.
# The line "comment:" is used to set the comment character.
ext: "mel"
comment: "//"
<LICENSE>
//--------------------------------------------------------------------------//
//  <SCRIPT>
//
//  Author:			<NAME>
//					<EMAIL>
//
//  Version:		0.00.001
//  Date:			<DATE>
//
//  Description:	...
//
//  Usage:			Type "<PROC>;" in the command line,
//					or create a shelf button with this command.
//
//  Return:			none
//
//  Files Needed:	none
//
//--------------------------------------------------------------------------//


//////////////////////////////////////////////////////////////////////////////
//                                                                          //
//                                  README                                  //
//                                                                          //
//  This is an automatically created MEL script which establishes the       //
//  structure that I use for bigger UI projects.                            //
//                                                                          //
//  It is divided into eight major parts:                                   //
//                                                                          //
//    PART 1: Sourcing of external scripts/libraries.                       //
//    PART 2: Simulated local constant variables.                           //
//    PART 3: Procs that operate in the Maya scene and do the work.         //
//    PART 4: UI operations (retrieving and setting values, etc.).          //
//    PART 5: UI creation and updating.                                     //
//    PART 6: Call procedures that collect UI information (partly using     //
//            PART 4 procs) and run the procs of PART 3 to perform their    //
//            task(s).                                                      //
//    PART 7: (optional) Command line interface for using this script       //
//                       within other scripts or in batch mode.             //
//    PART 8: Global procedures (including the callback manager).           //
//                                                                          //
//                                                                          //
//    To develop a new script, I take notes of what the script should be    //
//  doing, how it could do certain tasks and how exactly (this is often     //
//  underestimated) the user should be communicating with this script.      //
//  This last section provides detailed information of how the UI should    //
//  be designed and how it should react to allow for the utmost             //
//  flexibility and speed. The first thing that is scripted is the UI.      //
//  Then the functionality is added, bit by bit, until the main purpose is  //
//  achievable. Following is a second pass of thinking about the            //
//  interface. At this stage, major changes to the core of the script are   //
//  easy to incorporate. The last steps include the addition of the final   //
//  features to manage the system (if any) that is created with this        //
//  script and the invention of new features that speed up the workflow.    //
//    In more recent scripts, I have started writing down comments for      //
//  nearly every little bit of code that is written. This had the           //
//  surprising side effect that the whole code became more transparent and  //
//  bugs could not last very long (hopefully :). Also, the development      //
//  became much faster.                                                     //
//    "DPK_attrCombinationSystemUI.mel" is one of those newer ones.         //
//                                                                          //
//                                                                          //
//    As you will see, I have a naming convention for local procs. They     //
//  all use the pattern DPK_L_<procName>. So in this case it is             //
//  DPK_L_buildUI and DPK_L_apply.                                          //
//    This is done so that they don't collide with any other commands       //
//  outside this script. It wouldn't be a problem for the outside scripts   //
//  themselves but they couldn't be used here anymore. Having two local     //
//  procedures in two different scripts is no problem at all. They are      //
//  only visible inside their own script file (and only AFTER their         //
//  declaration!).                                                          //
//    You should find your own naming style and edit the melUI_template     //
//  file that came with the mkScript.pl perl script.                        //
//                                                                          //
//                                                                          //
//    Some parts of this script (or even whole procedures) are going to be  //
//  modified or deleted when starting to write the actual code. They are    //
//  just here to demonstrate how the seven parts work together.             //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////


//------------------------------
//------------------------------
//
//  PART 1:
//
//  Source the scripts which contain necessary procedures.
//
//------------------------------
//------------------------------


//------------------------------
//------------------------------
//
//  PART 2:
//
//  Define some local "dummy" procedures which just return a simple value.
//  They can be used as constant variables which are global to this script.
//
//------------------------------
//------------------------------

//------------------------------
// Returns the current version.
// Please synchronize with the version above.
//------------------------------
proc string DPK_L_version      () { return "0.00.001"; }


//------------------------------
// Set this variable to false for release.
// If we're developing, we want to delete any stored prefs about our windows.
// Default: false
//------------------------------
proc int    DPK_L_isDeveloping () { return true; }


//------------------------------
// The window's name is used in several procs, so we want one place to set it
// and get it from.
// Default: DPK_attrCombinationSystemUI_win
//------------------------------
proc string DPK_L_windowName   () {
	return "<PROC>_win";
}


//------------------------------
//------------------------------
//
//  PART 3:
//
//  These are the local procedures which do the actual work. They don't deal
//  with UI stuff but work in the actual Maya scene. They're approximately in
//  the order from general tasks (or tasks that are used in many other procs)
//  to very specific tasks.
//
//------------------------------
//------------------------------

//------------------------------
// Use this error proc to issue warnings and errors while informing the user
// in which script the error occured.
//
// $msg is the actual text message that is printed.
//
// $level defines the way the message is printed.
//   $level == 0
//		The message is just printed.
//   $level == 1
//		The message printed as a warning.
//   $level == 2
//		The message is printed as an error.
//   $level == 3
//		A confirm dialog is created with the message.
//------------------------------
proc DPK_L_error (string $msg, int $level)
//------------------------------
{
//--//
string $win = `DPK_L_windowName`;

// Add the script's name in front of the message.
string $procMsg = ("["+$win+"] "+$msg);

switch ($level)
{
	case 1:
		// Issue a warning.
		warning $procMsg;
		break;
	case 2:
		// Error out.
		error $procMsg;
		break;
	case 3:
		// Create a confirmDialog and show the message without the script's
		// name.
		confirmDialog
			-title   $win
			-message $msg
			-button  "Close"
			-db      "Close";
		break;
	default:
		// If $level is neither of the above values, just print the message.
		print ("// "+$procMsg+"\n");
		break;
}
//--//
}
//---- end "DPK_L_error" ----//


//------------------------------
// Creates a nurbs sphere with the given $name. The simple operation of
// creating a nurbs sphere doesn't require this complicated process, of
// course, but it is used here to demonstrate how the seven parts work
// together.
//------------------------------
proc string DPK_L_create (string $name)
//------------------------------
{
//--//
string $nodes[] = `sphere -name $name -ax 0 1 0`;
return $nodes[0];
//--//
}
//---- end "DPK_L_create" ----//


//------------------------------
//------------------------------
//
//  PART 4:
//
//  These are the procedures that operate in the UI. They set and retrieve
//  values, select items, etc.. They may be called directly by the global
//  callback procedure at the end of this script or by other procs that
//  collect information from the UI to perform their task.
//
//------------------------------
//------------------------------

//------------------------------
// This proc returns the text that was entered into the text field.
//------------------------------
proc string DPK_L_getText ()
//------------------------------
{
//--//
// Get the UI elements.
string $win  = `DPK_L_windowName`;
string $TFBG = ($win+"_TFBG");

// Retrieve and return the entered text.
string $text = `textFieldButtonGrp -query -text $TFBG`;

return $text;
//--//
}
//---- end "DPK_L_getText" ----//


//------------------------------
// This proc sets the text of the TFBG to the given $text.
//------------------------------
proc DPK_L_setText (string $text)
//------------------------------
{
//--//
// Get the UI elements.
string $win  = `DPK_L_windowName`;
string $TFBG = ($win+"_TFBG");

// Set the text.
textFieldButtonGrp -edit -text $text $TFBG;
//--//
}
//---- end "DPK_L_setText" ----//


//------------------------------
//------------------------------
//
//  PART 5:
//
//  These are the local procs directly related to the UI.
//  They will build and update it etc..
//
//------------------------------
//------------------------------

//------------------------------
proc DPK_L_buildPopup_TFBG ()
//------------------------------
{
//--//
// Delete all menu itmes of the popup menu.
string $win   = `DPK_L_windowName`;
string $popup = ($win+"_TFBG_PM");
popupMenu -e -dai $popup;

// Collect some data that is used to determine whether the menu items should
// be enabled or disabled.
int $isText = size(`textFieldButtonGrp -query -text ($win+"_TFBG")`);

// Make the popup the current parent for the next menuItems.
setParent -menu $popup;

// Create the menu items.
menuItem -label "Create"
		//-ann ""
		-enable $isText
		-c "<PROC>_call {\"create\"}";
menuItem -label "Apply"
		//-ann ""
		-c "<PROC>_call {\"apply\"}";
//--//
}
//---- end "DPK_L_buildPopup_TFBG" ----//


//------------------------------
// This proc is called whenever a menu is about to be shown. It
// enables/disables the individual menuItems based on some information about
// the state of the UI.
//------------------------------
proc DPK_L_enableMenu (string $which)
//------------------------------
{
//--//
string $win = `DPK_L_windowName`;

// Get the name of the menu using the naming convention mentioned below.
string $menu = ($win+"_"+$which+"_menu");

// Make the menu the parent for the next operations.
setParent -menu $menu;

// Collect some data that is used to determine whether the menu items should
// be enabled or disabled.
int $isText = size(`textFieldButtonGrp -query -text ($win+"_TFBG")`);

// Depending on the menu that is specified in the $which variable,
// enable/disable the menuItems.
switch ($which)
{
	case "file":
		menuItem -edit -enable $isText ($win+"_createMI");
		menuItem -edit -enable 1       ($win+"_applyMI");
		menuItem -edit -enable 1       ($win+"_closeMI");
		break;
}
//--//
}
//---- end "DPK_L_enableMenu" ----//


//------------------------------
// This procedure creates the menu items of the main menu.
//------------------------------
proc DPK_L_mainMenu ()
//------------------------------
{
//--//
string $win = `DPK_L_windowName`;

// Delete all existing menus from this window.
string $menus[] = `window -query -menuArray $win`;
string $menu;
for ($menu in $menus)
	deleteUI -menu ($win+"|"+$menu);

// Make the window the parent for the next menus.
setParent $win;

// Add the "File" menu. Whenever it is about to be shown, it calls a procedure
// that checks whether the menuItems should be enabled or disabled. There is a
// naming convention that the argument for this call is part of the name of
// the menu so that each menu is called ($win+"_"+$name+"_menu") where $name
// is the name of the menu (in this case "file").
menu -label "File" -tearOff 0
	-pmc "<PROC>_call {\"enableMenu\", \"file\"}"
	($win+"_file_menu");

	// Create the menuItems for the "File" menu.
	menuItem -label "Create"
			//-ann ""
			-c "<PROC>_call {\"create\"}"
			($win+"_createMI");
	menuItem -label "Apply"
			//-ann ""
			-c "<PROC>_call {\"apply\"}"
			($win+"_applyMI");
	menuItem -divider 1;
	menuItem -label "Close"
			//-ann ""
			-c ("deleteUI -wnd \""+$win+"\";")
			($win+"_closeMI");
//--//
}
//---- end "DPK_L_mainMenu" ----//


//------------------------------
proc string DPK_L_buildUI ()
//------------------------------
{
//--//
// First we get the window's name.
string $win = `DPK_L_windowName`;

// We shall delete it if it exists.
if (`window -ex $win`)
    deleteUI -wnd $win;

// If we're developing, we want to delete any stored prefs about our window.
if (`DPK_L_isDeveloping` && `windowPref -exists $win`)
	windowPref -remove $win;

// Now we can create the window.
string $ver = `DPK_L_version`;
$win = `window
			-t ("<PROC>    v"+$ver)
			-wh  300 140
			-tlc 150 500
			-menuBar 1
			$win`;

// Add the layouts.
string $mainFL = `formLayout -nd 100 ($win+"_mainFL")`;

// Add the UI controls.
setParent $mainFL;
string $closeB = `button -l "Close" ($win+"_closeB")`;
string $applyB = `button -l "Apply" ($win+"_applyB")`;
string $sep1   = `separator ($win+"_sep1")`;
string $TX     = `text -l "Enter a name and press \"Create\"."`;
string $TFBG   = `textFieldButtonGrp
						-cw  1 50
						-cw  3 50
						-adj 2
						-label       "Name:"
						-buttonLabel "Create"
						($win+"_TFBG")`;

// Create the main menu.
DPK_L_mainMenu;

// Create the popup menus.
popupMenu -p $TFBG
	-b   3
	-aob 0
	-pmc "<PROC>_call {\"buildPopup_TFBG\"}"
	($win+"_TFBG_PM");

// Setup callbacks.
button -e -c ("deleteUI -wnd "+$win) $closeB;
button -e
	-c  "<PROC>_call {\"apply\"}"
	$applyB;
textFieldButtonGrp -e
	-bc "<PROC>_call {\"create\"}"
	$TFBG;

// Do the layout.
formLayout -e
    -aof	$closeB		"top"		-25
    -af		$closeB		"bottom"    2
    -aof	$closeB		"left"		-80
    -af		$closeB		"right"		2

    -aof	$applyB		"top"		-25
    -af		$applyB		"bottom"    2
    -af		$applyB		"left"		2
    -aof	$applyB		"right"		-80

    -af		$sep1		"bottom"    27
    -af		$sep1		"left"		0
    -af		$sep1		"right"		0

	-af		$TX			"top"		5
	-af		$TX			"left"		5

	-af		$TFBG		"top"		30
	-af		$TFBG		"left"		5
	-af		$TFBG		"right"		5
$mainFL;

return $win;
//--//
}
//---- end "DPK_L_buildUI" ----//


//------------------------------
//------------------------------
//
//  PART 6:
//
//  These are the procedures that are indirectly called by the UI controls
//  through the global callback procedure at the end of this script. They
//  retrieve UI information and call the procedures which perform the actual
//  task within the Maya scene.
//
//------------------------------
//------------------------------

//------------------------------
proc DPK_L_apply ()
//------------------------------
{
//--//
// This is just a dummy code used to demonstrate that the "Apply" button
// actually works.
DPK_L_error "The \"Apply\" button works!" 3;
//--//
}
//---- end "DPK_L_apply" ----//


//------------------------------
// This procedure retrieves the entered text and creates a sphere.
//------------------------------
proc DPK_L_create_call ()
//------------------------------
{
//--//
// Get the entered name.
string $name = `DPK_L_getText`;

// If no text was entered, display a message and a warning.
if (!size($name)) {
	DPK_L_error "No text entered." 1;
	DPK_L_error "No text entered." 3;
	return;
}

// Create the sphere and retrieve the name.
string $sphere = `DPK_L_create $name`;

// Put the name into the TFBG. This is done in case the entered text had some
// invalid characters such as ",".
DPK_L_setText $sphere;
//--//
}
//---- end "DPK_L_create_call" ----//


//------------------------------
//------------------------------
//
//  PART 7: (optional)
//
//  This part contains global procedures which present an alternate interface
//  to the functionality of this script. They don't use any UI but directly
//  perform their task. These can be called from within other scripts or in
//  batch mode.
//
//------------------------------
//------------------------------

////////////////////////////////
// This proc does the same as the DPK_L_create_call but without the interface.
////////////////////////////////
global proc string <PROC>_create (string $name)
////////////////////////////////
{
//--//
// Create the sphere and retrieve the name.
string $sphere = `DPK_L_create $name`;

// We can't do any UI stuff in this proc since it may be called in batch mode.
// Instead, we just print a message that the sphere has been created.
print ("// Sphere created: "+$sphere+"\n");

return $sphere;
//--//
}
//---- end "<PROC>_create" ----//


//------------------------------
//------------------------------
//
//  PART 8:
//
//  And here are the two most important global procs.
//
//------------------------------
//------------------------------

////////////////////////////////
// This is the "callback" procedure.
//
// It is called by the UI controls with one string array. The first element
// defines the task that should be performed. The other elements are optional
// and can be used as arguments to the called procs.
//
// This construct helps to minimize the use of global procs when you have many
// buttons...
////////////////////////////////
global proc <PROC>_call (string $args[])
////////////////////////////////
{
//--//
// The first element of the $args array defines the task. We use a "switch"
// construct here because there may be many different tasks.
switch ($args[0])
{
	// The apply call doesn't really do anything.
    case "apply":
		DPK_L_apply;
		break;

	// This will create a sphere with the entered name.
    case "create":
		DPK_L_create_call;
		break;

	// These calls are used to manage the UI state. The first (enableMenu) is
	// called whenever a menu is about to be shown. It collects information
	// and enables/disables the menu items.
	case "enableMenu":
		DPK_L_enableMenu $args[1];
		break;

	// This is called whenever the popup menu is about to be shown. It
	// collects and updates all its menu items.
	case "buildPopup_TFBG":
		DPK_L_buildPopup_TFBG;
		break;

	// Issue a warning if the call wasn't implemented.
	default:
		DPK_L_error ("Not yet implemented: "+$args[0]) 1;
		break;
}
//--//
}
//---- end "<PROC>_call" ----//


////////////////////////////////
//------------------------------
// This is the main procedure. It really doesn't do more than calling the proc
// that creates the UI and showing the resulting window.
//------------------------------
////////////////////////////////
global proc <PROC> ()
////////////////////////////////
{
//--//
// Build and show the UI.
string $win = `DPK_L_buildUI`;
showWindow $win;
//--//
}
//---- end "<PROC>" ----//
