#include <QtCore/QObject>
#include <QtGui/QApplication>
#include <QtGui/qevent.h>
#include <maya/MFnPlugin.h>
#include <maya/MIOStream.h>
#include <maya/MStatus.h>     
#include <maya/MEvent.h> 
#include <maya/MGlobal.h>
#include <maya/MItSelectionList.h>
#include <maya/MFnSingleIndexedComponent.h>
#include <maya/MDagPath.h>
#include <maya/MFn.h>
#include <maya/MFnMesh.h>
#include <maya/MPoint.h>
#include <maya/MVector.h>
#include <maya/MMatrix.h>
#include <maya/MIntArray.h>
#include <maya/MFloatArray.h>
#include <maya/MUintArray.h>
#include <maya/MToolsInfo.h>
#include <maya/MUIDrawManager.h>
#include <maya/MFrameContext.h>
#include <maya/MColor.h> 
#include <maya/MPxTexContext.h>
#include <maya/MPxContextCommand.h>
#include <maya/MPxPolyTweakUVInteractiveCommand.h>
{
public:
    static void *creator() { return new UVUpdateCommand; };
};
struct BrushConfig
{
    BrushConfig() : fSize(50.0f) {};
    float size() const { return fSize; }
    void setSize( float size ) { fSize = size; }
private:
    float fSize;
};
{
public:
    
    grabUVContext();
    
    virtual ~grabUVContext() {} ;
    bool            doKeyPress( QKeyEvent* event );
    bool            doKeyRelease( QKeyEvent* event );
    virtual bool    eventFilter(QObject *object, QEvent *event);
    float   size() const;
    void    setSize( float size );
private:             
    enum DragMode
    {
        kNormal,
        kBrushSize
    };
    BrushConfig     fBrushConfig;
    DragMode        fDragMode;
    bool            fInStroke;
    MPoint          fBrushCenterScreenPoint;
 
    UVUpdateCommand *fCommand;
}; 
grabUVContext::grabUVContext() :
    fCommand(NULL),
    fInStroke(false),
    fDragMode(kNormal)
{
}
float grabUVContext::size() const 
{ 
    return fBrushConfig.size();
}
void grabUVContext::setSize( float size )
{ 
    fBrushConfig.setSize( size ); 
}
void grabUVContext::toolOnSetup( 
MEvent &event )
 
{
    QCoreApplication *app = qApp;
    app->installEventFilter(this);
}
void grabUVContext::toolOffCleanup()
{
    QCoreApplication *app = qApp;
    app->removeEventFilter(this);
}
bool grabUVContext::eventFilter( QObject * object, QEvent *event )
{
    if( QKeyEvent* e = dynamic_cast<QKeyEvent*>(event) )
    {
        if( e->type() == QEvent::KeyPress )
            doKeyPress( e );
        else if( e->type() == QEvent::KeyRelease )
            doKeyRelease( e );
    }
    
    
    return false;
}
bool grabUVContext::doKeyPress( QKeyEvent* event )
{
    if( fInStroke )
        return false;
    if( event->key() == Qt::Key_B ) 
    {
        fDragMode = kBrushSize;
        return true;
    }
    return false;
}
bool grabUVContext::doKeyRelease( QKeyEvent* event )
{
    if( fInStroke )
        return false;
    if( fDragMode != kNormal )
    {
        fDragMode = kNormal;
        return true;
    }
    return false;
}
{
        !event.isModifierNone() )
    fInStroke = true;
    short x, y;
    event.getPosition( x, y );
    fCurrentScreenPoint = 
MPoint( x, y );
    fLastScreenPoint = 
MPoint( x, y );
    fBrushCenterScreenPoint = 
MPoint( x, y );
    double xView, yView;
    portToView(x, y, xView, yView); 
    double portW, portH;
    portSize(portW, portH);
    double left, right, bottom, top;
    viewRect(left, right, bottom, top);
    double sizeInView = portW < 1e-5 ? 0.0 : ( fBrushConfig.size() * (right - left) / portW );
    double sizeInViewSquare = sizeInView * sizeInView;
    if( fDragMode == kNormal )
    {
        fCollectedUVs.clear();
        const bool bPickSingle = false;
                                                           x + fBrushConfig.size(), y + fBrushConfig.size(), 
                                                           mask, bPickSingle, true, selectionList );
        if (bSelect)
        {
            selectionList.
getDagPath( 0, fDagPath, component );
            fDagPath.extendToShape();
            mesh.getCurrentUVSetName(currentUVSetName);
            {
                compFn.getElements( UVsToTest );
                for (
unsigned int i = 0; i < UVsToTest.
length(); ++i)
 
                {
                    float u, v;
                    MStatus bGetUV = mesh.getUV(UVsToTest[i], u, v, ¤tUVSetName);
 
                    {
                        float distSquare = ( u - xView ) * ( u - xView ) + ( v - yView ) * ( v - yView );
                        if ( distSquare < sizeInViewSquare )
                            fCollectedUVs.append(UVsToTest[i]);
                    }
                }
            }
            
            fLastPoint = 
MPoint( xView, yView, 0.0 );
            fCurrentPoint = 
MPoint( xView, yView, 0.0 );
        }
    }
}
{
    fInStroke = false;
    if (fCommand)
        fCommand->finalize();
    fCommand = NULL;
}
{
        !event.isModifierNone() )
    short x, y;
    event.getPosition( x, y );
    fLastScreenPoint = fCurrentScreenPoint;
    fCurrentScreenPoint = 
