diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d656c0a..4d06c23 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ on: jobs: check-style: name: Find Trailing Whitespace - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - name: Find Trailing Whitespace @@ -23,42 +23,3 @@ jobs: exit 1 fi exit 0 - - build: - name: Generate python files from ui - runs-on: ubuntu-22.04 - steps: - - uses: actions/checkout@v4 - - name: Remove broken apt repos [Ubuntu] - run: | - for apt_file in `grep -lr microsoft /etc/apt/sources.list.d/`; do sudo rm $apt_file; done - - name: Dependencies [Ubuntu] - run: | - sudo apt update - sudo apt install -y pyqt5-dev-tools - - name: Generate python files - run: | - bash ./generate-ui.sh - - - name: Archive artifacts - uses: actions/upload-artifact@v4 - with: - name: autogenerated_files - path: robot_log_visualizer/ui/autogenerated - - deploy: - runs-on: ubuntu-22.04 - needs: [build] - if: github.ref == 'refs/heads/main' - steps: - - uses: actions/checkout@v4 - - - name: Download artifacts - uses: actions/download-artifact@v4 - with: - name: autogenerated_files - path: robot_log_visualizer/ui/autogenerated - - name: Deploy - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: ⚙️ Automatic update of the python UI classes diff --git a/generate-ui.sh b/generate-ui.sh deleted file mode 100755 index a85013c..0000000 --- a/generate-ui.sh +++ /dev/null @@ -1,13 +0,0 @@ -#! /bin/bash -echo "Generate the main window" -pyuic5 -o robot_log_visualizer/ui/autogenerated/visualizer.py robot_log_visualizer/ui/misc/visualizer.ui - -echo "Generate Additional windows" -pyuic5 -o robot_log_visualizer/ui/autogenerated/about.py robot_log_visualizer/ui/misc/about.ui -pyuic5 -o robot_log_visualizer/ui/autogenerated/set_robot_model.py robot_log_visualizer/ui/misc/set_robot_model.ui - -echo "Generate tab" -pyuic5 -o robot_log_visualizer/ui/autogenerated/plot_tab.py robot_log_visualizer/ui/misc/plot_tab.ui -pyuic5 -o robot_log_visualizer/ui/autogenerated/video_tab.py robot_log_visualizer/ui/misc/video_tab.ui - -echo "The ui is generated" diff --git a/robot_log_visualizer/__init__.py b/robot_log_visualizer/__init__.py index e69de29..88cb257 100644 --- a/robot_log_visualizer/__init__.py +++ b/robot_log_visualizer/__init__.py @@ -0,0 +1,4 @@ +import os + +# Prefer the PySide6 backend when QtPy resolves the Qt binding. +os.environ.setdefault("QT_API", "pyside2") diff --git a/robot_log_visualizer/__main__.py b/robot_log_visualizer/__main__.py index 7027c7a..6e7196f 100755 --- a/robot_log_visualizer/__main__.py +++ b/robot_log_visualizer/__main__.py @@ -7,8 +7,8 @@ import sys # GUI +from qtpy.QtWidgets import QApplication from robot_log_visualizer.ui.gui import RobotViewerMainWindow -from PyQt5.QtWidgets import QApplication # Meshcat from robot_log_visualizer.robot_visualizer.meshcat_provider import MeshcatProvider @@ -36,7 +36,11 @@ def main(): # show the main window gui.show() - return app.exec_() + exec_method = getattr(app, "exec", None) + if exec_method is None: + exec_method = app.exec_ + + return exec_method() if __name__ == "__main__": diff --git a/robot_log_visualizer/plotter/pyqtgraph_viewer_canvas.py b/robot_log_visualizer/plotter/pyqtgraph_viewer_canvas.py index 4d7a6ea..7704f31 100644 --- a/robot_log_visualizer/plotter/pyqtgraph_viewer_canvas.py +++ b/robot_log_visualizer/plotter/pyqtgraph_viewer_canvas.py @@ -8,7 +8,7 @@ import numpy as np import pyqtgraph as pg # type: ignore -from PyQt5 import QtCore, QtWidgets # type: ignore +from qtpy import QtCore, QtWidgets # type: ignore from robot_log_visualizer.plotter.color_palette import ColorPalette from robot_log_visualizer.signal_provider.signal_provider import ProviderType diff --git a/robot_log_visualizer/robot_visualizer/meshcat_provider.py b/robot_log_visualizer/robot_visualizer/meshcat_provider.py index 5efb0be..dad2a36 100644 --- a/robot_log_visualizer/robot_visualizer/meshcat_provider.py +++ b/robot_log_visualizer/robot_visualizer/meshcat_provider.py @@ -10,7 +10,7 @@ import idyntree.swig as idyn import numpy as np from idyntree.visualize import MeshcatVisualizer -from PyQt5.QtCore import QMutex, QMutexLocker, QThread +from qtpy.QtCore import QMutex, QMutexLocker, QThread from robot_log_visualizer.utils.utils import PeriodicThreadState diff --git a/robot_log_visualizer/signal_provider/realtime_signal_provider.py b/robot_log_visualizer/signal_provider/realtime_signal_provider.py index a6479c7..d41c6c0 100644 --- a/robot_log_visualizer/signal_provider/realtime_signal_provider.py +++ b/robot_log_visualizer/signal_provider/realtime_signal_provider.py @@ -5,6 +5,7 @@ import time import traceback from collections import deque +from typing import Iterable, Union import numpy as np @@ -117,7 +118,7 @@ def __init__(self, period: float, signal_root_name: str): self.buffered_signals.add("robot_realtime::joints_state::positions") # TODO: implement a logic to remove signals that are not needed anymore - def add_signals_to_buffer(self, signals: list | set | str): + def add_signals_to_buffer(self, signals: Union[str, Iterable[str]]): """Add signals to the buffer set.""" if isinstance(signals, str): signals = {signals} diff --git a/robot_log_visualizer/signal_provider/signal_provider.py b/robot_log_visualizer/signal_provider/signal_provider.py index e18efc1..285fb49 100644 --- a/robot_log_visualizer/signal_provider/signal_provider.py +++ b/robot_log_visualizer/signal_provider/signal_provider.py @@ -9,7 +9,9 @@ import h5py import idyntree.swig as idyn import numpy as np -from PyQt5.QtCore import QMutex, QMutexLocker, QThread, pyqtSignal +from qtpy.QtCore import QMutex, QMutexLocker, QThread, Signal + +pyqtSignal = Signal from robot_log_visualizer.utils.utils import PeriodicThreadState, RobotStatePath diff --git a/robot_log_visualizer/ui/autogenerated/__init__.py b/robot_log_visualizer/ui/autogenerated/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/robot_log_visualizer/ui/autogenerated/about.py b/robot_log_visualizer/ui/autogenerated/about.py deleted file mode 100644 index d9a94e7..0000000 --- a/robot_log_visualizer/ui/autogenerated/about.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: utf-8 -*- - -# Form implementation generated from reading ui file 'robot_log_visualizer/ui/misc/about.ui' -# -# Created by: PyQt5 UI code generator 5.15.6 -# -# WARNING: Any manual changes made to this file will be lost when pyuic5 is -# run again. Do not edit this file unless you know what you are doing. - - -from PyQt5 import QtCore, QtGui, QtWidgets - - -class Ui_aboutWindow(object): - def setupUi(self, aboutWindow): - aboutWindow.setObjectName("aboutWindow") - aboutWindow.resize(541, 102) - aboutWindow.setMaximumSize(QtCore.QSize(541, 102)) - self.centralwidget = QtWidgets.QWidget(aboutWindow) - self.centralwidget.setObjectName("centralwidget") - self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget) - self.horizontalLayout.setObjectName("horizontalLayout") - self.label_2 = QtWidgets.QLabel(self.centralwidget) - self.label_2.setEnabled(True) - self.label_2.setOpenExternalLinks(True) - self.label_2.setObjectName("label_2") - self.horizontalLayout.addWidget(self.label_2) - aboutWindow.setCentralWidget(self.centralwidget) - - self.retranslateUi(aboutWindow) - QtCore.QMetaObject.connectSlotsByName(aboutWindow) - - def retranslateUi(self, aboutWindow): - _translate = QtCore.QCoreApplication.translate - aboutWindow.setWindowTitle(_translate("aboutWindow", "Robot Log Visualizer - About")) - self.label_2.setText(_translate("aboutWindow", "

