MEL How-To #107

Back · Previous · Next Maya

How do I use '-dragCallback' and '-dropCallback'?

MEL's drag'n'drop functionality threw me for a loop for the longest time. I was never able to successfully implement drag'n'drop callbacks in any of my UI's until Maya v3, when an Alias rep casually alluded to an obscure requirement on the Highend3D Maya Mailing list. Unfortunately this requisite had not been clearly described in Maya's documentation.

There are several key things you need to keep in mind regarding MEL's drag'n'drop functionality:

  • MEL will register drop events only from other MEL controls which have been assigned a drag event. Assigning a '-dragCallback' to a control does not mean that it will interact with every other control automatically.

  • The drop callback will not trigger if the message array from the drag callback is empty! You must assign at least one item to the message array - even if it's an empty string. (This is the tip that finally got my drag'n'drop working.)

    For example:

    // A non-functional drag callback.
    //
    global proc string[] dragCallback( string $drag, 
                                       int $x, int $y, int $mods )
    {
      string $msgs[];
      return $msgs;
    }
    

    The above drag message will not trigger a drop! Use (at least):

    // A drag callback that works.
    //
    global proc string[] dragCallback( string $drag, 
                                     int $x, int $y, int $mods )
    {
      string $msgs[] = { "" };
      return $msgs;
    }
    

    I suppose one could argue that this is a documented behavior, as the description for the callback flags states:

    "By convention the first string in the array describes the user settable message type."
  • Several controls do not support a user-customizable drag'n'drop.

    Maya's native panels - such as the Outliner or its modelPanels - cannot be assigned drag events which will propogate to your own controls. For example, even though Maya provides a "drop cursor" when you attempt a drag from the Outliner to a MEL window, the drop callback is never invoked. A MEL UI element will only acknowledge a dropCallback from another MEL UI element that has initiated a dragCallback.

    You cannot successfully capture a drop callback directly upon a textField; the textField always offers a "Do not enter" cursor when you attempt a drop. A workaround is to use a textFieldGrp instead, and drop on its label.

    The "trash" control in Maya's shelfTabLayout is handled internally by the layout and not via a MEL callback. In other words, there's no way to assign a specific command to the trashcan or intercept its operation.

    The shelfLayout implements its own drag and drop functionality for managing shelfButtons; as a consequence, it is not possible to use the MEL '-dragCallback' nor '-dropCallback' on shelf layouts or shelf buttons.

    In general, controls such as shelfLayouts, shelfButtons, tabLayouts, textFields and scrollFields cannot react to custom drag callbacks assigned to controls as they have their own inherent drag and drop behaviors.

Below is a sample script with demonstrates the use of drag and drop callbacks, and shows some of the limitations inherent to the system:

