diff --git a/dat/gui/cellcontainer.py b/dat/gui/cellcontainer.py index b23efa8..21d3250 100644 --- a/dat/gui/cellcontainer.py +++ b/dat/gui/cellcontainer.py @@ -49,6 +49,8 @@ def __init__(self, cellInfo=None, widget=None, error=None, parent=None): self._parameter_hovered = None self._insert_pos = None + self._dragging = False + self._fake_widget = None # Notifications app = get_vistrails_application() @@ -62,7 +64,7 @@ def __init__(self, cellInfo=None, widget=None, error=None, parent=None): # Overlay self._overlay = None - self._overlay_scrollarea = QtGui.QScrollArea(self) + self._overlay_scrollarea = QtGui.QScrollArea() # FIXME: no parent self._overlay_scrollarea.setObjectName('overlay_scrollarea') self._overlay_scrollarea.setStyleSheet( 'QScrollArea#overlay_scrollarea {' @@ -72,6 +74,7 @@ def __init__(self, cellInfo=None, widget=None, error=None, parent=None): ' background-color: transparent;' '}') self._overlay_scrollarea.setWidgetResizable(True) + self._overlay_scrollarea.setVisible(False) # Toolbar self._container_toolbar = QtGui.QToolBar(self) @@ -144,17 +147,67 @@ def setCellInfo(self, cellInfo): app.unregister_notification( 'dragging_to_overlays', self._set_dragging) - def _set_dragging(self, dragging): - """This is a hack to avoid an issue with Qt's mouse event propagation. + def _make_fake_widget(self): + if self._fake_widget is None: + if hasattr(self.containedWidget, 'grabWindowPixmap'): + pixmap = self.containedWidget.grabWindowPixmap() + else: + pixmap = QtGui.QPixmap.grabWidget(self.containedWidget) + + self.containedWidget.setAttribute( + QtCore.Qt.WA_TransparentForMouseEvents, True) + self.containedWidget.setParent(None) + self.containedWidget.hide() - If we don't set TransparentForMouseEvents on the overlay, when the drag - enters, the overlay will receive the mouse event and propagate it to - us. Thus it is on the call stack and we can't replace it with another - overlay... It would cause a segmentation fault on Mac OS. + self._fake_widget = QtGui.QLabel(self) + self._fake_widget.setPixmap(pixmap) + self._fake_widget.setAttribute( + QtCore.Qt.WA_TransparentForMouseEvents, True) + + def _set_dragging(self, dragging): + """This is a hack to workaround issues related to dragging. """ + self._dragging = dragging + + # Issue with Qt's mouse event propagation. + # + # If we don't set TransparentForMouseEvents on the overlay, when the + # drag enters, the overlay will receive the mouse event and propagate + # it to us. Thus it is on the call stack and we can't replace it with + # another overlay... It would cause a segmentation fault on Mac OS. self._overlay_scrollarea.setAttribute( QtCore.Qt.WA_TransparentForMouseEvents, dragging) + # Issue with some non-Qt widgets, such as VTK's (that use direct + # rendering) + # We can just replace the cell with an image of the previous content, + # like the spreadsheet does with QCellPresenter + if dragging: + if self.containedWidget is not None: + self._make_fake_widget() + self._fake_widget.raise_() + self._fake_widget.show() + + self._overlay_scrollarea.setParent(self) + self._overlay_scrollarea.setVisible(True) + self._overlay_scrollarea.lower() + + self.do_layout() + else: + if self._fake_widget is not None: + self._fake_widget.setParent(None) + self._fake_widget.deleteLater() + self._fake_widget = None + if self.containedWidget is not None: + self.containedWidget.setAttribute( + QtCore.Qt.WA_TransparentForMouseEvents, False) + + self.containedWidget.setParent(self) + self.containedWidget.show() + self.containedWidget.raise_() + + self.do_layout() + def _variable_added(self, controller, varname, renamed_from=None): if (renamed_from is None or controller != self._controller or @@ -208,24 +261,24 @@ def setWidget(self, widget): This is called by the spreadsheet to put or remove a visualization in this cell. """ - if widget != self.containedWidget: + assert self._fake_widget is None + if widget is not self.containedWidget: if self.containedWidget: self.containedWidget.setParent(None) self.containedWidget.deleteLater() self.toolBar = None if widget: widget.setParent(self) - widget.show() self.containedWidget = widget if widget is None: return - widget.raise_() self._set_toolbar_buttons(True) self.contentsUpdated() def takeWidget(self): + assert self._fake_widget is None widget = self.containedWidget if widget is not None: widget.setParent(None) @@ -273,7 +326,7 @@ def contentsUpdated(self): self._set_overlay(None) def _set_overlay(self, overlay_class, **kwargs): - if overlay_class is None: + if overlay_class is None and not self._execute_pending: # Default overlay if self._plot is not None and self.has_error(): self._set_overlay(VariableDroppingOverlay, overlayed=False) @@ -293,22 +346,45 @@ def _set_overlay(self, overlay_class, **kwargs): if overlay_class is None: self._overlay = None - self._overlay_scrollarea.lower() + if not self._dragging: + self._overlay_scrollarea.setParent(None) + self._overlay_scrollarea.setVisible(False) if self._plot is not None: self._set_toolbar_buttons(True) else: self._set_toolbar_buttons(None) + if self._fake_widget is not None: + self._fake_widget.setParent(None) + self._fake_widget.deleteLater() + self._fake_widget = None + if self.containedWidget: + self.containedWidget.setParent(self) + self.containedWidget.show() + self.containedWidget.raise_() + self.containedWidget.setAttribute( + QtCore.Qt.WA_TransparentForMouseEvents, False) + self.do_layout() + # Now that we are done with the overlay, we can go on with a # deferred execution if self._execute_pending: self.update_pipeline() self._execute_pending = False else: + if self.containedWidget is not None: + self._make_fake_widget() + self._fake_widget.lower() + self._fake_widget.show() + self._overlay = overlay_class(self, **kwargs) + if not self._dragging: + self._overlay_scrollarea.setParent(self) + self._overlay_scrollarea.setVisible(True) self._overlay_scrollarea.setWidget(self._overlay) self._overlay.show() self._overlay_scrollarea.raise_() + self.do_layout() self._set_toolbar_buttons(None) @@ -347,8 +423,13 @@ def resizeEvent(self, event): self.do_layout() def do_layout(self): - if self.containedWidget is not None: - self.containedWidget.setGeometry( + if self._fake_widget is not None: + widget = self._fake_widget + else: + widget = self.containedWidget + + if widget is not None: + widget.setGeometry( 4, 4, self.width() - 8, self.height() - 8) self._overlay_scrollarea.setGeometry(