Jump to content

Drag and drop from python panel into viewport


satara

Recommended Posts

Hi,

 

I'm currently working on an asset browser implemented as a python panel using PySide.

The main part of it is a QListWidget containing one items per asset. I'm trying to implement drag and drop functionality to place items directly in viewport at drop position.

 

For dragging I'm using the itemPressed signal, which is sent by QListWidget when holding the mouse button over an item. Then I want to check if a drop is allowed on mouseMoveEvent() by traversing all viewports and checking if the mouse cursor is located inside. But can't find a way to check if the mouse cursor is over the viewport. Also I need the exact drop position when releasing the mouse button.

 

I found this related topic http://forums.odforce.net/topic/20382-geometry-point-under-the-mouse/ and tried to adopt the first block to get the drop position in world space. For testing I just created a default Mouse CHOP and called hou.evalParm('/obj/chopnet/mouse") from withi mouseReleaseEvent(), but it always fails (the path is definetely correct) with hou.OperationFailed exception. Also calling hou.GeometryViewport.mapFromMouseChop() always fails for me, even if I just pass (0.0, 0.0).

 

Here is some code:

class AssetListWidget(QtGui.QListWidget):
  def __init__(self, parent=None):
        QtGui.QListWidget.__init__(self, parent)
        # doing some initialization here
        self.itemPressed.connect(self.onItemPressed)

    def onItemPressed(self, item):
        self.draggedItem = item
        # cache sceneviewers
        for paneTab in hou.ui.curDesktop().paneTabs():
            if paneTab.type() == hou.paneTabType.SceneViewer:
                self.sceneViewers.append(paneTab)
   
    def mouseMoveEvent(self, ev):
        allowDrag = False
        for sceneViewer in self.sceneViewers:
            for viewport in sceneViewer.viewports():
                try:
                    mx, my = hou.evalParmTuple("/obj/chopnet/mouse") # always fails
                    vx, vy = v.mapFromMouseChop(mx, my) # screen to view
                    direction, position =v.mapToWorld(vx,vy) # view to world 
                except hou.OperationFailed as err:
                    print err
                """
                try:
                    print viewport.mapFromMouseChop(0.0, 0.0) # always fails
                except hou.OperationFailed as err:
                    print err
                """
                
    def mouseReleaseEvent(self, ev):
        # will be similiar to above
        QtGui.QListWidget.mouseReleaseEvent(self, ev)

What am I doing wrong? How do I have to set up the Mouse CHOP properly? Does someone have a better advice for implementing this feature (if it is even possible using hom)?

 

Thanks for any help!

 

Best,

Satara

 

 

 

 

Link to comment
Share on other sites

You could use this, for example:

    def mouseReleaseEvent(self, event):
        sc = toolutils.sceneViewer()
        try:
            res = sc.selectPositions()
            origin = res[0]
        except hou.OperationInterrupted:
            return

        n = hou.node('/obj').createNode('null')
        n.parmTuple('t').set(origin)
Link to comment
Share on other sites

Thanks Alexey, that's perfect for my case. Do you also have any idea, how to check if the cursor is inside the sceneviewer to adjust the mouse cursor inside mouseMoveEvent()?

 

You can get viewport QWidget like this:

QApplication.instance().widgetAt(QCursor.pos())

This will give you a widget under the cursor, BUT, i don't know how to check if this QWidget is actually a houdini viewport :) 

Link to comment
Share on other sites

Guest mantragora

... how to check if this QWidget is actually a houdini viewport :)

Maybe you could check if it's a window. I think that OpenGL will be a child of a window, not a window by itself.

EDIT: So in QT words, you can check if QWidget have any children. Viewport shouldn't contain any QWidget children since it's not a part of QT, so it should return only blank list. It can have only parent.

 

from PySide import QtGui as qtg 

widget = qtg.QApplication.instance().widgetAt(qtg.QCursor().pos())
print(len(widget.children()))
Edited by mantragora
Link to comment
Share on other sites

Hey thanks, it's a bit hacky but seems to work for most of the cases. Only the timeline and my own QListWidget failed in the test (also have zero children). I also added a check for the objectName() to filter my own widget. I think it will be sufficient for now, but improvements would be very welcome! :)

def mouseMoveEvent(self, ev):
    allowDrop = False
    widget = QtGui.QApplication.instance().widgetAt(ev.globalX(), ev.globalY())
    if widget:
        if widget.objectName() == 're_QGLWidget':
            if len(widget.children()) == 0:
                allowDrop = True
Edited by satara
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...