From e878f42e7130d9ca9152559941afdcda5c6ca394 Mon Sep 17 00:00:00 2001 From: Yannis Chatzikonstantinou Date: Sat, 13 Apr 2024 02:06:06 +0300 Subject: [PATCH] update only visible items --- studio/Python/tinymovr/gui/window.py | 56 ++++++++++++++++++++++++++-- studio/Python/tinymovr/gui/worker.py | 20 ++++++++-- 2 files changed, 68 insertions(+), 8 deletions(-) diff --git a/studio/Python/tinymovr/gui/window.py b/studio/Python/tinymovr/gui/window.py index bee0cf0e..1aa40fce 100644 --- a/studio/Python/tinymovr/gui/window.py +++ b/studio/Python/tinymovr/gui/window.py @@ -33,6 +33,7 @@ QHeaderView, QLabel, QMessageBox, + QTreeWidgetItem, ) from PySide6.QtGui import QAction import pyqtgraph as pg @@ -58,6 +59,7 @@ class MainWindow(QMainWindow): TreeItemCheckedSignal = Signal(dict) + updateVisibleAttrsSignal = Signal(set) def __init__(self, app, arguments, logger): super(MainWindow, self).__init__() @@ -99,6 +101,8 @@ def __init__(self, app, arguments, logger): # Setup the tree widget self.tree_widget = PlaceholderQTreeWidget() self.tree_widget.itemChanged.connect(self.item_changed) + self.tree_widget.itemExpanded.connect(self.update_visible_attrs) + self.tree_widget.itemCollapsed.connect(self.update_visible_attrs) self.tree_widget.setHeaderLabels(["Attribute", "Value"]) self.status_label = QLabel() @@ -158,15 +162,21 @@ def __init__(self, app, arguments, logger): self.worker.updateTimingsSignal.connect( self.timings_updated, QtCore.Qt.QueuedConnection ) + self.updateVisibleAttrsSignal.connect(self.worker.update_visible_attrs) app.aboutToQuit.connect(self.about_to_quit) - self.timer = QTimer(self) - self.timer.timeout.connect(self.worker._update) - self.timer.start(40) + self.worker_update_timer = QTimer(self) + self.worker_update_timer.timeout.connect(self.worker._update) + self.worker_update_timer.start(40) + + self.visibility_update_timer = QTimer(self) + self.visibility_update_timer.timeout.connect(self.update_visible_attrs) + self.visibility_update_timer.start(1000) @QtCore.Slot() def about_to_quit(self): - self.timer.stop() + self.visibility_update_timer.stop() + self.worker_update_timer.stop() self.worker.stop() @QtCore.Slot() @@ -208,6 +218,19 @@ def add_graph_for_attr(self, attr): } self.right_layout.addWidget(graph_widget) + @QtCore.Slot() + def update_visible_attrs(self): + """ + Collects names of visible attributes and emits a signal with these names. + """ + visible_attrs = { + attr_name + for attr_name, widget_info in self.attr_widgets_by_id.items() + if self.is_widget_visible(widget_info["widget"]) + and self.is_item_visible_in_viewport(widget_info["widget"]) + } + self.updateVisibleAttrsSignal.emit(visible_attrs) + @QtCore.Slot() def regen_tree(self, devices_by_name): """ @@ -326,3 +349,28 @@ def show_about_box(self): app_str ), ) + + def is_widget_visible(self, widget): + """ + Check if the given widget is visible, i.e., not hidden and all its + ancestor widgets are expanded. + """ + if widget.isHidden(): + return False + parent = widget.parent() + while parent is not None: + if isinstance(parent, QTreeWidgetItem) and not parent.isExpanded(): + return False + parent = parent.parent() + return True + + def is_item_visible_in_viewport(self, item): + """ + Check if the QTreeWidgetItem is visible in the viewport of the QTreeWidget. + """ + # Get the item's rectangle in tree widget coordinates + rect = self.tree_widget.visualItemRect(item) + + # Check if the rectangle is within the visible region of the tree widget + visible_region = self.tree_widget.visibleRegion() + return visible_region.contains(rect) diff --git a/studio/Python/tinymovr/gui/worker.py b/studio/Python/tinymovr/gui/worker.py index 3932d9a6..4d658bdf 100644 --- a/studio/Python/tinymovr/gui/worker.py +++ b/studio/Python/tinymovr/gui/worker.py @@ -32,7 +32,7 @@ class Worker(QObject): regenSignal = QtCore.Signal(dict) handleErrorSignal = QtCore.Signal(object) - def __init__(self, busparams, logger): + def __init__(self, busparams, logger, refresh_period=0.3): super().__init__() self.logger = logger self.mutx = QtCore.QMutex() @@ -43,10 +43,14 @@ def __init__(self, busparams, logger): ) self.timed_getter = TimedGetter() + self.refresh_period = refresh_period + self.dt_update = 1 self.dt_load = 0 self.t_last_update = time.time() + self.visible_attrs = set() + @QtCore.Slot() def stop(self): destroy_tee() @@ -78,18 +82,19 @@ def _get_attr_values(self): except Exception as e: self.handleErrorSignal.emit(e) start_time = time.time() - self.dynamic_attrs.sort( + attrs_to_update = [attr for attr in self.dynamic_attrs if attr.full_name in self.visible_attrs] + attrs_to_update.sort( key=lambda attr: self.dynamic_attrs_last_update[attr.full_name] if attr.full_name in self.dynamic_attrs_last_update else 0 ) - for attr in self.dynamic_attrs: + for attr in attrs_to_update: t = ( self.dynamic_attrs_last_update[attr.full_name] if attr.full_name in self.dynamic_attrs_last_update else 0 ) - if (attr.full_name not in vals) and (start_time - t > 0.5): + if (attr.full_name not in vals) and (start_time - t > self.refresh_period): try: vals[attr.full_name] = self.timed_getter.get_value(attr.get_value) self.dynamic_attrs_last_update[attr.full_name] = start_time @@ -97,6 +102,13 @@ def _get_attr_values(self): self.handleErrorSignal.emit(e) break return vals + + @QtCore.Slot(set) + def update_visible_attrs(self, attrs): + """ + Update the set of visible attributes based on the signal from the main window. + """ + self.visible_attrs = attrs def _init_containers(self): self.active_attrs = set()