qtosd: port in pyqt5
authorOlivier Matz <zer0@droids-corp.org>
Tue, 2 Jun 2015 19:55:09 +0000 (21:55 +0200)
committerOlivier Matz <zer0@droids-corp.org>
Tue, 2 Jun 2015 20:10:43 +0000 (22:10 +0200)
qtosd/qtosd.py
qtosd/qtosd.ui
qtosd/qtosd_ui.py [new file with mode: 0644]
qtosd/serialfpv.py

index dd2a6ee..37bbfcb 100644 (file)
 # http://pytricity.com/qt-artificial-horizon-custom-widget/
 
 import math
-from PyQt4 import QtCore, QtGui
+import argparse
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+from PyQt5.QtCore import pyqtSlot
 
 import serialfpv
+import qtosd_ui
 
 try:
     _fromUtf8 = QtCore.QString.fromUtf8
@@ -32,18 +36,19 @@ except AttributeError:
         return s
 
 try:
-    _encoding = QtGui.QApplication.UnicodeUTF8
+    _encoding = QtWidgets.QApplication.UnicodeUTF8
     def _translate(context, text, disambig):
-        return QtGui.QApplication.translate(context, text, disambig, _encoding)
+        return QtWidgets.QApplication.translate(context, text, disambig, _encoding)
 except AttributeError:
     def _translate(context, text, disambig):
-        return QtGui.QApplication.translate(context, text, disambig)
+        return QtWidgets.QApplication.translate(context, text, disambig)
 
-class OSDWidget(QtGui.QWidget):
-    def __init__(self, roundWidget = False):
+class OSDWidget(QtWidgets.QWidget):
+    def __init__(self, roundWidget = False, filename = None):
         super(OSDWidget, self).__init__()
         # init parameters
         self.roundWidget = roundWidget
+        self.fpv = None
         # parameters that will be modified by the user
         self.user_pitch = 0
         self.user_roll = 0
@@ -111,11 +116,16 @@ class OSDWidget(QtGui.QWidget):
                                    self.ALT_REFLINES_NUM_LINES)
         self.ALT_REFLINES_SIZE_FACTOR = 0.7
 
+        if filename:
+            self.fpv = serialfpv.SerialFPV()
+            self.fpv.open_file(filename)
+
         self.FPS = 50.
         self.timer = QtCore.QTimer(self)
-        self.connect(self.timer, QtCore.SIGNAL("timeout()"), self.frameTimerCb)
+        self.timer.timeout.connect(self.frameTimerCb)
         self.timer.start(1000. / self.FPS)
 
+    @pyqtSlot(name = "paintEvent")
     def paintEvent(self, evt):
         """Paint callback, this is the entry point for all drawings."""
         painter = QtGui.QPainter()
@@ -129,11 +139,15 @@ class OSDWidget(QtGui.QWidget):
         self.draw(painter)
         painter.end()
 
+    @pyqtSlot(name = "frameTimerCb")
     def frameTimerCb(self):
-        """called periodically, every frame, it calls the user_frame_cb function,
-           updates the filter and updates the widget"""
-        if self.user_frame_cb != None:
-            self.user_frame_cb()
+        # read from SerialFPV object
+        if self.fpv:
+            self.fpv.update_state()
+            self.user_speed = self.user_speed + 1
+            self.setRoll(self.fpv.roll)
+            self.setPitch(self.fpv.pitch)
+            self.setYaw(self.fpv.yaw)
 
         # avoid filter bugs when changing between 180 and -180
         self.pitch += round((self.user_pitch - self.pitch) / 360.) * 360
@@ -327,6 +341,7 @@ class OSDWidget(QtGui.QWidget):
             sz = metrics.size(QtCore.Qt.TextSingleLine, disp_val)
             lefttxt = QtCore.QRect(QtCore.QPoint(0, 0), sz)
             lefttxt.moveCenter(pt1 - QtCore.QPoint(0.2 * r, 0))
+            # XXX
             #pen.setWidth(1);
             #brush = QtGui.QBrush(QtCore.Qt.white)
             #painter.setBrush(brush)
@@ -645,105 +660,49 @@ class OSDWidget(QtGui.QWidget):
         """set the left text"""
         self.right_txt = txt
 
-    def setFrameCb(self, user_frame_cb):
-        """set a function that is called every frame, before updating the widget"""
-        self.user_frame_cb = user_frame_cb
+class Ui_MainWindow(QtWidgets.QMainWindow):
+    def __init__(self, parent = None, roundWidget = False, filename = None):
+        super(Ui_MainWindow, self).__init__(parent)
+        self.ui = qtosd_ui.Ui_MainWindow()
+        self.ui.setupUi(self)
 
-class Ui_MainWindow(object):
-    def __init__(self, filename = None, roundWidget = False):
         self.roundWidget = roundWidget
         self.filename = filename
 
