Skip to content

Commit

Permalink
Merge pull request #339 from tinymovr/studio/adaptive_update
Browse files Browse the repository at this point in the history
Enable adaptive updates in studio app
  • Loading branch information
yconst authored Apr 19, 2024
2 parents b3ec7c0 + e878f42 commit 09be975
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 8 deletions.
56 changes: 52 additions & 4 deletions studio/Python/tinymovr/gui/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
QHeaderView,
QLabel,
QMessageBox,
QTreeWidgetItem,
)
from PySide6.QtGui import QAction
import pyqtgraph as pg
Expand Down Expand Up @@ -60,6 +61,7 @@

class MainWindow(QMainWindow):
TreeItemCheckedSignal = Signal(dict)
updateVisibleAttrsSignal = Signal(set)

def __init__(self, app, arguments, logger):
super(MainWindow, self).__init__()
Expand Down Expand Up @@ -101,6 +103,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()
Expand Down Expand Up @@ -160,15 +164,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()
Expand Down Expand Up @@ -210,6 +220,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):
"""
Expand Down Expand Up @@ -331,3 +354,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)
20 changes: 16 additions & 4 deletions studio/Python/tinymovr/gui/worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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()
Expand Down Expand Up @@ -78,25 +82,33 @@ 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
except Exception as e:
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()
Expand Down

0 comments on commit 09be975

Please sign in to comment.