from __future__ import division import maya.OpenMayaUI import maya.cmds from pymel.core import melGlobals from PySide2 import QtCore, QtGui, QtWidgets import shiboken2 import six if six.PY3: long = int def get_qobj(ui, widget=QtCore.QObject): if isinstance(ui, six.string_types): ptr = maya.OpenMayaUI.MQtUtil.findControl(ui) if ptr is None: ptr = maya.OpenMayaUI.MQtUtil.findLayout(ui) if ptr is None: ptr = maya.OpenMayaUI.MQtUtil.findMenuItem(ui) if ptr is not None: return shiboken2.wrapInstance(long(ptr), widget) else: return shiboken2.wrapInstance(long(ui), widget) def get_maya_ui(qobj): return maya.OpenMayaUI.MQtUtil.fullName(long(shiboken2.getCppPointer(qobj)[0])) class TableModel(QtCore.QAbstractTableModel): def __init__(self, data): super(TableModel, self).__init__() self._data = data def data(self, index, role): if role == QtCore.Qt.DisplayRole: return self._data[index.row()][index.column()] def rowCount(self, index): return len(self._data) def columnCount(self, index): return len(self._data[0]) def flags(self, index): return ( QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsDragEnabled ) class Table(QtWidgets.QTableView): dropped = QtCore.Signal(QtCore.QPoint, list) def __init__(self, parent=None): super(Table, self).__init__(parent) self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) self.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop) self.setDropIndicatorShown(True) def startDrag(self, supportedActions): listsQModelIndex = self.selectedIndexes() if listsQModelIndex: dragQDrag = QtGui.QDrag(self) defaultDropAction = QtCore.Qt.CopyAction dataQMimeData = self.model().mimeData(listsQModelIndex) dragQDrag.setMimeData(dataQMimeData) # dragQDrag.targetChanged.connect(self.__test) print("drag start") dragQDrag.exec_(supportedActions, defaultDropAction) pos = QtGui.QCursor.pos() data = [x.data() for x in listsQModelIndex] n = 2 data = [data[i : i + n] for i in range(0, len(data), n)] self.dropped.emit(pos, data) class MainWindow(QtWidgets.QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.table = Table() self.table.horizontalHeader().setStretchLastSection(True) data = [ ["awesome", "1.0"], ["ordinary", "0.3"], ["good", "1.2"], ["bad", "0.1"], ] self.model = TableModel(data) self.table.setModel(self.model) self.setCentralWidget(self.table) self.table.dropped.connect(self.insertButton) def insertButton(self, pos, data): print('insert at %s' % pos, data) shelfTabLayout = melGlobals["gShelfTopLevel"] shelfTabLayoutO = get_qobj(shelfTabLayout, QtWidgets.QWidget) pos_local = shelfTabLayoutO.mapFromGlobal(pos) maya.cmds.shelfTabLayout(shelfTabLayout, query=True, selectTabIndex=True) widget = QtWidgets.QApplication.widgetAt(pos) ui = get_maya_ui(widget) ui = ui.rstrip("|") print('dropped on', ui) current = maya.cmds.shelfTabLayout(shelfTabLayout, q=1, st=1) if ui.endswith("%s|mayaLayoutInternalWidget" % current): move = False else: ui_type = maya.cmds.objectTypeUI(ui) if ui_type in ("shelfButton", "separator"): move = True elif ui_type == "tabLayout": move = False # figure out which tab it is tabWidget = widget.parent() bar = tabWidget.tabBar() shelves = len( maya.cmds.shelfTabLayout(shelfTabLayout, query=True, ca=True) ) tab_width = bar.width() / shelves # estimated tab index = int((pos_local.x() // tab_width)) + 1 print( "dropped on", index, maya.cmds.shelfTabLayout(shelfTabLayout, q=1, tabLabelIndex=1)[ index ], ) # now you can append shelf button to that shelf tab and # activate it return else: return # append shelf button to currente tab buttons = [] for label, ver in data: button = maya.cmds.shelfButton( label=label, annotation="I am %s" % label, p="%s|%s" % (shelfTabLayout, current), command="print(%r)" % label, image1=":/ambientlight.png", imageOverlayLabel=label, ) buttons.append(button) if move: # determine drop on left or right button under cursor drop pos width = maya.cmds.control(ui, q=1, w=1) # left = pos_local.x() // width existing = maya.cmds.shelfLayout(current, q=1, ca=1) index = existing.index(ui.split("|")[-1]) left = sum([maya.cmds.control(x, q=1, w=1) for x in existing[:index] if maya.cmds.control(x, q=1, vis=1)]) right = 1 if (pos_local.x() - left) > width / 2.0 else 0 index = index + 1 + right for b in reversed(buttons): maya.cmds.shelfLayout(current, e=1, position=[b, index]) window = MainWindow() window.show()