diff --git a/grill/views/_graph.py b/grill/views/_graph.py index 3520a1f6..4a6d42e9 100644 --- a/grill/views/_graph.py +++ b/grill/views/_graph.py @@ -28,11 +28,14 @@ # Blockers: # - There seems to be two calls to LOADGRAPH when ConnectionViewer # - Popup everytime a new graph is loaded in Houdini or Maya ( it's on _run_prog func line 1380 of agraph.py ) +# https://github.com/pygraphviz/pygraphviz/pull/514 +# - LayerStack composition does not load if pygraphviz is not in the environment # Non blockers: # - Tooltip on nodes for layerstack -# - Focus with F # - Context menu items # - Ability to move further in canvas after Nodes don't exist +# - when switching a node left to right with precise source layers, the source node plugs do not refresh if we're moving the target node + _NO_PEN = QtGui.QPen(QtCore.Qt.NoPen) @@ -421,7 +424,9 @@ class _GraphicsViewport(QtWidgets.QGraphicsView): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._dragging = False - self._last_pan_pos = None + self._last_pan_pos = QtCore.QPoint() + self._rubber_band = QtWidgets.QRubberBand(QtWidgets.QRubberBand.Rectangle, self) + self._start_rubber_band_pos = QtCore.QPoint() def wheelEvent(self, event): modifiers = event.modifiers() @@ -441,6 +446,10 @@ def mousePressEvent(self, event): QtWidgets.QApplication.setOverrideCursor(QtGui.Qt.ClosedHandCursor) self._last_pan_pos = _EVENT_POSITION_FUNC(event) event.accept() + elif event.button() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.NoModifier: + self._start_rubber_band_pos = event.pos() + self._rubber_band.setGeometry(QtCore.QRect(self._start_rubber_band_pos, QtCore.QSize())) + self._rubber_band.show() return super().mousePressEvent(event) @@ -449,9 +458,17 @@ def mouseReleaseEvent(self, event): self._dragging = False QtWidgets.QApplication.restoreOverrideCursor() event.accept() - + elif event.button() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.NoModifier: + self._rubber_band.hide() + for item in self._get_items_in_rubber_band(): + item.setSelected(True) return super().mouseReleaseEvent(event) + def _get_items_in_rubber_band(self): + rubber_band_rect = self._rubber_band.geometry() + scene_rect = self.mapToScene(rubber_band_rect).boundingRect() + return self.scene().items(scene_rect) + def mouseMoveEvent(self, event): if self._dragging and event.buttons() == QtCore.Qt.MiddleButton: # Pan the scene when middle mouse button is held down @@ -460,6 +477,8 @@ def mouseMoveEvent(self, event): self.verticalScrollBar().setValue(self.verticalScrollBar().value() - delta.y()) self._last_pan_pos = _EVENT_POSITION_FUNC(event) return + elif event.buttons() == QtCore.Qt.LeftButton and event.modifiers() == QtCore.Qt.NoModifier: + self._rubber_band.setGeometry(QtCore.QRect(self._start_rubber_band_pos, event.pos()).normalized()) return super().mouseMoveEvent(event) def horizontal_pan(self, event): @@ -472,6 +491,21 @@ def vertical_pan(self, event): scroll_bar = self.verticalScrollBar() scroll_bar.setValue(scroll_bar.value() - delta) + def keyPressEvent(self, event): + if event.key() == QtCore.Qt.Key_F: + self._focus_view_requested() + return super().keyPressEvent(event) + + def _focus_view_requested(self): + if selected_items := self.scene().selectedItems(): + bounding_rect = QtCore.QRectF() + for item in selected_items: + bounding_rect |= item.sceneBoundingRect() + else: # if no items have been selected, focus on all items + bounding_rect = self.scene().itemsBoundingRect() + + self.fitInView(bounding_rect, QtCore.Qt.KeepAspectRatio) + class GraphView(_GraphicsViewport): def __init__(self, graph: nx.DiGraph = None, parent=None): diff --git a/grill/views/description.py b/grill/views/description.py index 061c656b..4a017a48 100644 --- a/grill/views/description.py +++ b/grill/views/description.py @@ -323,6 +323,7 @@ def __init__(self, parent=None, **kwargs): self._graph_view = _graph._GraphViewer(parent=self) vertical = QtWidgets.QSplitter(QtCore.Qt.Vertical) vertical.addWidget(self._graph_view) + self.setFocusProxy(self._graph_view) layout = QtWidgets.QVBoxLayout() layout.addWidget(vertical) self.setLayout(layout) @@ -844,7 +845,7 @@ def __init__(self, parent=None, **kwargs): horizontal.addWidget(self._prims) self._graph_view = _graph._GraphViewer(parent=self) - + self.setFocusProxy(self._graph_view) _graph_legend_controls = QtWidgets.QFrame() _graph_controls_layout = QtWidgets.QVBoxLayout() _graph_arcs_layout = QtWidgets.QHBoxLayout() @@ -877,7 +878,8 @@ def _arc_filter(title, state=QtCore.Qt.CheckState.PartiallyChecked): return widget _graph_arcs_layout.addStretch(0) - self._has_specs = _arc_filter("Has Specs", QtCore.Qt.CheckState.Checked) + # self._has_specs = _arc_filter("Has Specs", QtCore.Qt.CheckState.Checked) + self._has_specs = _arc_filter("Has Specs") self._is_ancestral = _arc_filter("Is Ancestral") self._is_implicit = _arc_filter("Is Implicit") self._from_root_prim_spec = _arc_filter("From Root Layer Prim Spec") @@ -885,8 +887,6 @@ def _arc_filter(title, state=QtCore.Qt.CheckState.PartiallyChecked): filters_layout.addStretch(0) ############## - - # _graph_controls_layout.addStretch(0) _graph_legend_controls.setFixedHeight(_graph_legend_controls.sizeHint().height()) vertical = QtWidgets.QSplitter(QtCore.Qt.Vertical) vertical.addWidget(horizontal)