Source code for stytra.gui.framerate_viewer

from PyQt5.QtCore import QPoint
from PyQt5.QtWidgets import QWidget, QLabel, QHBoxLayout, QSizePolicy, QSpacerItem
from PyQt5.QtGui import QPainter, QColor, QPen, QBrush
from PyQt5.QtCore import Qt

import numpy as np


[docs]class FramerateWidget(QWidget): def __init__(self, acc, inertia=0.985): super().__init__() self.acc = acc self.g_fps = self.acc.goal_framerate self.fps = None self.fps_inertia_max = None self.fps_inertia_min = None self.inertia = inertia self.set_fps = False self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)) self.indicator_color = (40, 230, 150) self.indicator_shadow_color = (17, 147, 91) self.error_indicator_color = (230, 40, 0) self.error_indicator_shadow_color = (170, 30, 0)
[docs] def update(self): self.set_fps = False if len(self.acc.stored_data) > 0: self.fps = self.acc.stored_data[-1] self.set_fps = self.fps is not None if self.fps_inertia_max is None: self.fps_inertia_max = self.fps self.fps_inertia_min = self.fps else: if self.fps > self.fps_inertia_max: self.fps_inertia_max = self.fps else: self.fps_inertia_max = ( self.fps_inertia_max * self.inertia + self.fps * (1 - self.inertia) ) if self.fps < self.fps_inertia_min: self.fps_inertia_min = self.fps else: self.fps_inertia_min = ( self.fps_inertia_min * self.inertia + self.fps * (1 - self.inertia) ) super().update()
[docs] def paintEvent(self, e): # Three valid cases: there are both a goal and current framerate # or either of them if self.fps is not None: if self.g_fps is not None: lb = min(self.fps_inertia_min, self.g_fps) ub = max(self.fps_inertia_max, self.g_fps) else: lb = self.fps_inertia_min ub = self.fps_inertia_max else: if self.g_fps is not None: lb = self.g_fps ub = self.g_fps else: return min_bound = np.floor(lb * 0.08) * 10 max_bound = np.ceil(ub * 0.12) * 10 delta_bound = max_bound - min_bound size = self.size() pad = 6 w = size.width() h = size.height() p = QPainter() p.begin(self) fm = p.fontMetrics() if max_bound == min_bound: max_bound += 1 limit_color = (200, 200, 200) goal_color = (80, 80, 80) if self.fps is not None and self.g_fps is not None and self.fps < self.g_fps: indicator_color = self.error_indicator_color shadow_color = self.error_indicator_shadow_color else: indicator_color = self.indicator_color shadow_color = self.indicator_shadow_color w_min = 0 w_max = w - pad delta_w = w_max - w_min text_height = 16 h_max = h - pad h_min = text_height + pad if self.set_fps and self.fps is not None: loc = (self.fps - min_bound) / delta_bound w_l = int(w_min + loc * delta_w) w_shadow_min = int( w_min + (self.fps_inertia_min - min_bound) * delta_w / delta_bound ) w_shadow_max = int( w_min + (self.fps_inertia_max - min_bound) * delta_w / delta_bound ) # Draw the inertially moving rectangle p.setPen(Qt.NoPen) p.setBrush(QBrush(QColor(*shadow_color))) l_corner = w_shadow_min w_rect = w_shadow_max - w_shadow_min p.drawRect(l_corner, h_min, w_rect, h_max - h_min) # Draw the indicator line p.setPen(QPen(QColor(*indicator_color))) p.drawLine(w_l, h_min, w_l, h_max + 5) val_str = "{:.1f}".format(self.fps) textw = fm.width(val_str) p.drawText(QPoint((w_max + w_min - textw) // 2, text_height), val_str) if self.g_fps is not None: # Draw the goal line loc_g = (self.g_fps - min_bound) / delta_bound p.setPen(QPen(QColor(*goal_color), 3)) w_l = int(w_min + loc_g * delta_w) p.drawLine(w_l, h_min, w_l, h_max) # Draw the limits p.setPen(QPen(QColor(*limit_color))) p.drawLine(w_min, h_min, w_min, h_max) p.drawLine(w_max, h_min, w_max, h_max) p.drawText(QPoint(w_min, text_height), str(min_bound)) maxst = str(max_bound) textw = fm.width(maxst) p.drawText(QPoint(w_max - textw, text_height), maxst) p.end()
[docs]class MultiFrameratesWidget(QWidget): def __init__(self): super().__init__() self.fr_widgets = [] self.setLayout(QHBoxLayout())
[docs] def update(self): for wid in self.fr_widgets: wid.update()
[docs] def add_framerate(self, framerate_acc): lbl_name = QLabel(framerate_acc.name) fr_disp = FramerateWidget(framerate_acc) if len(self.fr_widgets) > 0: self.layout().addItem(QSpacerItem(40, 10)) self.layout().addWidget(lbl_name) self.fr_widgets.append(fr_disp) self.layout().addWidget(fr_disp)
if __name__ == "__main__": from PyQt5.QtWidgets import QApplication app = QApplication([]) w = FramerateWidget() w.show() app.exec_()