global proc dragDropHowTo()
{
    string $windowUI = "dragDropHowToUI";

    if ( `window -exists $windowUI` )
    deleteUI -window $windowUI;

    window -title "MEL How-To #107" -iconName "How-To #107" 
           -wh 540 280 $windowUI;
    string $form = `formLayout`;

        string $buttonLeftUI = `button leftButtonUI`;
        string $buttonRightUI = `button rightButtonUI`;

        string $shelfUI = `shelfLayout shelfUI`;

            string $sphereUI = `shelfButton
                -enableCommandRepeat 1
                -enable 1
                -width 34
                -height 34
                -manage 1
                -visible 1
                -label "Polygon Sphere" 
                -image1 "polySphere.xpm" 
                -style "iconOnly" 
                -command ( "polySphere -r 1 -sx 16 -sy 8 -ax 0 1 0 " +
                                      "-tx 1 -ch 1;\n" )
                    sphereUI`;

            string $cubeUI = `shelfButton
                -enableCommandRepeat 1
                -enable 1
                -width 34
                -height 34
                -manage 1
                -visible 1
                -label "Polygon Cube" 
                -image1 "polyCube.xpm" 
                -style "iconOnly" 
                -command ( "polyCube -w 1 -h 1 -d 1 -sx 1 -sy 1 -sz 1 " +
                                    "-ax 0 1 0 -tx 1 -ch 1;\n" )
                    cubeUI`;

            setParent ..;

        string $tslUI = `textScrollList -height 64 tslUI`;

        string $scrollUI = `scrollField scrollUI`;

        setParent ..;

    setParent ..;

    formLayout -e

        -af $buttonLeftUI       "top"       2
        -af $buttonLeftUI       "left"      2
        -ap $buttonLeftUI       "right"     2   50

        -af $buttonRightUI      "top"       2
        -ap $buttonRightUI      "left"      2   50
        -af $buttonRightUI      "right"     2

        -ac $shelfUI            "top"       2   $buttonLeftUI
        -af $shelfUI            "left"      2
        -af $shelfUI            "right"     2

        -ac $tslUI              "top"       2   $shelfUI
        -af $tslUI              "left"      2
        -af $tslUI              "right"     2

        -ac $scrollUI           "top"       2   $tslUI
        -af $scrollUI           "left"      2
        -af $scrollUI           "right"     2
        -af $scrollUI           "bottom"    2

            $form;

    showWindow;  

    button -e
        -dragCallback howToDragCB
        -dropCallback howToDropCB
            $buttonLeftUI;

    button -e
        -dragCallback howToDragCB
        -dropCallback howToDropCB
            $buttonRightUI;

    // The shelfLayout does not send nor accept drag/drop callbacks.
    //
    shelfLayout -e
        -dragCallback howToDragCB
        -dropCallback howToDropCB
            $shelfUI;

    // The shelfButton does not send nor accept drag/drop callbacks.
    //
    shelfButton -e
        -dragCallback howToDragCB
        -dropCallback howToDropCB
            $sphereUI;

    // The shelfButton does not send nor accept drag/drop callbacks.
    //
    shelfButton -e
        -dragCallback howToDragCB
        -dropCallback howToDropCB
            $cubeUI;

    // The scrollField does not send nor accept drag/drop callbacks.
    //
    scrollField -e
        -text ( "Drop shelf buttons on this scrollField to paste text;\n" +
                "This is not an effect of the '-dropCallback', but a native\n" +
                "behavior of the shelfButton and scrollField controls.\n" +
                "The button drag callbacks won't trigger a drop here.\n" )
        -dragCallback howToDragCB
        -dropCallback howToDropCB
            $scrollUI;

    // The textScrollList will send and accept drag/drop callbacks.
    //
    textScrollList -e
        -append ( "You may drag the button controls to this textScrollList, " + 
                  "but the shelfButtons will do naught." )
        -dragCallback howToDragCB
        -dropCallback howToDropCB
            $tslUI;
}

// ---------------------------------------------------------------------
// howToDragCB
// ---------------------------------------------------------------------
/// Process the "on drag" events from participating MEL UI controls.
///
/// \param  $dragControl: The control from which the "on drag" event
///                       was initiated.
/// \param  $x: The X coordinate of the mouse where the drag event
///             occurred.
/// \param  $y: The Y coordinate of the mouse where the drag event
///             occurred.
/// \param  $mods: Any modifying keypresses.
///                 0 = None, 1 = Shift, 2 = Ctrl, 3 = Both.
// ---------------------------------------------------------------------
global proc string[] howToDragCB( string $dragControl, 
                               int $x, int $y, int $mods )
{
    print ( "Drag from " + $dragControl + "\n" );

    // The msg array returned from the drag callback must _not_ be empty,
    // else the drop callback will not trigger.
    //
    return { $dragControl };
}

// ---------------------------------------------------------------------
// howToDropCB
// ---------------------------------------------------------------------
/// Process the "on drop" events from participating MEL UI controls.
///
/// \param  $drag: The control from which the "on drag" event was 
///                initiated.
/// \param  $drop: The control upon which the "on drop" event was 
///                invoked.
/// \param  $msgs: Array of messages sent from the "on drag" callback.
/// \param  $x: The X coordinate of the mouse where the drop event
///             occurred.
/// \param  $y: The Y coordinate of the mouse where the drop event
///             occurred.
/// \param  $type: (unknown)
// ---------------------------------------------------------------------
global proc howToDropCB( string $drag, string $drop, string $msgs[],
                          int $x, int $y, int $type )
{
    print ( "Drop on " + $drop + " from " + $msgs[0] + "\n" );

    // Special case for textScrollList.
    //
    if ( `textScrollList -q -exists $drop` )
    {
      textScrollList -e -append ( "Drop from " + $msgs[0] ) $drop;
    }
}

19 Feb 2005