def mouseMoveEvent(self, event): ''' Determine if the current movement is a drag. If it is, convert it into a QDrag. If the drag ends inside the tab bar, emit an move_tab_signal. If the drag ends outside the tab bar, emit an detach_tab_signal. ''' # Determine if the current movement is detected as a drag if not self.drag_start_pos.isNull() and ((event.pos() - self.drag_start_pos).manhattanLength() > QApplication.startDragDistance()): self.drag_initiated = True # If the current movement is a drag initiated by the left button if ((event.buttons() & Qt.LeftButton)) and self.drag_initiated: # Stop the move event finishMoveEvent = QMouseEvent(QEvent.MouseMove, event.pos(), Qt.NoButton, Qt.NoButton, Qt.NoModifier) QTabBar.mouseMoveEvent(self, finishMoveEvent) # Convert the move event into a drag drag = QDrag(self) mime_data = QMimeData() mime_data.setData('action', b'application/tab-detach') drag.setMimeData(mime_data) # Create the appearance of dragging the tab content # tab_index = self.tabAt(self.drag_start_pos) pixmap = self.parentWidget().grab() targetPixmap = QPixmap(pixmap.size()) targetPixmap.fill(Qt.transparent) painter = QPainter(targetPixmap) painter.setOpacity(0.85) painter.drawPixmap(0, 0, pixmap) painter.end() drag.setPixmap(targetPixmap) # Initiate the drag dropAction = drag.exec_(Qt.MoveAction | Qt.CopyAction) # If the drag completed outside of the tab bar, detach the tab and move # the content to the current cursor position if dropAction == Qt.IgnoreAction: event.accept() self.detach_tab_signal.emit(self.tabAt(self.drag_start_pos), self.mouse_cursor.pos(), False) elif dropAction == Qt.MoveAction: # else if the drag completed inside the tab bar, move the selected tab to the new position if not self.drag_droped_pos.isNull(): self.move_tab_signal.emit(self.tabAt(self.drag_start_pos), self.tabAt(self.drag_droped_pos)) else: # else if the drag completed inside the tab bar new TabBar, move the selected tab to the new TabBar self.detach_tab_signal.emit(self.tabAt(self.drag_start_pos), self.mouse_cursor.pos(), False) event.accept() else: QTabBar.mouseMoveEvent(self, event)
def _event(self, e): if e.type() == QEvent.MouseButtonPress and e.button() == Qt.LeftButton: qDebug('%spress, rel=%s, global=%s, diff=%s' % ( (' - pseudo ' if self._releasing_and_repressing_while_dragging else ''), e.pos(), e.globalPos(), e.globalPos() - self.pos())) if e.type() == QEvent.MouseButtonRelease and e.button( ) == Qt.LeftButton: qDebug('%srelease, rel=%s, global=%s, diff=%s' % ( (' - pseudo ' if self._releasing_and_repressing_while_dragging else ''), e.pos(), e.globalPos(), e.globalPos() - self.pos())) # store local position when pressing button before starting the custom drag'n'drop # only allow when layout is not frozen if self._dragging_parent is None and e.type( ) == QEvent.MouseButtonPress and e.button() == Qt.LeftButton and bool( self.features() & QDockWidget.DockWidgetMovable): self._dragging_local_pos = e.pos() if self._dragging_parent is None and self._dragging_local_pos is not None and e.type( ) == QEvent.Move and QApplication.mouseButtons() & Qt.LeftButton: if self._widget_at(e.pos()) is not None: qDebug( 'DockWidget._event() start drag, dockwidget=%s, parent=%s, floating=%s, pos=%s' % (str(self), str(self.parent()), str( self.isFloating()), str(self._dragging_local_pos))) self._dragging_parent = self.parent() # ignore further mouse events so that the widget behind this dock widget can be determined self.setAttribute(Qt.WA_TransparentForMouseEvents) # collect all main windows (except self.main_window) to re-implement QApplication.widgetAt() in self._widget_at() self._main_windows = [ self._container_manager.get_root_main_window() ] for container in self._container_manager.get_containers(): if container == self: continue self._main_windows.append(container.main_window) # unset local position when releasing button even when custom drag'n'drop has not been started if self._dragging_local_pos is not None and e.type( ) == QEvent.MouseButtonRelease and e.button( ) == Qt.LeftButton and not self._releasing_and_repressing_while_dragging: self._dragging_local_pos = None if self._dragging_parent is not None and e.type( ) == QEvent.MouseButtonRelease and e.button( ) == Qt.LeftButton and not self._releasing_and_repressing_while_dragging: qDebug( 'DockWidget._event() stop drag, dockwidget=%s, parent=%s\n' % (self, self.parent())) self._dragging_parent = None self.setAttribute(Qt.WA_TransparentForMouseEvents, False) self._main_windows = [] if self._dragging_parent is not None and e.type( ) == QEvent.MouseMove and e.buttons( ) & Qt.LeftButton and not self._releasing_and_repressing_while_dragging: widget = self._widget_at(e.globalPos()) new_parent = self._get_new_parent(widget) #print 'new_parent', new_parent, (new_parent.objectName() if new_parent else '') if new_parent is not None and new_parent != self.parent(): self._releasing_and_repressing_while_dragging = True # schedule stop of pseudo drag'n'drop and let it complete mouse_release_event = QMouseEvent(QEvent.MouseButtonRelease, self._dragging_local_pos, e.globalPos(), Qt.LeftButton, Qt.NoButton, e.modifiers()) QApplication.instance().postEvent(self, mouse_release_event) QApplication.sendPostedEvents() # schedule reparent to hovered main window and let it complete reparent_event = ReparentEvent(self, new_parent) QApplication.instance().postEvent(self._container_manager, reparent_event) QApplication.sendPostedEvents() # reenable mouse events to be able to receive upcoming pseudo mouse events self.setAttribute(Qt.WA_TransparentForMouseEvents, False) # schedule restart of pseudo drag'n'drop and let it complete mouse_repress_event = QMouseEvent(QEvent.MouseButtonPress, self._dragging_local_pos, e.globalPos(), Qt.LeftButton, Qt.LeftButton, e.modifiers()) QApplication.instance().postEvent(self, mouse_repress_event) QApplication.sendPostedEvents() # schedule move to trigger dock widget drag'n'drop required for snapping and showing rubber band and let it complete # move forth... mouse_move_event = QMouseEvent( QEvent.MouseMove, self._dragging_local_pos, e.globalPos() + QPoint(QApplication.startDragDistance(), 1), Qt.NoButton, Qt.LeftButton, e.modifiers()) QApplication.instance().postEvent(self, mouse_move_event) QApplication.sendPostedEvents() # ...and back mouse_move_event = QMouseEvent(QEvent.MouseMove, self._dragging_local_pos, e.globalPos(), Qt.NoButton, Qt.LeftButton, e.modifiers()) QApplication.instance().postEvent(self, mouse_move_event) QApplication.sendPostedEvents() # restore attributes after repressing the button self.setAttribute(Qt.WA_TransparentForMouseEvents) self._releasing_and_repressing_while_dragging = False return super(DockWidget, self).event(e)
def _event(self, e): if e.type() == QEvent.MouseButtonPress and e.button() == Qt.LeftButton: qDebug('%spress, rel=%s, global=%s, diff=%s' % ((' - pseudo ' if self._releasing_and_repressing_while_dragging else ''), e.pos(), e.globalPos(), e.globalPos() - self.pos())) if e.type() == QEvent.MouseButtonRelease and e.button() == Qt.LeftButton: qDebug('%srelease, rel=%s, global=%s, diff=%s' % ((' - pseudo ' if self._releasing_and_repressing_while_dragging else ''), e.pos(), e.globalPos(), e.globalPos() - self.pos())) # store local position when pressing button before starting the custom drag'n'drop # only allow when layout is not frozen if self._dragging_parent is None and e.type() == QEvent.MouseButtonPress and e.button() == Qt.LeftButton and bool(self.features() & QDockWidget.DockWidgetMovable): self._dragging_local_pos = e.pos() if self._dragging_parent is None and self._dragging_local_pos is not None and e.type() == QEvent.Move and QApplication.mouseButtons() & Qt.LeftButton: if self._widget_at(e.pos()) is not None: qDebug('DockWidget._event() start drag, dockwidget=%s, parent=%s, floating=%s, pos=%s' % (str(self), str(self.parent()), str(self.isFloating()), str(self._dragging_local_pos))) self._dragging_parent = self.parent() # ignore further mouse events so that the widget behind this dock widget can be determined self.setAttribute(Qt.WA_TransparentForMouseEvents) # collect all main windows (except self.main_window) to re-implement QApplication.widgetAt() in self._widget_at() self._main_windows = [self._container_manager.get_root_main_window()] for container in self._container_manager.get_containers(): if container == self: continue self._main_windows.append(container.main_window) # unset local position when releasing button even when custom drag'n'drop has not been started if self._dragging_local_pos is not None and e.type() == QEvent.MouseButtonRelease and e.button() == Qt.LeftButton and not self._releasing_and_repressing_while_dragging: self._dragging_local_pos = None if self._dragging_parent is not None and e.type() == QEvent.MouseButtonRelease and e.button() == Qt.LeftButton and not self._releasing_and_repressing_while_dragging: qDebug('DockWidget._event() stop drag, dockwidget=%s, parent=%s\n' % (self, self.parent())) self._dragging_parent = None self.setAttribute(Qt.WA_TransparentForMouseEvents, False) self._main_windows = [] if self._dragging_parent is not None and e.type() == QEvent.MouseMove and e.buttons() & Qt.LeftButton and not self._releasing_and_repressing_while_dragging: widget = self._widget_at(e.globalPos()) new_parent = self._get_new_parent(widget) #print 'new_parent', new_parent, (new_parent.objectName() if new_parent else '') if new_parent is not None and new_parent != self.parent(): self._releasing_and_repressing_while_dragging = True # schedule stop of pseudo drag'n'drop and let it complete mouse_release_event = QMouseEvent(QEvent.MouseButtonRelease, self._dragging_local_pos, e.globalPos(), Qt.LeftButton, Qt.NoButton, e.modifiers()) QApplication.instance().postEvent(self, mouse_release_event) QApplication.sendPostedEvents() # schedule reparent to hovered main window and let it complete reparent_event = ReparentEvent(self, new_parent) QApplication.instance().postEvent(self._container_manager, reparent_event) QApplication.sendPostedEvents() # reenable mouse events to be able to receive upcoming pseudo mouse events self.setAttribute(Qt.WA_TransparentForMouseEvents, False) # schedule restart of pseudo drag'n'drop and let it complete mouse_repress_event = QMouseEvent(QEvent.MouseButtonPress, self._dragging_local_pos, e.globalPos(), Qt.LeftButton, Qt.LeftButton, e.modifiers()) QApplication.instance().postEvent(self, mouse_repress_event) QApplication.sendPostedEvents() # schedule move to trigger dock widget drag'n'drop required for snapping and showing rubber band and let it complete # move forth... mouse_move_event = QMouseEvent(QEvent.MouseMove, self._dragging_local_pos, e.globalPos() + QPoint(QApplication.startDragDistance(), 1), Qt.NoButton, Qt.LeftButton, e.modifiers()) QApplication.instance().postEvent(self, mouse_move_event) QApplication.sendPostedEvents() # ...and back mouse_move_event = QMouseEvent(QEvent.MouseMove, self._dragging_local_pos, e.globalPos(), Qt.NoButton, Qt.LeftButton, e.modifiers()) QApplication.instance().postEvent(self, mouse_move_event) QApplication.sendPostedEvents() # restore attributes after repressing the button self.setAttribute(Qt.WA_TransparentForMouseEvents) self._releasing_and_repressing_while_dragging = False return super(DockWidget, self).event(e)