diff --git a/bec_widgets/utils/bec_connector.py b/bec_widgets/utils/bec_connector.py index a5b6b087..daa1f6ac 100644 --- a/bec_widgets/utils/bec_connector.py +++ b/bec_widgets/utils/bec_connector.py @@ -89,6 +89,7 @@ class BECConnector: object_name: str | None = None, root_widget: bool = False, rpc_exposed: bool = True, + rpc_passthrough_children: bool = True, **kwargs, ): """ @@ -101,6 +102,9 @@ class BECConnector: object_name(str, optional): The object name. root_widget(bool, optional): If set to True, the parent_id will be always set to None, thus enforcing that the widget is accessible as a root widget of the BECGuiClient object. rpc_exposed(bool, optional): If set to False, this instance is excluded from RPC registry broadcast and CLI namespace discovery. + rpc_passthrough_children(bool, optional): Only relevant when ``rpc_exposed=False``. + If True, RPC-visible children rebind to the next visible ancestor. + If False (default), children stay hidden behind this widget. **kwargs: """ # Extract object_name from kwargs to not pass it to Qt class @@ -193,6 +197,9 @@ class BECConnector: self.root_widget = root_widget # If set to False, this instance is not exposed through RPC at all. self.rpc_exposed = bool(rpc_exposed) + # If True on a hidden parent (rpc_exposed=False), children can bubble up to + # the next visible RPC ancestor. + self.rpc_passthrough_children = bool(rpc_passthrough_children) self._update_object_name() @@ -201,11 +208,41 @@ class BECConnector: try: if self.root_widget: return None - connector_parent = WidgetHierarchy.get_becwidget_ancestor(self) + connector_parent = self._get_rpc_parent_ancestor() return connector_parent.gui_id if connector_parent else None except: logger.error(f"Error getting parent_id for {self.__class__.__name__}") + def _get_rpc_parent_ancestor(self) -> BECConnector | None: + """ + Find the nearest ancestor that is RPC-addressable. + + Rules: + - If an ancestor has ``rpc_exposed=False``, it is an explicit visibility + boundary unless ``rpc_passthrough_children=True``. + - If an ancestor has ``RPC=False`` (but remains rpc_exposed), it is treated + as structural and children continue to the next ancestor. + - Lookup always happens through ``WidgetHierarchy.get_becwidget_ancestor`` + so plain ``QWidget`` nodes between connectors are ignored. + """ + current = self + while True: + parent = WidgetHierarchy.get_becwidget_ancestor(current) + if parent is None: + return None + + if not getattr(parent, "rpc_exposed", True): + if getattr(parent, "rpc_passthrough_children", False): + current = parent + continue + return parent + + if getattr(parent, "RPC", True): + return parent + + current = parent + return None + def change_object_name(self, name: str) -> None: """ Change the object name of the widget. Unregister old name and register the new one. diff --git a/bec_widgets/widgets/containers/main_window/main_window.py b/bec_widgets/widgets/containers/main_window/main_window.py index d0514a86..e0f84a08 100644 --- a/bec_widgets/widgets/containers/main_window/main_window.py +++ b/bec_widgets/widgets/containers/main_window/main_window.py @@ -197,7 +197,7 @@ class BECMainWindow(BECWidget, QMainWindow): # Setting HoverWidget for the scan progress bar - minimal and full version self._scan_progress_bar_simple = ScanProgressBar( - self, one_line_design=True, rpc_exposed=False + self, one_line_design=True, rpc_exposed=False, rpc_passthrough_children=False ) self._scan_progress_bar_simple.show_elapsed_time = False self._scan_progress_bar_simple.show_remaining_time = False @@ -205,7 +205,9 @@ class BECMainWindow(BECWidget, QMainWindow): self._scan_progress_bar_simple.progressbar.label_template = "" self._scan_progress_bar_simple.progressbar.setFixedHeight(self.SCAN_PROGRESS_HEIGHT) self._scan_progress_bar_simple.progressbar.setFixedWidth(self.SCAN_PROGRESS_WIDTH) - self._scan_progress_bar_full = ScanProgressBar(self, rpc_exposed=False) + self._scan_progress_bar_full = ScanProgressBar( + self, rpc_exposed=False, rpc_passthrough_children=False + ) self._scan_progress_hover = HoverWidget( self, simple=self._scan_progress_bar_simple, full=self._scan_progress_bar_full )