1 # -*- coding: utf-8 -*-
3 # OSD (on screen display) written in Qt
4 # Copyright (C) 2015 Olivier Matz <zer0@droids-corp.org>
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 # Inspired from QcGauge
20 # Copyright (C) 2015 Hadj Tahar Berrima
21 # http://pytricity.com/qt-artificial-horizon-custom-widget/
26 from PyQt5 import QtCore
27 from PyQt5.QtCore import (pyqtSlot, QTimer, QRect, QPoint, Qt)
28 from PyQt5.QtGui import (QPainter, QColor, QPen, QBrush, QLinearGradient, QFont,
29 QPainterPath, QPolygonF)
30 from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget)
35 _fromUtf8 = QtCore.QString.fromUtf8
36 except AttributeError:
41 _encoding = QApplication.UnicodeUTF8
42 def _translate(context, text, disambig):
43 return QApplication.translate(context, text, disambig, _encoding)
44 except AttributeError:
45 def _translate(context, text, disambig):
46 return QApplication.translate(context, text, disambig)
48 class OSDWidget(QWidget):
49 def __init__(self, roundWidget = False, filename = None):
50 super(OSDWidget, self).__init__()
52 self.roundWidget = roundWidget
54 # parameters that will be modified by the user
61 self.left_txt = "14.8v / 34A\n1.5Ah" # XXX
62 self.right_txt = "23:03 since take-off\n1.4 km to home\nRSSI 60dB" # XXX
63 self.user_frame_cb = None
71 # filtered parameters (0 = no filter, 1 = infinite filter)
72 self.pitch_filter_coef = 0.8
73 self.roll_filter_coef = 0.8
74 self.yaw_filter_coef = 0.8
75 self.speed_filter_coef = 0.8
76 self.alt_filter_coef = 0.8
77 self.rthome_filter_coef = 0.8
78 # QRect representing the viewport
80 # QRect representing the viewport, adjusted to a square
82 self.setMinimumSize(250, 250)
84 # how many degrees between pitch reference lines
87 self.PITCH_REFLINES_STEP_ANGLE = 10.
88 self.PITCH_REFLINES_BOLD_STEP_ANGLE = 30.
89 self.PITCH_REFLINES_NUM_LINES = 6
92 self.PITCH_REFLINES_STEP_ANGLE = 5.
93 self.PITCH_REFLINES_BOLD_STEP_ANGLE = 10.
94 self.PITCH_REFLINES_NUM_LINES = 4
96 self.PITCH_REFLINES_TOTAL_ANGLE = (self.PITCH_REFLINES_STEP_ANGLE *
97 self.PITCH_REFLINES_NUM_LINES)
98 # in fraction of radius
100 # how many degrees between yaw reference lines
101 self.YAW_REFLINES_STEP_ANGLE = 15.
102 self.YAW_REFLINES_NUM_LINES = 12
103 self.YAW_REFLINES_TOTAL_ANGLE = (self.YAW_REFLINES_STEP_ANGLE *
104 self.YAW_REFLINES_NUM_LINES)
105 self.YAW_REFLINES_SIZE_FACTOR = 0.5
107 self.SPEED_REFLINES_STEP = 10.
108 self.SPEED_REFLINES_BOLD_STEP = 50.
109 self.SPEED_REFLINES_NUM_LINES = 10
110 self.SPEED_REFLINES_TOTAL = (self.SPEED_REFLINES_STEP *
111 self.SPEED_REFLINES_NUM_LINES)
112 self.SPEED_REFLINES_SIZE_FACTOR = 0.7
114 self.ALT_REFLINES_STEP = 100.
115 self.ALT_REFLINES_BOLD_STEP = 500.
116 self.ALT_REFLINES_NUM_LINES = 10
117 self.ALT_REFLINES_TOTAL = (self.ALT_REFLINES_STEP *
118 self.ALT_REFLINES_NUM_LINES)
119 self.ALT_REFLINES_SIZE_FACTOR = 0.7
122 self.fpv = serialfpv.SerialFPV()
123 self.fpv.open_file(filename)
126 self.timer = QTimer(self)
127 self.timer.timeout.connect(self.frameTimerCb)
128 self.timer.start(1000. / self.FPS)
130 @pyqtSlot(name = "paintEvent")
131 def paintEvent(self, evt):
132 """Paint callback, this is the entry point for all drawings."""
135 painter.setRenderHint(QPainter.Antialiasing)
136 self.dev = evt.rect()
137 self.min_dim = min(self.dev.right(), self.dev.bottom())
138 self.max_dim = max(self.dev.right(), self.dev.bottom())
139 self.adjdev = QRect(0, 0, self.min_dim, self.min_dim)
140 self.adjdev.moveCenter(self.dev.center())
144 @pyqtSlot(name = "frameTimerCb")
145 def frameTimerCb(self):
146 # read from SerialFPV object
148 self.fpv.update_state()
149 self.user_speed = self.user_speed + 1
150 self.setRoll(self.fpv.roll)
151 self.setPitch(self.fpv.pitch)
152 self.setYaw(self.fpv.yaw)
154 # avoid filter bugs when changing between 180 and -180
155 self.pitch += round((self.user_pitch - self.pitch) / 360.) * 360
156 self.pitch = (self.pitch * self.pitch_filter_coef +
157 self.user_pitch * (1. - self.pitch_filter_coef))
158 self.roll += round((self.user_roll - self.roll) / 360.) * 360
159 self.roll = (self.roll * self.roll_filter_coef +
160 self.user_roll * (1. - self.roll_filter_coef))
161 self.yaw += round((self.user_yaw - self.yaw) / 360.) * 360
162 self.yaw = (self.yaw * self.yaw_filter_coef +
163 self.user_yaw * (1. - self.yaw_filter_coef))
164 self.speed = (self.speed * self.speed_filter_coef +
165 self.user_speed * (1. - self.speed_filter_coef))
166 self.alt = (self.alt * self.alt_filter_coef +
167 self.user_alt * (1. - self.alt_filter_coef))
168 self.rthome += round((self.user_rthome - self.rthome) / 360.) * 360
169 self.rthome = (self.rthome * self.rthome_filter_coef +
170 self.user_rthome * (1. - self.rthome_filter_coef))
173 def draw(self, painter):
174 """Draw the widget."""
176 self.drawHorizonRound(painter)
178 self.drawHorizon(painter)
179 self.drawPitchGraduation(painter)
180 self.drawRollGraduation(painter)
181 self.drawYaw(painter)
182 self.drawCenterRef(painter)
183 if self.roundWidget == False:
184 self.drawSpeed(painter)
185 self.drawAlt(painter)
186 self.drawReturnToHome(painter)
187 self.drawTxtInfo(painter)
189 def getSkyBrush(self):
190 """return the color gradient for the sky (blue)"""
191 sky_gradient = QLinearGradient(self.adjdev.topLeft(),
192 self.adjdev.bottomRight())
195 sky_gradient.setColorAt(0, color1)
196 sky_gradient.setColorAt(.8, color2)
199 def getGroundBrush(self):
200 """return the color gradient for the ground (marron)"""
201 ground_gradient = QLinearGradient(self.adjdev.topLeft(),
202 self.adjdev.bottomRight())
203 color1 = QColor(140, 100, 80)
204 color2 = QColor(140, 100, 40)
205 ground_gradient.setColorAt(0, color1)
206 ground_gradient.setColorAt(.8, color2)
207 return ground_gradient
209 def getCenterRadius(self):
210 """Return the radius of the widget circle"""
212 return self.adjdev.width() / 2.
214 return self.adjdev.width() / 3.5
216 def drawHorizonRound(self, painter):
217 """Draw the horizon for round widget: the sky in blue,
218 the ground in marron."""
220 # set local pitch and roll
229 pitch = -180. - pitch
234 # we have to draw a partial circle delimited by its chord, define
235 # where the chord starts
236 start_angle = math.degrees(math.asin(pitch / 90.)) - roll
237 span = 2 * math.degrees(math.asin(pitch / 90.))
240 painter.setBrush(self.getSkyBrush())
241 # startAngle and spanAngle must be specified in 1/16th of a degree
242 painter.drawChord(self.adjdev, 16 * start_angle, 16 * (180. - span))
245 painter.setBrush(self.getGroundBrush())
246 # startAngle and spanAngle must be specified in 1/16th of a degree
247 painter.drawChord(self.adjdev, 16 * start_angle, -16 * (180. + span))
249 def drawHorizon(self, painter):
250 """Draw the horizon: the sky in blue, the ground in marron."""
252 painter.setBrush(self.getSkyBrush())
253 painter.drawRect(self.dev)
254 center = self.adjdev.center()
255 r = self.getCenterRadius()
256 # radius of the adjusted screen (same than r if roundWidget = True)
257 dev_r = self.adjdev.width() / 2.
259 if self.pitch < -90.:
260 pitch = -180 - self.pitch
261 elif self.pitch < 90.:
264 pitch = 180 - self.pitch
265 y_off = (pitch / self.CAM_ANGLE) * dev_r
266 painter.translate(center.x(), center.y())
268 ground_rect = QRect(0, 0, self.max_dim * 5., self.max_dim * 5.)
269 if self.pitch < 90. and self.pitch > -90.:
270 ground_rect.moveCenter(QPoint(0, -y_off + ground_rect.width()/2.))
272 ground_rect.moveCenter(QPoint(0, y_off - ground_rect.width()/2.))
273 painter.setBrush(self.getGroundBrush())
274 painter.drawRect(ground_rect)
277 def drawCenterRef(self, painter):
278 """Draw the cross on the middle of the OSD"""
279 center = self.adjdev.center()
280 r = self.getCenterRadius()
281 pen = QPen(Qt.red, r / 100., Qt.SolidLine)
283 pt1 = QPoint(center.x() - 0.05 * r, center.y())
284 pt2 = QPoint(center.x() + 0.05 * r, center.y())
285 painter.drawLine(pt1, pt2)
286 pt1 = QPoint(center.x(), center.y() + -0.025 * r)
287 pt2 = QPoint(center.x(), center.y() + 0.025 * r)
288 painter.drawLine(pt1, pt2)
290 def drawPitchGraduation(self, painter):
291 """Draw the pitch graduations."""
292 # change the reference
294 center = self.adjdev.center()
295 r = self.getCenterRadius()
296 # radius of the adjusted screen (same than r if roundWidget = True)
297 dev_r = self.adjdev.width() / 2.
299 x_off = (self.pitch / self.CAM_ANGLE) * dev_r * math.sin(math.radians(roll))
300 y_off = (self.pitch / self.CAM_ANGLE) * dev_r * math.cos(math.radians(roll))
301 painter.translate(center.x() + x_off, center.y() - y_off)
305 pen = QPen(Qt.white, r / 100., Qt.SolidLine)
307 font = QFont("Meiryo UI", 0, QFont.Bold)
308 font.setPointSizeF(self.FONT_SIZE * r)
309 painter.setFont(font)
311 # round to nearest angle that is a multiple of step
312 a = self.pitch / self.PITCH_REFLINES_STEP_ANGLE
314 a = int(a * self.PITCH_REFLINES_STEP_ANGLE)
315 a -= self.PITCH_REFLINES_STEP_ANGLE * (self.PITCH_REFLINES_NUM_LINES / 2.)
316 angles = [ a + i * self.PITCH_REFLINES_STEP_ANGLE
317 for i in range(self.PITCH_REFLINES_NUM_LINES + 1) ]
320 if int(a) % int(self.PITCH_REFLINES_BOLD_STEP_ANGLE) != 0:
321 pen = QPen(Qt.white, r / 100., Qt.SolidLine)
323 pt1 = QPoint(-0.05 * r, dev_r / self.CAM_ANGLE * a)
324 pt2 = QPoint(0.05 * r, dev_r / self.CAM_ANGLE * a)
325 painter.drawLine(pt1, pt2)
329 pen = QPen(Qt.white, r / 50., Qt.SolidLine)
331 pt1 = QPoint(-0.2 * r, dev_r / self.CAM_ANGLE * a)
332 pt2 = QPoint(0.2 * r, dev_r / self.CAM_ANGLE * a)
333 painter.drawLine(pt1, pt2)
338 disp_val = 180. - disp_val
340 disp_val = -180. - disp_val
341 disp_val = str(int(disp_val))
342 metrics = painter.fontMetrics()
343 sz = metrics.size(Qt.TextSingleLine, disp_val)
344 lefttxt = QRect(QPoint(0, 0), sz)
345 lefttxt.moveCenter(pt1 - QPoint(0.2 * r, 0))
348 #brush = QBrush(Qt.white)
349 #painter.setBrush(brush)
350 #pen.setColor(Qt.black);
352 #path = QPainterPath()
353 #path.addText(lefttxt.center(), font, disp_val)
354 #painter.drawPath(path)
355 painter.drawText(lefttxt, Qt.TextSingleLine, disp_val)
357 # flip the right text
359 painter.translate(pt2 + QPoint(0.2 * r, 0))
361 painter.translate(-pt2 - QPoint(0.2 * r, 0))
362 righttxt = QRect(QPoint(0, 0), sz)
363 righttxt.moveCenter(pt2 + QPoint(0.2 * r, 0))
364 #path = QPainterPath()
365 #path.addText(righttxt.center(), font, disp_val)
366 #painter.drawPath(path)
367 painter.drawText(righttxt, Qt.TextSingleLine, disp_val)
372 def drawOneRollGraduation(self, painter, deg, disp_text):
373 # draw the graduiation
374 r = self.getCenterRadius()
375 center = self.adjdev.center()
376 x = center.x() - math.cos(math.radians(deg)) * r
377 y = center.y() - math.sin(math.radians(deg)) * r
379 path = QPainterPath()
382 pt2 = path.pointAtPercent(0.075) # graduation len is 7.5% of the radius
383 painter.drawLine(pt, pt2)
385 if disp_text == True:
386 pt_txt = path.pointAtPercent(0.2)
387 font = QFont("Meiryo UI", 0, QFont.Bold)
388 font.setPointSizeF(self.FONT_SIZE * r)
389 painter.setFont(font)
392 disp_val = 180. - disp_val
393 disp_val = str(int(disp_val))
394 metrics = painter.fontMetrics()
395 sz = metrics.size(Qt.TextSingleLine, disp_val)
396 txt = QRect(QPoint(0, 0), sz)
397 txt.moveCenter(pt_txt.toPoint())
398 painter.drawText(txt, Qt.TextSingleLine, disp_val)
400 def drawRollGraduation(self, painter):
401 """Draw the roll graduations."""
402 center = self.adjdev.center()
403 r = self.getCenterRadius()
405 # draw the red reference lines (pitch 0)
407 painter.translate(center.x(), center.y())
408 painter.rotate(self.roll)
409 pen = QPen(Qt.red, r / 100., Qt.SolidLine)
411 pt1 = QPoint(-0.925 * r, 0)
412 pt2 = QPoint(-0.85 * r, 0)
413 painter.drawLine(pt1, pt2)
414 pt1 = QPoint(0.925 * r, 0)
415 pt2 = QPoint(0.85 * r, 0)
416 painter.drawLine(pt1, pt2)
419 pen = QPen(Qt.white, r / 50., Qt.SolidLine)
431 self.drawOneRollGraduation(painter, deg, disp_text)
434 def drawYaw(self, painter):
435 center = self.adjdev.center()
436 r = self.getCenterRadius()
437 pen = QPen(Qt.red, r / 100., Qt.SolidLine)
439 font = QFont("Meiryo UI", 0, QFont.Bold)
440 font.setPointSizeF(self.FONT_SIZE * r)
441 painter.setFont(font)
442 if self.roundWidget == True:
443 y_txt = center.y() + r * 0.6
444 y1 = center.y() + r * 0.7
445 y2 = center.y() + r * 0.8
446 y3 = center.y() + r * 0.85
448 y_txt = center.y() + r * 1.
449 y1 = center.y() + r * 1.1
450 y2 = center.y() + r * 1.2
451 y3 = center.y() + r * 1.25
452 pt1 = QPoint(center.x(), y2)
453 pt2 = QPoint(center.x(), y3)
454 painter.drawLine(pt1, pt2)
456 # round to nearest angle multiple of step
457 a = self.yaw / self.YAW_REFLINES_STEP_ANGLE
459 a = int(a * self.YAW_REFLINES_STEP_ANGLE)
460 a -= self.YAW_REFLINES_STEP_ANGLE * (self.YAW_REFLINES_NUM_LINES / 2.)
461 angles = [ a + i * self.YAW_REFLINES_STEP_ANGLE
462 for i in range(self.YAW_REFLINES_NUM_LINES + 1) ]
467 pen = QPen(Qt.white, r / 50., Qt.SolidLine)
471 pen = QPen(Qt.white, r / 100., Qt.SolidLine)
474 x = center.x() - ((r / (self.YAW_REFLINES_TOTAL_ANGLE / 2.)) *
475 (self.yaw - a) * self.YAW_REFLINES_SIZE_FACTOR)
476 pt_txt = QPoint(x, y_txt)
479 painter.drawLine(pt1, pt2)
480 if disp_text == False:
482 disp_val = ["N", "E", "S", "W"][(int(a)/90)%4]
483 metrics = painter.fontMetrics()
484 sz = metrics.size(Qt.TextSingleLine, disp_val)
485 txt = QRect(QPoint(0, 0), sz)
486 txt.moveCenter(pt_txt)
487 painter.drawText(txt, Qt.TextSingleLine, disp_val)
489 def drawSpeed(self, painter):
490 center = self.adjdev.center()
491 r = self.getCenterRadius()
492 pen = QPen(Qt.red, r / 100., Qt.SolidLine)
494 font = QFont("Meiryo UI", 0, QFont.Bold)
495 font.setPointSizeF(self.FONT_SIZE * r)
496 painter.setFont(font)
497 x1 = center.x() - 1.5 * r
498 x2 = center.x() - 1.6 * r
499 pt1 = QPoint(center.x() - 1.45 * r, center.y())
500 pt2 = QPoint(x2, center.y())
501 painter.drawLine(pt1, pt2)
503 # round to nearest angle multiple of step
504 s = self.speed / self.SPEED_REFLINES_STEP
506 s = int(s * self.SPEED_REFLINES_STEP)
507 s -= self.SPEED_REFLINES_STEP * (self.SPEED_REFLINES_NUM_LINES / 2.)
508 speeds = [ s + i * self.SPEED_REFLINES_STEP
509 for i in range(self.SPEED_REFLINES_NUM_LINES + 1) ]
511 if int(s) % int(self.SPEED_REFLINES_BOLD_STEP) == 0:
513 pen = QPen(Qt.white, r / 50., Qt.SolidLine)
517 pen = QPen(Qt.white, r / 100., Qt.SolidLine)
520 y = center.y() + ((r / (self.SPEED_REFLINES_TOTAL/2.)) *
521 (self.speed - s) * self.SPEED_REFLINES_SIZE_FACTOR)
522 pt_txt = QPoint(center.x() + r * -1.75, y)
525 painter.drawLine(pt1, pt2)
526 if disp_text == False:
528 disp_val = str(int(s))
529 metrics = painter.fontMetrics()
530 sz = metrics.size(Qt.TextSingleLine, disp_val)
531 txt = QRect(QPoint(0, 0), sz)
532 txt.moveCenter(pt_txt)
533 painter.drawText(txt, Qt.TextSingleLine, disp_val)
535 def drawAlt(self, painter):
536 center = self.adjdev.center()
537 r = self.getCenterRadius()
538 pen = QPen(Qt.red, r / 100., Qt.SolidLine)
540 font = QFont("Meiryo UI", 0, QFont.Bold)
541 font.setPointSizeF(self.FONT_SIZE * r)
542 painter.setFont(font)
543 x1 = center.x() + 1.5 * r
544 x2 = center.x() + 1.6 * r
545 pt1 = QPoint(center.x() + 1.45 * r, center.y())
546 pt2 = QPoint(x2, center.y())
547 painter.drawLine(pt1, pt2)
549 # round to nearest angle multiple of step
550 a = self.alt / self.ALT_REFLINES_STEP
552 a = int(a * self.ALT_REFLINES_STEP)
553 a -= self.ALT_REFLINES_STEP * (self.ALT_REFLINES_NUM_LINES / 2.)
554 alts = [ a + i * self.ALT_REFLINES_STEP
555 for i in range(self.ALT_REFLINES_NUM_LINES + 1) ]
557 if int(a) % int(self.ALT_REFLINES_BOLD_STEP) == 0:
559 pen = QPen(Qt.white, r / 50., Qt.SolidLine)
563 pen = QPen(Qt.white, r / 100., Qt.SolidLine)
566 y = center.y() + ((r / (self.ALT_REFLINES_TOTAL / 2.)) *
567 (self.alt - a) * self.ALT_REFLINES_SIZE_FACTOR)
568 pt_txt = QPoint(center.x() + r * 1.75, y)
571 painter.drawLine(pt1, pt2)
572 if disp_text == False:
574 disp_val = str(int(a))
575 metrics = painter.fontMetrics()
576 sz = metrics.size(Qt.TextSingleLine, disp_val)
577 txt = QRect(QPoint(0, 0), sz)
578 txt.moveCenter(pt_txt)
579 painter.drawText(txt, Qt.TextSingleLine, disp_val)
581 def drawReturnToHome(self, painter):
582 center = self.adjdev.center()
583 r = self.getCenterRadius()
584 dev_r = self.adjdev.width() / 2.
586 painter.translate(center.x(), center.y() - 0.9 * dev_r)
587 painter.rotate(self.yaw) # XXX
588 pen = QPen(Qt.white, r / 100., Qt.SolidLine)
591 poly.append(QPoint(0., -0.08 * r))
592 poly.append(QPoint(0.04 * r, 0.08 * r))
593 poly.append(QPoint(-0.04 * r, 0.08 * r))
594 poly.append(QPoint(0., -0.08 * r))
595 path = QPainterPath()
596 path.addPolygon(poly)
597 brush = QBrush(Qt.darkGray)
598 painter.setBrush(brush)
599 painter.drawPath(path)
602 def drawTxtInfo(self, painter):
603 center = self.adjdev.center()
604 dev_r = self.adjdev.width() / 2.
605 r = self.getCenterRadius()
606 pen = QPen(Qt.white, r / 100., Qt.SolidLine)
608 font = QFont("Meiryo UI", 0, QFont.Bold)
609 font.setPointSizeF(self.FONT_SIZE * r)
610 metrics = painter.fontMetrics()
612 sz = metrics.size(Qt.AlignLeft, self.left_txt)
613 txt = QRect(QPoint(0, 0), sz)
614 pt_txt = QPoint(center.x() + dev_r * -0.95,
615 center.y() + dev_r * -0.95)
616 txt.moveTopLeft(pt_txt)
617 painter.drawText(txt, Qt.AlignLeft, self.left_txt)
619 sz = metrics.size(Qt.AlignRight, self.right_txt)
620 txt = QRect(QPoint(0, 0), sz)
621 pt_txt = QPoint(center.x() + dev_r * 0.95,
622 center.y() + dev_r * -0.95)
623 txt.moveTopRight(pt_txt)
624 painter.drawText(txt, Qt.AlignRight, self.right_txt)
626 def setPitch(self, pitch):
627 """set the pitch in degrees, between -180 and 180"""
631 self.user_pitch = pitch
633 def setRoll(self, roll):
634 """set the roll in degrees, between -180 and 180"""
638 self.user_roll = roll
640 def setYaw(self, yaw):
641 """set the yaw in degrees, between 0 and 360"""
645 def setSpeed(self, speed):
647 self.user_speed = speed
649 def setAlt(self, alt):
653 def setReturnToHomeAngle(self, angle):
654 """set the left text"""
655 self.user_rthome = angle
657 def setLeftTxt(self, txt):
658 """set the right text"""
661 def setRightTxt(self, txt):
662 """set the left text"""
665 class Ui_OSD(QMainWindow):
666 def __init__(self, parent = None, roundWidget = False, filename = None):
667 super(Ui_OSD, self).__init__(parent)
668 self.ui = qtosd_ui.Ui_MainWindow()
669 self.ui.setupUi(self)
671 self.roundWidget = roundWidget
672 self.filename = filename
674 self.osd = OSDWidget(roundWidget = self.roundWidget,
675 filename = self.filename)
676 self.ui.gridLayout.addWidget(self.osd, 0, 1)
677 self.ui.pitchSlider.valueChanged[int].connect(self.changePitch)
678 self.ui.rollSlider.valueChanged[int].connect(self.changeRoll)
679 self.ui.yawSlider.valueChanged[int].connect(self.changeYaw)
680 self.ui.actionExit.triggered.connect(self.close)
682 def keyPressEvent(self, event):
683 if event.key() == Qt.Key_J:
684 self.osd.setRoll(self.osd.user_roll + 2)
686 elif event.key() == Qt.Key_L:
687 self.osd.setRoll(self.osd.user_roll - 2)
689 elif event.key() == Qt.Key_I:
690 self.osd.setPitch(self.osd.user_pitch + 2)
692 elif event.key() == Qt.Key_K:
693 self.osd.setPitch(self.osd.user_pitch - 2)
695 elif event.key() == Qt.Key_Q:
698 def keyReleaseEvent(self, event):
701 def retranslateUi(self, MainWindow):
702 MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
704 @pyqtSlot(int, name = "changePitch")
705 def changePitch(self, value):
706 self.osd.setPitch(value)
708 @pyqtSlot(int, name = "changeRoll")
709 def changeRoll(self, value):
710 self.osd.setRoll(value)
712 @pyqtSlot(int, name = "changeYaw")
713 def changeYaw(self, value):
714 self.osd.setYaw(value)
716 if __name__ == "__main__":
719 parser = argparse.ArgumentParser(description='OSD written in Qt.')
720 parser.add_argument('--round', '-r', action="store_true",
721 help='display the widget as a round attitude meter')
722 parser.add_argument('--filename', '-f',
723 help='specify the log file')
724 args = parser.parse_args()
726 app = QApplication(sys.argv)
727 ui = Ui_OSD(filename = args.filename, roundWidget = args.round)
729 sys.exit(app.exec_())