-    def update_fpv_info(self):
-        self.fpv.update()
-        self.osd.user_speed = self.osd.user_speed + 1
-        self.osd.setRoll(self.fpv.roll)
-        self.osd.setPitch(self.fpv.pitch)
-        self.osd.setYaw(self.fpv.yaw)
-
-    def setupUi(self, MainWindow):
-        MainWindow.setObjectName(_fromUtf8("MainWindow"))
-        MainWindow.resize(400, 300)
-        self.centralWidget = QtGui.QWidget(MainWindow)
-        self.centralWidget.setObjectName(_fromUtf8("centralWidget"))
-        self.gridLayout = QtGui.QGridLayout(self.centralWidget)
-        self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
-
-        self.pitchSlider = QtGui.QSlider(self.centralWidget)
-        self.pitchSlider.setMinimum(-180)
-        self.pitchSlider.setMaximum(180)
-        self.pitchSlider.setOrientation(QtCore.Qt.Vertical)
-        self.pitchSlider.setObjectName(_fromUtf8("pitchSlider"))
-        self.pitchSlider.valueChanged[int].connect(self.changePitch)
-        self.gridLayout.addWidget(self.pitchSlider, 0, 0)
-
-        self.osd = OSDWidget(self.roundWidget)
-        if self.filename:
-            self.fpv = serialfpv.SerialFPV()
-            self.fpv.open_file(self.filename)
-            self.osd.setFrameCb(self.update_fpv_info)
-        self.gridLayout.addWidget(self.osd, 0, 1)
-
-        self.rollSlider = QtGui.QSlider(self.centralWidget)
-        self.rollSlider.setMinimum(-180)
-        self.rollSlider.setMaximum(180)
-        self.rollSlider.setOrientation(QtCore.Qt.Horizontal)
-        self.rollSlider.setObjectName(_fromUtf8("rollSlider"))
-        self.rollSlider.valueChanged[int].connect(self.changeRoll)
-        self.gridLayout.addWidget(self.rollSlider, 1, 1)
-
-        self.yawSlider = QtGui.QSlider(self.centralWidget)
-        self.yawSlider.setMaximum(360)
-        self.yawSlider.setProperty("value", 180)
-        self.osd.setYaw(180)
-        self.yawSlider.setOrientation(QtCore.Qt.Horizontal)
-        self.yawSlider.setObjectName(_fromUtf8("yawSlider"))
-        self.yawSlider.valueChanged[int].connect(self.changeYaw)
-        self.gridLayout.addWidget(self.yawSlider, 2, 1)
-
-        MainWindow.setCentralWidget(self.centralWidget)
-        self.menuBar = QtGui.QMenuBar(MainWindow)
-        self.menuBar.setGeometry(QtCore.QRect(0, 0, 400, 23))
-        self.menuBar.setObjectName(_fromUtf8("menuBar"))
-        MainWindow.setMenuBar(self.menuBar)
-        self.mainToolBar = QtGui.QToolBar(MainWindow)
-        self.mainToolBar.setObjectName(_fromUtf8("mainToolBar"))
-        MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.mainToolBar)
-        self.statusBar = QtGui.QStatusBar(MainWindow)
-        self.statusBar.setObjectName(_fromUtf8("statusBar"))
-        MainWindow.setStatusBar(self.statusBar)
-
-        self.retranslateUi(MainWindow)
-        QtCore.QMetaObject.connectSlotsByName(MainWindow)
+        self.osd = OSDWidget(roundWidget = self.roundWidget,
+                             filename = self.filename)
+        self.ui.gridLayout.addWidget(self.osd, 0, 1)
+        self.ui.pitchSlider.valueChanged[int].connect(self.changePitch)
+        self.ui.rollSlider.valueChanged[int].connect(self.changeRoll)
+        self.ui.yawSlider.valueChanged[int].connect(self.changeYaw)
 
     def retranslateUi(self, MainWindow):
         MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
 
+    @pyqtSlot(int, name = "changePitch")
     def changePitch(self, value):
         self.osd.setPitch(value)
-        self.osd.update()
 
+    @pyqtSlot(int, name = "changeRoll")
     def changeRoll(self, value):
         self.osd.setRoll(value)
-        self.osd.update()
 
+    @pyqtSlot(int, name = "changeYaw")
     def changeYaw(self, value):
         self.osd.setYaw(value)
-        self.osd.update()
 
 if __name__ == "__main__":
     import sys
-    app = QtGui.QApplication(sys.argv)
-    if "round" in sys.argv:
-        roundWidget = True
-    else:
-        roundWidget = False
-    MainWindow = QtGui.QMainWindow()
-    if len(sys.argv) > 1:
-        ui = Ui_MainWindow(sys.argv[1], roundWidget)
-    else:
-        ui = Ui_MainWindow(roundWidget = roundWidget)
-    ui.setupUi(MainWindow)
-    MainWindow.show()
+
+    parser = argparse.ArgumentParser(description='OSD written in Qt.')
+    parser.add_argument('--round', '-r', action="store_true",
+                        help='display the widget as a round attitude meter')
+    parser.add_argument('--filename', '-f',
+                        help='specify the log file')
+    args = parser.parse_args()
+
+    app = QtWidgets.QApplication(sys.argv)
+    ui = Ui_MainWindow(filename = args.filename, roundWidget = args.round)
+    ui.show()
     sys.exit(app.exec_())
 