About Robot Log Visualizer

This program is Licensed under the 3-Clause BSD License

The project is mantained by the Artificial and Mechanical Intelligence lab

")) diff --git a/robot_log_visualizer/ui/autogenerated/plot_tab.py b/robot_log_visualizer/ui/autogenerated/plot_tab.py deleted file mode 100644 index 871104a..0000000 --- a/robot_log_visualizer/ui/autogenerated/plot_tab.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- - -# Form implementation generated from reading ui file 'robot_log_visualizer/ui/misc/plot_tab.ui' -# -# Created by: PyQt5 UI code generator 5.15.6 -# -# WARNING: Any manual changes made to this file will be lost when pyuic5 is -# run again. Do not edit this file unless you know what you are doing. - - -from PyQt5 import QtCore, QtGui, QtWidgets - - -class Ui_PlotTab(object): - def setupUi(self, PlotTab): - PlotTab.setObjectName("PlotTab") - PlotTab.resize(331, 149) - self.horizontalLayout = QtWidgets.QHBoxLayout(PlotTab) - self.horizontalLayout.setObjectName("horizontalLayout") - self.plotLayout = QtWidgets.QVBoxLayout() - self.plotLayout.setObjectName("plotLayout") - self.horizontalLayout.addLayout(self.plotLayout) - - self.retranslateUi(PlotTab) - QtCore.QMetaObject.connectSlotsByName(PlotTab) - - def retranslateUi(self, PlotTab): - _translate = QtCore.QCoreApplication.translate - PlotTab.setWindowTitle(_translate("PlotTab", "Form")) diff --git a/robot_log_visualizer/ui/autogenerated/set_robot_model.py b/robot_log_visualizer/ui/autogenerated/set_robot_model.py deleted file mode 100644 index 2c45f50..0000000 --- a/robot_log_visualizer/ui/autogenerated/set_robot_model.py +++ /dev/null @@ -1,130 +0,0 @@ -# -*- coding: utf-8 -*- - -# Form implementation generated from reading ui file 'robot_log_visualizer/ui/misc/set_robot_model.ui' -# -# Created by: PyQt5 UI code generator 5.15.6 -# -# WARNING: Any manual changes made to this file will be lost when pyuic5 is -# run again. Do not edit this file unless you know what you are doing. - - -from PyQt5 import QtCore, QtGui, QtWidgets - - -class Ui_setRobotModelDialog(object): - def setupUi(self, setRobotModelDialog): - setRobotModelDialog.setObjectName("setRobotModelDialog") - setRobotModelDialog.resize(711, 363) - self.gridLayout = QtWidgets.QGridLayout(setRobotModelDialog) - self.gridLayout.setObjectName("gridLayout") - spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.gridLayout.addItem(spacerItem, 1, 0, 1, 1) - self.buttonBox = QtWidgets.QDialogButtonBox(setRobotModelDialog) - self.buttonBox.setOrientation(QtCore.Qt.Horizontal) - self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Close|QtWidgets.QDialogButtonBox.Save|QtWidgets.QDialogButtonBox.SaveAll) - self.buttonBox.setObjectName("buttonBox") - self.gridLayout.addWidget(self.buttonBox, 2, 0, 1, 1) - self.tabWidget = QtWidgets.QTabWidget(setRobotModelDialog) - self.tabWidget.setObjectName("tabWidget") - self.robot_tab = QtWidgets.QWidget() - self.robot_tab.setObjectName("robot_tab") - self.verticalLayout = QtWidgets.QVBoxLayout(self.robot_tab) - self.verticalLayout.setObjectName("verticalLayout") - self.frame = QtWidgets.QFrame(self.robot_tab) - self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel) - self.frame.setObjectName("frame") - self.gridLayout_2 = QtWidgets.QGridLayout(self.frame) - self.gridLayout_2.setObjectName("gridLayout_2") - self.robotModelToolButton = QtWidgets.QToolButton(self.frame) - self.robotModelToolButton.setObjectName("robotModelToolButton") - self.gridLayout_2.addWidget(self.robotModelToolButton, 1, 1, 1, 1) - self.label = QtWidgets.QLabel(self.frame) - self.label.setObjectName("label") - self.gridLayout_2.addWidget(self.label, 0, 0, 1, 1) - self.robotModelLineEdit = QtWidgets.QLineEdit(self.frame) - font = QtGui.QFont() - font.setFamily("Ubuntu Mono") - self.robotModelLineEdit.setFont(font) - self.robotModelLineEdit.setObjectName("robotModelLineEdit") - self.gridLayout_2.addWidget(self.robotModelLineEdit, 1, 0, 1, 1) - self.verticalLayout.addWidget(self.frame) - self.frame_2 = QtWidgets.QFrame(self.robot_tab) - self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel) - self.frame_2.setObjectName("frame_2") - self.gridLayout_3 = QtWidgets.QGridLayout(self.frame_2) - self.gridLayout_3.setObjectName("gridLayout_3") - self.packageDirToolButton = QtWidgets.QToolButton(self.frame_2) - self.packageDirToolButton.setObjectName("packageDirToolButton") - self.gridLayout_3.addWidget(self.packageDirToolButton, 1, 1, 1, 1) - self.label_3 = QtWidgets.QLabel(self.frame_2) - self.label_3.setObjectName("label_3") - self.gridLayout_3.addWidget(self.label_3, 0, 0, 1, 1) - self.packageDirLineEdit = QtWidgets.QLineEdit(self.frame_2) - font = QtGui.QFont() - font.setFamily("Ubuntu Mono") - self.packageDirLineEdit.setFont(font) - self.packageDirLineEdit.setObjectName("packageDirLineEdit") - self.gridLayout_3.addWidget(self.packageDirLineEdit, 1, 0, 1, 1) - self.verticalLayout.addWidget(self.frame_2) - self.frame_3 = QtWidgets.QFrame(self.robot_tab) - self.frame_3.setFrameShape(QtWidgets.QFrame.StyledPanel) - self.frame_3.setObjectName("frame_3") - self.formLayout_2 = QtWidgets.QFormLayout(self.frame_3) - self.formLayout_2.setObjectName("formLayout_2") - self.label_5 = QtWidgets.QLabel(self.frame_3) - self.label_5.setObjectName("label_5") - self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_5) - self.frameNameComboBox = QtWidgets.QComboBox(self.frame_3) - self.frameNameComboBox.setMaxVisibleItems(5) - self.frameNameComboBox.setObjectName("frameNameComboBox") - self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.SpanningRole, self.frameNameComboBox) - self.verticalLayout.addWidget(self.frame_3) - self.tabWidget.addTab(self.robot_tab, "") - self.mischellanea_tab = QtWidgets.QWidget() - self.mischellanea_tab.setObjectName("mischellanea_tab") - self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.mischellanea_tab) - self.verticalLayout_2.setObjectName("verticalLayout_2") - self.frame_4 = QtWidgets.QFrame(self.mischellanea_tab) - self.frame_4.setFrameShape(QtWidgets.QFrame.StyledPanel) - self.frame_4.setFrameShadow(QtWidgets.QFrame.Raised) - self.frame_4.setObjectName("frame_4") - self.gridLayout_4 = QtWidgets.QGridLayout(self.frame_4) - self.gridLayout_4.setObjectName("gridLayout_4") - self.label_2 = QtWidgets.QLabel(self.frame_4) - self.label_2.setObjectName("label_2") - self.gridLayout_4.addWidget(self.label_2, 0, 0, 1, 1) - self.arrowScaling_lineEdit = QtWidgets.QLineEdit(self.frame_4) - self.arrowScaling_lineEdit.setEnabled(False) - self.arrowScaling_lineEdit.setReadOnly(False) - self.arrowScaling_lineEdit.setClearButtonEnabled(False) - self.arrowScaling_lineEdit.setObjectName("arrowScaling_lineEdit") - self.gridLayout_4.addWidget(self.arrowScaling_lineEdit, 0, 1, 1, 1) - self.arrowScaling_checkBox = QtWidgets.QCheckBox(self.frame_4) - self.arrowScaling_checkBox.setChecked(True) - self.arrowScaling_checkBox.setTristate(False) - self.arrowScaling_checkBox.setObjectName("arrowScaling_checkBox") - self.gridLayout_4.addWidget(self.arrowScaling_checkBox, 0, 2, 1, 1) - self.verticalLayout_2.addWidget(self.frame_4) - spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.verticalLayout_2.addItem(spacerItem1) - self.tabWidget.addTab(self.mischellanea_tab, "") - self.gridLayout.addWidget(self.tabWidget, 0, 0, 1, 1) - - self.retranslateUi(setRobotModelDialog) - self.tabWidget.setCurrentIndex(0) - self.buttonBox.accepted.connect(setRobotModelDialog.accept) # type: ignore - self.buttonBox.rejected.connect(setRobotModelDialog.reject) # type: ignore - QtCore.QMetaObject.connectSlotsByName(setRobotModelDialog) - - def retranslateUi(self, setRobotModelDialog): - _translate = QtCore.QCoreApplication.translate - setRobotModelDialog.setWindowTitle(_translate("setRobotModelDialog", "Dialog")) - self.robotModelToolButton.setText(_translate("setRobotModelDialog", "...")) - self.label.setText(_translate("setRobotModelDialog", "Robot Model")) - self.packageDirToolButton.setText(_translate("setRobotModelDialog", "...")) - self.label_3.setText(_translate("setRobotModelDialog", "Package Directory")) - self.label_5.setText(_translate("setRobotModelDialog", "Base Frame")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.robot_tab), _translate("setRobotModelDialog", "Robot")) - self.label_2.setText(_translate("setRobotModelDialog", "Arrow scaling")) - self.arrowScaling_checkBox.setText(_translate("setRobotModelDialog", "Automatic")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.mischellanea_tab), _translate("setRobotModelDialog", "Miscellanea")) diff --git a/robot_log_visualizer/ui/autogenerated/video_tab.py b/robot_log_visualizer/ui/autogenerated/video_tab.py deleted file mode 100644 index b43318e..0000000 --- a/robot_log_visualizer/ui/autogenerated/video_tab.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- - -# Form implementation generated from reading ui file 'robot_log_visualizer/ui/misc/video_tab.ui' -# -# Created by: PyQt5 UI code generator 5.15.6 -# -# WARNING: Any manual changes made to this file will be lost when pyuic5 is -# run again. Do not edit this file unless you know what you are doing. - - -from PyQt5 import QtCore, QtGui, QtWidgets - - -class Ui_VideoTab(object): - def setupUi(self, VideoTab): - VideoTab.setObjectName("VideoTab") - VideoTab.resize(400, 300) - self.horizontalLayout = QtWidgets.QHBoxLayout(VideoTab) - self.horizontalLayout.setObjectName("horizontalLayout") - self.webcamView = QVideoWidget(VideoTab) - self.webcamView.setObjectName("webcamView") - self.horizontalLayout.addWidget(self.webcamView) - - self.retranslateUi(VideoTab) - QtCore.QMetaObject.connectSlotsByName(VideoTab) - - def retranslateUi(self, VideoTab): - _translate = QtCore.QCoreApplication.translate - VideoTab.setWindowTitle(_translate("VideoTab", "Form")) -from PyQt5.QtMultimediaWidgets import QVideoWidget diff --git a/robot_log_visualizer/ui/autogenerated/visualizer.py b/robot_log_visualizer/ui/autogenerated/visualizer.py deleted file mode 100644 index 3ba96b8..0000000 --- a/robot_log_visualizer/ui/autogenerated/visualizer.py +++ /dev/null @@ -1,287 +0,0 @@ -# -*- coding: utf-8 -*- - -# Form implementation generated from reading ui file 'robot_log_visualizer/ui/misc/visualizer.ui' -# -# Created by: PyQt5 UI code generator 5.15.6 -# -# WARNING: Any manual changes made to this file will be lost when pyuic5 is -# run again. Do not edit this file unless you know what you are doing. - - -from PyQt5 import QtCore, QtGui, QtWidgets - - -class Ui_MainWindow(object): - def setupUi(self, MainWindow): - MainWindow.setObjectName("MainWindow") - MainWindow.resize(929, 908) - MainWindow.setAcceptDrops(True) - self.centralwidget = QtWidgets.QWidget(MainWindow) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth()) - self.centralwidget.setSizePolicy(sizePolicy) - self.centralwidget.setObjectName("centralwidget") - self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget) - self.verticalLayout.setObjectName("verticalLayout") - self.splitter_2 = QtWidgets.QSplitter(self.centralwidget) - self.splitter_2.setOrientation(QtCore.Qt.Vertical) - self.splitter_2.setChildrenCollapsible(False) - self.splitter_2.setObjectName("splitter_2") - self.dataVisualizationFrame = QtWidgets.QFrame(self.splitter_2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(2) - sizePolicy.setHeightForWidth(self.dataVisualizationFrame.sizePolicy().hasHeightForWidth()) - self.dataVisualizationFrame.setSizePolicy(sizePolicy) - self.dataVisualizationFrame.setMaximumSize(QtCore.QSize(16777215, 16777215)) - self.dataVisualizationFrame.setFrameShape(QtWidgets.QFrame.NoFrame) - self.dataVisualizationFrame.setObjectName("dataVisualizationFrame") - self.gridLayout_3 = QtWidgets.QGridLayout(self.dataVisualizationFrame) - self.gridLayout_3.setContentsMargins(-1, 9, -1, -1) - self.gridLayout_3.setObjectName("gridLayout_3") - self.pauseButton = QtWidgets.QPushButton(self.dataVisualizationFrame) - self.pauseButton.setEnabled(False) - self.pauseButton.setMaximumSize(QtCore.QSize(40, 16777215)) - self.pauseButton.setText("") - icon = QtGui.QIcon.fromTheme("media-playback-pause") - self.pauseButton.setIcon(icon) - self.pauseButton.setCheckable(False) - self.pauseButton.setDefault(False) - self.pauseButton.setFlat(False) - self.pauseButton.setObjectName("pauseButton") - self.gridLayout_3.addWidget(self.pauseButton, 1, 4, 1, 1) - self.timeSlider = QtWidgets.QSlider(self.dataVisualizationFrame) - self.timeSlider.setEnabled(False) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.timeSlider.sizePolicy().hasHeightForWidth()) - self.timeSlider.setSizePolicy(sizePolicy) - self.timeSlider.setPageStep(1) - self.timeSlider.setTracking(True) - self.timeSlider.setOrientation(QtCore.Qt.Horizontal) - self.timeSlider.setObjectName("timeSlider") - self.gridLayout_3.addWidget(self.timeSlider, 1, 1, 1, 2) - self.startButton = QtWidgets.QPushButton(self.dataVisualizationFrame) - self.startButton.setEnabled(False) - self.startButton.setMaximumSize(QtCore.QSize(40, 16777215)) - self.startButton.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) - self.startButton.setText("") - icon = QtGui.QIcon.fromTheme("media-playback-start") - self.startButton.setIcon(icon) - self.startButton.setObjectName("startButton") - self.gridLayout_3.addWidget(self.startButton, 1, 3, 1, 1) - self.timeLabel = QtWidgets.QLabel(self.dataVisualizationFrame) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Ignored) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.timeLabel.sizePolicy().hasHeightForWidth()) - self.timeLabel.setSizePolicy(sizePolicy) - self.timeLabel.setMinimumSize(QtCore.QSize(60, 0)) - self.timeLabel.setObjectName("timeLabel") - self.gridLayout_3.addWidget(self.timeLabel, 1, 0, 1, 1) - self.splitter = QtWidgets.QSplitter(self.dataVisualizationFrame) - self.splitter.setOrientation(QtCore.Qt.Horizontal) - self.splitter.setChildrenCollapsible(True) - self.splitter.setObjectName("splitter") - self.variableTreeWidget = QtWidgets.QTreeWidget(self.splitter) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.variableTreeWidget.sizePolicy().hasHeightForWidth()) - self.variableTreeWidget.setSizePolicy(sizePolicy) - self.variableTreeWidget.setMaximumSize(QtCore.QSize(16777215, 16777215)) - self.variableTreeWidget.setSizeIncrement(QtCore.QSize(0, 0)) - self.variableTreeWidget.setBaseSize(QtCore.QSize(0, 0)) - self.variableTreeWidget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) - self.variableTreeWidget.setFrameShape(QtWidgets.QFrame.Box) - self.variableTreeWidget.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection) - self.variableTreeWidget.setAnimated(True) - self.variableTreeWidget.setObjectName("variableTreeWidget") - self.variableTreeWidget.header().setVisible(False) - self.variableTreeWidget.header().setDefaultSectionSize(100) - self.tabPlotWidget = QtWidgets.QTabWidget(self.splitter) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.tabPlotWidget.sizePolicy().hasHeightForWidth()) - self.tabPlotWidget.setSizePolicy(sizePolicy) - self.tabPlotWidget.setTabsClosable(True) - self.tabPlotWidget.setMovable(False) - self.tabPlotWidget.setTabBarAutoHide(False) - self.tabPlotWidget.setObjectName("tabPlotWidget") - self.meshcatAndVideoTab = QtWidgets.QTabWidget(self.splitter) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) - sizePolicy.setHorizontalStretch(2) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.meshcatAndVideoTab.sizePolicy().hasHeightForWidth()) - self.meshcatAndVideoTab.setSizePolicy(sizePolicy) - self.meshcatAndVideoTab.setTabPosition(QtWidgets.QTabWidget.East) - self.meshcatAndVideoTab.setDocumentMode(False) - self.meshcatAndVideoTab.setObjectName("meshcatAndVideoTab") - self.meshcatTab = QtWidgets.QWidget() - self.meshcatTab.setObjectName("meshcatTab") - self.horizontalLayout = QtWidgets.QHBoxLayout(self.meshcatTab) - self.horizontalLayout.setObjectName("horizontalLayout") - self.meshcatView = QtWebEngineWidgets.QWebEngineView(self.meshcatTab) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.meshcatView.sizePolicy().hasHeightForWidth()) - self.meshcatView.setSizePolicy(sizePolicy) - self.meshcatView.setObjectName("meshcatView") - self.horizontalLayout.addWidget(self.meshcatView) - icon = QtGui.QIcon.fromTheme("input-gaming") - self.meshcatAndVideoTab.addTab(self.meshcatTab, icon, "") - self.gridLayout_3.addWidget(self.splitter, 0, 0, 1, 5) - self.tabWidget = QtWidgets.QTabWidget(self.splitter_2) - self.tabWidget.setMinimumSize(QtCore.QSize(0, 0)) - self.tabWidget.setAutoFillBackground(False) - self.tabWidget.setTabPosition(QtWidgets.QTabWidget.West) - self.tabWidget.setUsesScrollButtons(False) - self.tabWidget.setDocumentMode(False) - self.tabWidget.setTabsClosable(False) - self.tabWidget.setMovable(True) - self.tabWidget.setObjectName("tabWidget") - self.yarpTextLogWidget = QtWidgets.QWidget() - self.yarpTextLogWidget.setObjectName("yarpTextLogWidget") - self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.yarpTextLogWidget) - self.verticalLayout_3.setObjectName("verticalLayout_3") - self.splitter_3 = QtWidgets.QSplitter(self.yarpTextLogWidget) - self.splitter_3.setOrientation(QtCore.Qt.Horizontal) - self.splitter_3.setObjectName("splitter_3") - self.yarpTextLogTreeWidget = QtWidgets.QTreeWidget(self.splitter_3) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.yarpTextLogTreeWidget.sizePolicy().hasHeightForWidth()) - self.yarpTextLogTreeWidget.setSizePolicy(sizePolicy) - self.yarpTextLogTreeWidget.setMaximumSize(QtCore.QSize(16777215, 16777215)) - self.yarpTextLogTreeWidget.setSizeIncrement(QtCore.QSize(0, 0)) - self.yarpTextLogTreeWidget.setBaseSize(QtCore.QSize(0, 0)) - self.yarpTextLogTreeWidget.setFrameShape(QtWidgets.QFrame.Box) - self.yarpTextLogTreeWidget.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) - self.yarpTextLogTreeWidget.setAnimated(True) - self.yarpTextLogTreeWidget.setObjectName("yarpTextLogTreeWidget") - self.yarpTextLogTreeWidget.header().setVisible(False) - self.yarpTextLogTreeWidget.header().setDefaultSectionSize(100) - self.yarpTextLogTableWidget = QtWidgets.QTableWidget(self.splitter_3) - self.yarpTextLogTableWidget.setEnabled(True) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) - sizePolicy.setHorizontalStretch(10) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.yarpTextLogTableWidget.sizePolicy().hasHeightForWidth()) - self.yarpTextLogTableWidget.setSizePolicy(sizePolicy) - self.yarpTextLogTableWidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) - self.yarpTextLogTableWidget.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustIgnored) - self.yarpTextLogTableWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) - self.yarpTextLogTableWidget.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection) - self.yarpTextLogTableWidget.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel) - self.yarpTextLogTableWidget.setShowGrid(False) - self.yarpTextLogTableWidget.setGridStyle(QtCore.Qt.NoPen) - self.yarpTextLogTableWidget.setObjectName("yarpTextLogTableWidget") - self.yarpTextLogTableWidget.setColumnCount(0) - self.yarpTextLogTableWidget.setRowCount(0) - self.yarpTextLogTableWidget.horizontalHeader().setVisible(False) - self.yarpTextLogTableWidget.verticalHeader().setVisible(False) - self.verticalLayout_3.addWidget(self.splitter_3) - icon = QtGui.QIcon.fromTheme("zoom-in") - self.tabWidget.addTab(self.yarpTextLogWidget, icon, "") - self.pythonWidget = QtWidgets.QWidget() - self.pythonWidget.setAutoFillBackground(False) - self.pythonWidget.setObjectName("pythonWidget") - self.pythonWidgetLayout = QtWidgets.QVBoxLayout(self.pythonWidget) - self.pythonWidgetLayout.setObjectName("pythonWidgetLayout") - icon = QtGui.QIcon.fromTheme("terminal") - self.tabWidget.addTab(self.pythonWidget, icon, "") - self.tab_5 = QtWidgets.QWidget() - self.tab_5.setObjectName("tab_5") - self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.tab_5) - self.verticalLayout_2.setObjectName("verticalLayout_2") - self.logScrollArea = QtWidgets.QScrollArea(self.tab_5) - self.logScrollArea.setMinimumSize(QtCore.QSize(0, 120)) - self.logScrollArea.setAutoFillBackground(False) - self.logScrollArea.setStyleSheet("background: white") - self.logScrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) - self.logScrollArea.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents) - self.logScrollArea.setWidgetResizable(True) - self.logScrollArea.setObjectName("logScrollArea") - self.logScrollAreaWidgetContents = QtWidgets.QWidget() - self.logScrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 860, 190)) - self.logScrollAreaWidgetContents.setObjectName("logScrollAreaWidgetContents") - self.gridLayout = QtWidgets.QGridLayout(self.logScrollAreaWidgetContents) - self.gridLayout.setObjectName("gridLayout") - spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.gridLayout.addItem(spacerItem, 2, 0, 1, 1) - self.logLabel = QtWidgets.QLabel(self.logScrollAreaWidgetContents) - self.logLabel.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) - self.logLabel.setText("") - self.logLabel.setObjectName("logLabel") - self.gridLayout.addWidget(self.logLabel, 1, 0, 1, 1) - self.logScrollArea.setWidget(self.logScrollAreaWidgetContents) - self.verticalLayout_2.addWidget(self.logScrollArea) - icon = QtGui.QIcon.fromTheme("document") - self.tabWidget.addTab(self.tab_5, icon, "") - self.verticalLayout.addWidget(self.splitter_2) - MainWindow.setCentralWidget(self.centralwidget) - self.menubar = QtWidgets.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 929, 22)) - self.menubar.setObjectName("menubar") - self.menuFile = QtWidgets.QMenu(self.menubar) - self.menuFile.setObjectName("menuFile") - self.menuHelp = QtWidgets.QMenu(self.menubar) - self.menuHelp.setObjectName("menuHelp") - self.menuEdit = QtWidgets.QMenu(self.menubar) - self.menuEdit.setObjectName("menuEdit") - MainWindow.setMenuBar(self.menubar) - self.actionQuit = QtWidgets.QAction(MainWindow) - icon = QtGui.QIcon.fromTheme("exit") - self.actionQuit.setIcon(icon) - self.actionQuit.setObjectName("actionQuit") - self.actionOpen = QtWidgets.QAction(MainWindow) - icon = QtGui.QIcon.fromTheme("document-open") - self.actionOpen.setIcon(icon) - self.actionOpen.setObjectName("actionOpen") - self.actionAbout = QtWidgets.QAction(MainWindow) - self.actionAbout.setObjectName("actionAbout") - self.actionSet_Robot_Model = QtWidgets.QAction(MainWindow) - self.actionSet_Robot_Model.setObjectName("actionSet_Robot_Model") - self.actionRealtime_Connect = QtWidgets.QAction(MainWindow) - self.actionRealtime_Connect.setObjectName("actionRealtime_Connect") - self.menuFile.addAction(self.actionOpen) - self.menuFile.addAction(self.actionRealtime_Connect) - self.menuFile.addSeparator() - self.menuFile.addAction(self.actionQuit) - self.menuHelp.addAction(self.actionAbout) - self.menuEdit.addAction(self.actionSet_Robot_Model) - self.menubar.addAction(self.menuFile.menuAction()) - self.menubar.addAction(self.menuEdit.menuAction()) - self.menubar.addAction(self.menuHelp.menuAction()) - - self.retranslateUi(MainWindow) - self.tabPlotWidget.setCurrentIndex(-1) - self.meshcatAndVideoTab.setCurrentIndex(0) - self.tabWidget.setCurrentIndex(0) - QtCore.QMetaObject.connectSlotsByName(MainWindow) - - def retranslateUi(self, MainWindow): - _translate = QtCore.QCoreApplication.translate - MainWindow.setWindowTitle(_translate("MainWindow", "Robot Log Visualizer")) - self.timeLabel.setText(_translate("MainWindow", "0.0")) - self.variableTreeWidget.headerItem().setText(0, _translate("MainWindow", "Variables")) - self.yarpTextLogTreeWidget.headerItem().setText(0, _translate("MainWindow", "Variables")) - self.yarpTextLogTableWidget.setSortingEnabled(False) - self.menuFile.setTitle(_translate("MainWindow", "&File")) - self.menuHelp.setTitle(_translate("MainWindow", "Help")) - self.menuEdit.setTitle(_translate("MainWindow", "&Edit")) - self.actionQuit.setText(_translate("MainWindow", "&Quit")) - self.actionQuit.setShortcut(_translate("MainWindow", "Ctrl+Q")) - self.actionOpen.setText(_translate("MainWindow", "&Open")) - self.actionOpen.setShortcut(_translate("MainWindow", "Ctrl+O")) - self.actionAbout.setText(_translate("MainWindow", "About")) - self.actionSet_Robot_Model.setText(_translate("MainWindow", "Options")) - self.actionRealtime_Connect.setText(_translate("MainWindow", "Realtime Connect")) - self.actionRealtime_Connect.setShortcut(_translate("MainWindow", "Ctrl+R")) -from PyQt5 import QtWebEngineWidgets diff --git a/robot_log_visualizer/ui/gui.py b/robot_log_visualizer/ui/gui.py index dc9edfd..0e66a27 100644 --- a/robot_log_visualizer/ui/gui.py +++ b/robot_log_visualizer/ui/gui.py @@ -2,19 +2,21 @@ # This software may be modified and distributed under the terms of the # Released under the terms of the BSD 3-Clause License -# PyQt5 -from PyQt5 import QtWidgets, QtGui -from PyQt5.QtCore import QUrl -from PyQt5.QtCore import pyqtSlot, Qt, QMutex, QMutexLocker -from PyQt5.QtWidgets import ( +# QtPy abstraction +from qtpy import QtWidgets, QtGui, QtCore +from qtpy import QtWebEngineWidgets # noqa: F401 # Ensure WebEngine is initialised +from qtpy.QtCore import QMutex, QMutexLocker, QUrl, Qt, Slot +from qtpy.QtWidgets import ( + QDialog, + QDialogButtonBox, QFileDialog, - QTreeWidgetItem, + QLineEdit, QToolButton, - QDialog, + QTreeWidgetItem, QVBoxLayout, - QLineEdit, - QDialogButtonBox, ) + +pyqtSlot = Slot from robot_log_visualizer.robot_visualizer.meshcat_provider import MeshcatProvider from robot_log_visualizer.signal_provider.realtime_signal_provider import ( RealtimeSignalProvider, @@ -24,7 +26,10 @@ MatfileSignalProvider, ) -from robot_log_visualizer.signal_provider.signal_provider import SignalProvider +from robot_log_visualizer.signal_provider.signal_provider import ( + ProviderType, + SignalProvider, +) from robot_log_visualizer.ui.plot_item import PlotItem from robot_log_visualizer.ui.video_item import VideoItem from robot_log_visualizer.ui.text_logging import TextLoggingItem @@ -43,9 +48,7 @@ import numpy as np # QtDesigner generated classes -from robot_log_visualizer.ui.autogenerated.visualizer import Ui_MainWindow -from robot_log_visualizer.ui.autogenerated.about import Ui_aboutWindow -from robot_log_visualizer.ui.autogenerated.set_robot_model import Ui_setRobotModelDialog +from robot_log_visualizer.ui.ui_loader import load_ui # for logging from time import localtime, strftime @@ -60,8 +63,7 @@ class SetRobotModelDialog(QtWidgets.QDialog): def __init__(self, meshcat_provider, parent=None, dataset_loaded=False): # call QMainWindow constructor super().__init__(parent) - self.ui = Ui_setRobotModelDialog() - self.ui.setupUi(self) + self.ui = load_ui("set_robot_model.ui", self) model_path = meshcat_provider.model_path package_dir = meshcat_provider.custom_package_dir @@ -143,8 +145,7 @@ class About(QtWidgets.QMainWindow): def __init__(self): # call QMainWindow constructor super().__init__() - self.ui = Ui_aboutWindow() - self.ui.setupUi(self) + self.ui = load_ui("about.ui", self) def build_plot_title_box_dialog(): @@ -187,8 +188,7 @@ def __init__(self, signal_provider_period, meshcat_provider, animation_period): self.animation_period = animation_period # set up the user interface - self.ui = Ui_MainWindow() - self.ui.setupUi(self) + self.ui = load_ui("visualizer.ui", self) # Set all the icons self.ui.startButton.setIcon(get_icon("play-outline.svg")) @@ -452,7 +452,7 @@ def plotTabCloseButton_on_click(self, index): def plotTabBar_on_doubleClick(self, index): dlg, plot_title = build_plot_title_box_dialog() - if dlg.exec() == QDialog.Accepted: + if dlg.exec_() == QDialog.Accepted: self.ui.tabPlotWidget.setTabText(index, plot_title.text()) def variableTreeWidget_on_click(self): @@ -813,7 +813,7 @@ def open_set_robot_model(self): self, self.dataset_loaded, ) - outcome = dlg.exec() + outcome = dlg.exec_() if outcome == QDialog.Accepted: # check which button was clicked @@ -1178,4 +1178,8 @@ def scroll_down(self): # show the main window gui.show() - sys.exit(app.exec_()) + exec_method = getattr(app, "exec", None) + if exec_method is None: + exec_method = app.exec_ + + sys.exit(exec_method()) diff --git a/robot_log_visualizer/ui/misc/video_tab.ui b/robot_log_visualizer/ui/misc/video_tab.ui index 35d09b0..82d80aa 100644 --- a/robot_log_visualizer/ui/misc/video_tab.ui +++ b/robot_log_visualizer/ui/misc/video_tab.ui @@ -21,9 +21,9 @@ - QVideoWidget - QWidget -
PyQt5.QtMultimediaWidgets
+ QVideoWidget + QWidget +
qtpy.QtMultimediaWidgets
1
diff --git a/robot_log_visualizer/ui/misc/visualizer.ui b/robot_log_visualizer/ui/misc/visualizer.ui index 85ff73b..32e531f 100644 --- a/robot_log_visualizer/ui/misc/visualizer.ui +++ b/robot_log_visualizer/ui/misc/visualizer.ui @@ -570,7 +570,7 @@ QWebEngineView QWidget -
QtWebEngineWidgets/QWebEngineView
+
qtpy.QtWebEngineWidgets
1
diff --git a/robot_log_visualizer/ui/plot_item.py b/robot_log_visualizer/ui/plot_item.py index b4ba329..c0889c0 100644 --- a/robot_log_visualizer/ui/plot_item.py +++ b/robot_log_visualizer/ui/plot_item.py @@ -2,17 +2,16 @@ # This software may be modified and distributed under the terms of the # Released under the terms of the BSD 3-Clause License -from PyQt5.QtWidgets import QFrame +from qtpy.QtWidgets import QFrame from robot_log_visualizer.plotter.pyqtgraph_viewer_canvas import PyQtGraphViewerCanvas -from robot_log_visualizer.ui.autogenerated.plot_tab import Ui_PlotTab +from robot_log_visualizer.ui.ui_loader import load_ui class PlotItem(QFrame): def __init__(self, period): super().__init__(None) - self.ui = Ui_PlotTab() - self.ui.setupUi(self) + self.ui = load_ui("plot_tab.ui", self) self.canvas = PyQtGraphViewerCanvas(parent=self, period=period) self.ui.plotLayout.addWidget(self.canvas) diff --git a/robot_log_visualizer/ui/text_logging.py b/robot_log_visualizer/ui/text_logging.py index 477b4b8..dcb2403 100644 --- a/robot_log_visualizer/ui/text_logging.py +++ b/robot_log_visualizer/ui/text_logging.py @@ -1,9 +1,6 @@ -from PyQt5 import QtWidgets -from PyQt5.QtWidgets import ( - QTableWidgetItem, -) - -from PyQt5.QtGui import QColor, QBrush +from qtpy import QtWidgets +from qtpy.QtGui import QColor, QBrush +from qtpy.QtWidgets import QTableWidgetItem class TextLoggingItem: diff --git a/robot_log_visualizer/ui/ui_loader.py b/robot_log_visualizer/ui/ui_loader.py new file mode 100644 index 0000000..3524916 --- /dev/null +++ b/robot_log_visualizer/ui/ui_loader.py @@ -0,0 +1,55 @@ +# Copyright (C) 2022 Istituto Italiano di Tecnologia (IIT). All rights reserved. +# This software may be modified and distributed under the terms of the +# Released under the terms of the BSD 3-Clause License + +"""Utilities to load Qt Designer `.ui` files at runtime.""" + +from __future__ import annotations + +from importlib import resources +from typing import Any + +from qtpy import uic + + +class UiProxy: + """Proxy object exposing UI attributes through the ``ui`` namespace. + + Historically the project relied on the Qt Designer generated ``Ui_*`` + classes that exposed widgets under a ``ui`` attribute. We keep the same + interface by wrapping the current instance in this proxy so existing code + can continue to access widgets as ``self.ui.someWidget``. + """ + + def __init__(self, target: Any) -> None: + super().__setattr__("_target", target) + + def __getattr__(self, name: str) -> Any: + return getattr(self._target, name) + + def __setattr__(self, name: str, value: Any) -> None: + setattr(self._target, name, value) + + +def load_ui(ui_filename: str, baseinstance: Any) -> UiProxy: + """Load a Qt Designer ``.ui`` file into an existing widget instance. + + Parameters + ---------- + ui_filename + Name of the ``.ui`` file stored inside ``robot_log_visualizer.ui.misc``. + baseinstance + The Qt widget instance where the UI should be loaded. + + Returns + ------- + UiProxy + A proxy object that exposes the loaded widgets under the ``ui`` + namespace, preserving the previous ``self.ui`` calling convention. + """ + + package = "robot_log_visualizer.ui.misc" + with resources.path(package, ui_filename) as ui_path: + uic.loadUi(str(ui_path), baseinstance) + + return UiProxy(baseinstance) diff --git a/robot_log_visualizer/ui/video_item.py b/robot_log_visualizer/ui/video_item.py index 8db0ad8..723573e 100644 --- a/robot_log_visualizer/ui/video_item.py +++ b/robot_log_visualizer/ui/video_item.py @@ -2,27 +2,26 @@ # This software may be modified and distributed under the terms of the # Released under the terms of the BSD 3-Clause License -from PyQt5.QtCore import QUrl -from PyQt5.QtWidgets import QFrame -from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer +from qtpy.QtCore import QUrl +from qtpy.QtMultimedia import QAudioOutput, QMediaPlayer +from qtpy.QtWidgets import QFrame -from robot_log_visualizer.ui.autogenerated.video_tab import Ui_VideoTab +from robot_log_visualizer.ui.ui_loader import load_ui import os class VideoItem(QFrame): def __init__(self, video_filename: str): super().__init__(None) - self.ui = Ui_VideoTab() - self.ui.setupUi(self) + self.ui = load_ui("video_tab.ui", self) - self.media_player = QMediaPlayer(None, QMediaPlayer.VideoSurface) + self.media_player = QMediaPlayer(self) + self.audio_output = QAudioOutput(self) + self.media_player.setAudioOutput(self.audio_output) self.media_player.setVideoOutput(self.ui.webcamView) self.media_loaded = False if os.path.isfile(video_filename): - self.media_player.setMedia( - QMediaContent(QUrl.fromLocalFile(video_filename)) - ) + self.media_player.setSource(QUrl.fromLocalFile(video_filename)) self.media_loaded = True diff --git a/setup.cfg b/setup.cfg index b2ccf29..0d9cb5c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -40,15 +40,15 @@ classifiers = packages = find: python_requires = >=3.8 install_requires = - idyntree >= 10.2.0 - meshcat - numpy - PyQt5 - PyQtWebEngine - pyqtconsole - matplotlib - h5py - pyqtgraph + idyntree >= 10.2.0 + meshcat + numpy + PySide2 + qtpy + pyqtconsole + matplotlib + h5py + pyqtgraph include_package_data = True [options.entry_points] @@ -56,4 +56,4 @@ console_scripts = robot-log-visualizer = robot_log_visualizer.__main__:main [options.package_data] -* = *.png, *.svg +* = *.png, *.svg, *.ui