Creating Drag/Droppable UI in Maya is a really nice way of making your UIs either more user-friendly or adding a lot more functionality without adding any more visible UI controls. It is also very easy to set up and manage once you know how.
Nearly all UI controls (of all types; buttons, sliders, fields, layouts, etc..) support being a drag zone, drop zone or both. If you add a drag callback flag to your UI control it will be dragable, if you add a drop callback it will be a drop zone. Add both callbacks and your UI control can be dragged and dropped to!
To make a piece of UI drag or droppable you simply add the appropriate flag and it’s function to the control command. For example:
button -l "Create Cube" -c "polyCube" -dgc "dragButton" -dpc "dropButton";
This creates a normal button that, when pressed creates a cube. When MMB-dragged, the button will execute the function dragButton and if anything is dropped onto the button, the function dropButton will be executed.
Every UI control uses these same two flags to support drag/drop (-dgc and -dpc) and when their functions are executed Maya automatically passes certain parameters into them.
Of course we have to write these callback functions, and every callback you write must always contain the same correct input parameters:
// the drag function: proc string[] dragProc(string $dragCtrl,int $x, int $y, int $mods) { ... } // and the drop function: proc dropProc(string $dragCtrl, string $dropCtrl, string $msgs[], int $x, int $y, int $typ) { ... }
Don’t worry about what all those params do just yet, we’ll get to that later, for now lets just create some test UI:
{ string $win = "dragDropTestWindow"; if (`window -exists $win`) deleteUI -window $win; window -title "Drag/Drop Window" $win; columnLayout -adj 1 -rs 5; button -h 50 -l "Drag Me!" -dgc "dragCallBack"; button -h 50 -l "Drop Here!" -dpc "dropCallBack"; button -h 50 -l "Drag/Drop Here!" -dgc "dragCallBack" -dpc "dropCallBack"; separator -h 20; button -h 50 -l "MMB-Click me!" -dgc "dragCallBack" -dpc "dropCallBack"; setParent ..; window -e -wh 200 300 $win; showWindow $win; }
Now if you run that MEL script it should display a test window with four large buttons. Of course they won’t work yet as we’ve not defined our callback functions, but lets do that now…
global proc string[] dragCallBack(string $dragCtrl,int $x, int $y, int $mods) { print ("dragCallBack - Drag control: "+$dragCtrl+"\n"); return {"A","B","C"}; }
This is the DRAG callback. You can call it anything you like but it must have four input parameters (but again, as long as they are a string and three ints, you can call them whatever you like). This callback function is fired as soon as you MMB-drag on any UI control with it specified in its -dgc flag. The drag callback function MUST return a string array otherwise it will NOT register the drag/drop functionality at all!. If you’ve ever tried to get drag/drop working and been unsuccessful, chances are this was the reason!
Even if you don’t want your drag callback to return any data or messages it still has to return a string array, although returning an empty array is fine if you really don’t want any actual data.
The primary input parameter is: $dragCtrl. When the callback is executed this parameter contains the (full) name of the UI control you dragged on. To be honest I’ve never really needed this data as you also get it inside the drop callback, but it’s here anyway if you do need it for something. The $x and $y params pass in the screen x and y positions you clicked on and $mods holds any keyModifier values, so if you want to check the user is holding down SHIFT or CTRL or whatever you can. (see Maya’s getModifiers command for more details on modifiers).
You may find that in your production UI you have several different drop callbacks, but you can often recycle the same drag callback for all the UI controls. In all my UIs so far the drag callback does practically nothing, it simply exists to ensure that the dropping works, as you cannot have one without the other!
global proc dropCallBack(string $dragCtrl, string $dropCtrl, string $msgs[], int $x, int $y, int $type) { string $text = "dropCallBack:\n"; $text += (" Drag control: "+$dragCtrl+"\n"); $text += (" Drop control: "+$dropCtrl+"\n"); $text += (" messages: "); $text += `stringArrayToString $msgs ", "`; confirmDialog -m $text; }
This is the DROP callback and it’s the important one that does all the work. Basically, dragging something usually has no effect in itself right? it’s only once you let go and drop it that something happens! As with the drag function, you may call this anything you like, but make sure your function always has these same six parameters.
The first two are strings which contain the (full) names of the drag control and the drop control. These are important because you will always want to know what you dragged and what you dropped it on to determine what action to take. The third parameter is the message array. This simply contains whatever the drag callback returned. While this is often unused it is a way to pass your own data from the drag to the drop zone if you need to. The $x and $y parameters are the screen position of the drop and $type is supposed to somehow indicate move, copy and link, but I’ve never found any details of how to utilise this parameter. I’ve never needed to use any of these three last parameters and chances are you won’t either, but don’t forget they still have to be declared as function parameters.
Once you’ve input the UI code above and defined both drag and drop callbacks you should have a fully working Drag/Drop UI to play with.
You can legally drag/drop controls from any drag/drop UI to any other drag/drop UI, even between different windows and even when they have different callback functions. The only way to restrict what is permitted to be dropped on what is by making your drop callbacks check some attribute or property of the drag control and return if not “compatible”.
Unfortunately you cannot interact with the existing drag/drop controls inside Maya. For example you cannot drop a shelf button or a hypershade swatch onto a custom UI drop zone or drop your custom drag objects onto a maya drop zone (i.e. viewport, outliner, hypershade, etc..)
so if I want to interact with a button in the shelf, I have to create my own (duplicate) inside my window?
Comment by Shawn — February 22, 2011 @ 6:03 pm
Hey Shawn. it depends what you mean by “interact”. shelf buttons can be drag/dropped between any shelfLayouts without any additional code, so if you just want to support shelf buttons on a custom UI you just create a shelfLayout and you’re done. but you CAN’T drop a shelf button onto a UI control that has a -dpc or vice versa. This is all pre-2011 btw, so if you are using QT in 2011 there’s possible more stuff like this available.
Comment by Naughty — February 22, 2011 @ 8:36 pm
Hi Shawn,
Have you experimented using drag and drop from different types of windows. I mean dragging a file from a window’s explorer window into a control using Maya.
I tried this and I cannot get it to work. Other types of drag and drop events between Maya controls work fine.
Comment by Carlos — January 19, 2012 @ 2:55 am