MPoint( x, y );
    double xView, yView;
    portToView(x, y, xView, yView); 
    fLastPoint = fCurrentPoint;
    fCurrentPoint = 
MPoint( xView, yView, 0.0 );
    if( fDragMode == kBrushSize )
    {
        double dis = fCurrentScreenPoint.distanceTo( fLastScreenPoint );
        if ( fCurrentScreenPoint[0] > fLastScreenPoint[0] )
            setSize( size() + float(dis) );
        else
            setSize( std::max( size() - float(dis), 0.01f ) );
    }
    else
    {
        fBrushCenterScreenPoint = 
MPoint( x, y );
        const MVector vec = fCurrentPoint - fLastPoint;
 
        if (!fCommand)
        {
            fCommand = (UVUpdateCommand *)(newToolCommand());
        }
        if (fCommand)
        {
            mesh.getCurrentUVSetName(currentUVSetName);
            int nbUVs = mesh.numUVs(currentUVSetName);
            mesh.getPinUVs(uvPinIds, pinData, ¤tUVSetName);
            for (unsigned int i = 0; i < nbUVs; i++) {
                fullPinData[i] = 0.0;
            }
            while( len-- > 0 ) {
                fullPinData[uvPinIds[len]] = pinData[len];
            }
            float pinWeight = 0;
            for (unsigned int i = 0; i < fCollectedUVs.length(); ++i)
            {
                float u, v;
                MStatus bGetUV = mesh.getUV(fCollectedUVs[i], u, v, ¤tUVSetName);
 
                {
                    pinWeight = fullPinData[fCollectedUVs[i]];
                    u += (float)vec[0]*(1-pinWeight);
                    v += (float)vec[1]*(1-pinWeight);
                }
            }
            fCommand->setUVs( mesh.object(), fCollectedUVs, uValues, vValues, ¤tUVSetName );
        }
    }
}
{
    double portW, portH;
    portSize(portW, portH);
    short x, y;
    event.getPosition( x, y );
    y = short(portH) - y;
    fCurrentScreenPoint = 
MPoint( x, y );
    fLastScreenPoint = 
MPoint( x, y );
    fBrushCenterScreenPoint = 
MPoint( x, y );
}
{
    
    {
        drawMgr.
circle2d(
MPoint(fBrushCenterScreenPoint.x, fBrushCenterScreenPoint.y), fBrushConfig.size());
    }               
}
void grabUVContext::getClassName( 
MString & name )
 const 
{
}
#define kSizeFlag           "-sz"
#define kSizeFlagLong       "-size"
{
public:  
                        grabUVContextCommand();
    static void*        creator();
protected:
    grabUVContext*      fGrabUVContext;
};          
grabUVContextCommand::grabUVContextCommand() {}
{
    fGrabUVContext = new grabUVContext();
    return fGrabUVContext;
}
void* grabUVContextCommand::creator()
{
    return new grabUVContextCommand;
}
MStatus grabUVContextCommand::doEditFlags()
 
{
        double size;
        if (!status) {
            status.
perror(
"size flag parsing failed.");
            return status;
        }
        fGrabUVContext->setSize( float(size) );
    }
}
MStatus grabUVContextCommand::doQueryFlags()
 
{
        setResult(fGrabUVContext->size());
    }
}
MStatus grabUVContextCommand::appendSyntax()
 
{
    }
}
#define CTX_CREATOR_NAME "grabUVContext"
#define TEX_COMMAND_NAME "uvUpdateCommand" 
    
    
    
    
    
    
    
    
    
{ 
    
    
    status = plugin.registerContextCommand(CTX_CREATOR_NAME, grabUVContextCommand::creator,
        TEX_COMMAND_NAME, UVUpdateCommand::creator);
    return status;
}
    
    
    
    
    
    
    
    
{
    
    
    status = plugin.deregisterContextCommand(CTX_CREATOR_NAME, TEX_COMMAND_NAME);
    return status;
}