index 05f288e..11aaf4f 100644 (file)
@@ -28,9 +28,6 @@
       </property>
      </widget>
     </item>
-    <item row="0" column="1">
-     <layout class="QVBoxLayout" name="verticalLayout"/>
-    </item>
     <item row="1" column="1">
      <widget class="QSlider" name="rollSlider">
       <property name="minimum">
diff --git a/qtosd/qtosd_ui.py b/qtosd/qtosd_ui.py
new file mode 100644 (file)
index 0000000..2089ed5
--- /dev/null
@@ -0,0 +1,66 @@
+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'qtosd.ui'
+#
+# Created: Tue Jun  2 19:36:00 2015
+#      by: PyQt5 UI code generator 5.3.2
+#
+# WARNING! All changes made in this file will be lost!
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+class Ui_MainWindow(object):
+    def setupUi(self, MainWindow):
+        MainWindow.setObjectName("MainWindow")
+        MainWindow.resize(400, 300)
+        self.centralWidget = QtWidgets.QWidget(MainWindow)
+        self.centralWidget.setObjectName("centralWidget")
+        self.gridLayout = QtWidgets.QGridLayout(self.centralWidget)
+        self.gridLayout.setObjectName("gridLayout")
+        self.pitchSlider = QtWidgets.QSlider(self.centralWidget)
+        self.pitchSlider.setMinimum(-180)
+        self.pitchSlider.setMaximum(180)
+        self.pitchSlider.setOrientation(QtCore.Qt.Vertical)
+        self.pitchSlider.setObjectName("pitchSlider")
+        self.gridLayout.addWidget(self.pitchSlider, 0, 0, 1, 1)
+        self.rollSlider = QtWidgets.QSlider(self.centralWidget)
+        self.rollSlider.setMinimum(-180)
+        self.rollSlider.setMaximum(180)
+        self.rollSlider.setOrientation(QtCore.Qt.Horizontal)
+        self.rollSlider.setObjectName("rollSlider")
+        self.gridLayout.addWidget(self.rollSlider, 1, 1, 1, 1)
+        self.yawSlider = QtWidgets.QSlider(self.centralWidget)
+        self.yawSlider.setMaximum(360)
+        self.yawSlider.setProperty("value", 180)
+        self.yawSlider.setOrientation(QtCore.Qt.Horizontal)
+        self.yawSlider.setObjectName("yawSlider")
+        self.gridLayout.addWidget(self.yawSlider, 2, 1, 1, 1)
+        MainWindow.setCentralWidget(self.centralWidget)
+        self.menuBar = QtWidgets.QMenuBar(MainWindow)
+        self.menuBar.setGeometry(QtCore.QRect(0, 0, 400, 23))
+        self.menuBar.setObjectName("menuBar")
+        MainWindow.setMenuBar(self.menuBar)
+        self.mainToolBar = QtWidgets.QToolBar(MainWindow)
+        self.mainToolBar.setObjectName("mainToolBar")
+        MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.mainToolBar)
+        self.statusBar = QtWidgets.QStatusBar(MainWindow)
+        self.statusBar.setObjectName("statusBar")
+        MainWindow.setStatusBar(self.statusBar)
+
+        self.retranslateUi(MainWindow)
+        QtCore.QMetaObject.connectSlotsByName(MainWindow)
+
+    def retranslateUi(self, MainWindow):
+        _translate = QtCore.QCoreApplication.translate
+        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
+
+
+if __name__ == "__main__":
+    import sys
+    app = QtWidgets.QApplication(sys.argv)
+    MainWindow = QtWidgets.QMainWindow()
+    ui = Ui_MainWindow()
+    ui.setupUi(MainWindow)
+    MainWindow.show()
+    sys.exit(app.exec_())
+
index 6153a3d..f089d1c 100644 (file)
@@ -49,7 +49,7 @@ class SerialFPV():
         self.prev_reftime = None
         self.data = ""
 
-    def update(self):
+    def update_state(self):
         # read from file/serial
         while len(self.data) < 16384:
             data = self.f.read(1024)
@@ -75,7 +75,7 @@ class SerialFPV():
                          "\| magnet %s %s %s " % (FLOAT, FLOAT, FLOAT) +
                          "\| angles %s %s %s"% (FLOAT, FLOAT, FLOAT), l)
             if m:
-                cur_time = float(m.groups()[0]) / 20.
+                cur_time = float(m.groups()[0]) / 1000.
                 # first time, init prev_time and prev_reftime
                 if self.realtime == False and self.prev_time == None:
                     self.prev_time = cur_time
@@ -88,7 +88,6 @@ class SerialFPV():
                         break
                 roll, pitch, yaw = (
                     map(lambda x: float(x), m.groups()[10:13]))
-                print roll, pitch, yaw
                 self.roll = math.degrees(roll) + 180.
                 self.pitch = math.degrees(pitch)
                 self.yaw = math.degrees(yaw)