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/
24 from PyQt4 import QtCore, QtGui
29 _fromUtf8 = QtCore.QString.fromUtf8
30 except AttributeError:
35 _encoding = QtGui.QApplication.UnicodeUTF8
36 def _translate(context, text, disambig):
37 return QtGui.QApplication.translate(context, text, disambig, _encoding)
38 except AttributeError:
39 def _translate(context, text, disambig):
40 return QtGui.QApplication.translate(context, text, disambig)
42 class OSDWidget(QtGui.QWidget):
43 def __init__(self, roundWidget = False):
44 super(OSDWidget, self).__init__()
46 self.roundWidget = roundWidget
47 # parameters that will be modified by the user
54 self.left_txt = "14.8v / 34A\n1.5Ah" # XXX
55 self.right_txt = "23:03 since take-off\n1.4 km to home\nRSSI 60dB" # XXX
56 self.user_frame_cb = None
64 # filtered parameters (0 = no filter, 1 = infinite filter)
65 self.pitch_filter_coef = 0.8
66 self.roll_filter_coef = 0.8
67 self.yaw_filter_coef = 0.8
68 self.speed_filter_coef = 0.8
69 self.alt_filter_coef = 0.8
70 self.rthome_filter_coef = 0.8
71 # QRect representing the viewport
73 # QRect representing the viewport, adjusted to a square
75 self.setMinimumSize(250, 250)
77 # how many degrees between pitch reference lines
80 self.PITCH_REFLINES_STEP_ANGLE = 10.
81 self.PITCH_REFLINES_BOLD_STEP_ANGLE = 30.
82 self.PITCH_REFLINES_NUM_LINES = 6
85 self.PITCH_REFLINES_STEP_ANGLE = 5.
86 self.PITCH_REFLINES_BOLD_STEP_ANGLE = 10.
87 self.PITCH_REFLINES_NUM_LINES = 4
89 self.PITCH_REFLINES_TOTAL_ANGLE = (self.PITCH_REFLINES_STEP_ANGLE *
90 self.PITCH_REFLINES_NUM_LINES)
91 # in fraction of radius
93 # how many degrees between yaw reference lines
94 self.YAW_REFLINES_STEP_ANGLE = 15.
95 self.YAW_REFLINES_NUM_LINES = 12
96 self.YAW_REFLINES_TOTAL_ANGLE = (self.YAW_REFLINES_STEP_ANGLE *
97 self.YAW_REFLINES_NUM_LINES)
98 self.YAW_REFLINES_SIZE_FACTOR = 0.5
100 self.SPEED_REFLINES_STEP = 10.
101 self.SPEED_REFLINES_BOLD_STEP = 50.
102 self.SPEED_REFLINES_NUM_LINES = 10
103 self.SPEED_REFLINES_TOTAL = (self.SPEED_REFLINES_STEP *
104 self.SPEED_REFLINES_NUM_LINES)
105 self.SPEED_REFLINES_SIZE_FACTOR = 0.7
107 self.ALT_REFLINES_STEP = 100.
108 self.ALT_REFLINES_BOLD_STEP = 500.
109 self.ALT_REFLINES_NUM_LINES = 10
110 self.ALT_REFLINES_TOTAL = (self.ALT_REFLINES_STEP *
111 self.ALT_REFLINES_NUM_LINES)
112 self.ALT_REFLINES_SIZE_FACTOR = 0.7
115 self.timer = QtCore.QTimer(self)
116 self.connect(self.timer, QtCore.SIGNAL("timeout()"), self.frameTimerCb)
117 self.timer.start(1000. / self.FPS)
119 def paintEvent(self, evt):
120 """Paint callback, this is the entry point for all drawings."""
121 painter = QtGui.QPainter()
123 painter.setRenderHint(QtGui.QPainter.Antialiasing)
124 self.dev = evt.rect()
125 self.min_dim = min(self.dev.right(), self.dev.bottom())
126 self.max_dim = max(self.dev.right(), self.dev.bottom())
127 self.adjdev = QtCore.QRect(0, 0, self.min_dim, self.min_dim)
128 self.adjdev.moveCenter(self.dev.center())
132 def frameTimerCb(self):
133 """called periodically, every frame, it calls the user_frame_cb function,
134 updates the filter and updates the widget"""
135 if self.user_frame_cb != None:
138 # avoid filter bugs when changing between 180 and -180
139 self.pitch += round((self.user_pitch - self.pitch) / 360.) * 360
140 self.pitch = (self.pitch * self.pitch_filter_coef +
141 self.user_pitch * (1. - self.pitch_filter_coef))
142 self.roll += round((self.user_roll - self.roll) / 360.) * 360
143 self.roll = (self.roll * self.roll_filter_coef +
144 self.user_roll * (1. - self.roll_filter_coef))
145 self.yaw += round((self.user_yaw - self.yaw) / 360.) * 360
146 self.yaw = (self.yaw * self.yaw_filter_coef +
147 self.user_yaw * (1. - self.yaw_filter_coef))
148 self.speed = (self.speed * self.speed_filter_coef +
149 self.user_speed * (1. - self.speed_filter_coef))
150 self.alt = (self.alt * self.alt_filter_coef +
151 self.user_alt * (1. - self.alt_filter_coef))
152 self.rthome += round((self.user_rthome - self.rthome) / 360.) * 360
153 self.rthome = (self.rthome * self.rthome_filter_coef +
154 self.user_rthome * (1. - self.rthome_filter_coef))
157 def draw(self, painter):
158 """Draw the widget."""
160 self.drawHorizonRound(painter)
162 self.drawHorizon(painter)
163 self.drawPitchGraduation(painter)
164 self.drawRollGraduation(painter)
165 self.drawYaw(painter)
166 self.drawCenterRef(painter)
167 if self.roundWidget == False:
168 self.drawSpeed(painter)
169 self.drawAlt(painter)
170 self.drawReturnToHome(painter)
171 self.drawTxtInfo(painter)
173 def getSkyBrush(self):
174 """return the color gradient for the sky (blue)"""
175 sky_gradient = QtGui.QLinearGradient(self.adjdev.topLeft(),
176 self.adjdev.bottomRight())
177 color1 = QtCore.Qt.blue
178 color2 = QtCore.Qt.darkBlue
179 sky_gradient.setColorAt(0, color1)
180 sky_gradient.setColorAt(.8, color2)
183 def getGroundBrush(self):
184 """return the color gradient for the ground (marron)"""
185 ground_gradient = QtGui.QLinearGradient(self.adjdev.topLeft(),
186 self.adjdev.bottomRight())
187 color1 = QtGui.QColor(140, 100, 80)
188 color2 = QtGui.QColor(140, 100, 40)
189 ground_gradient.setColorAt(0, color1)
190 ground_gradient.setColorAt(.8, color2)
191 return ground_gradient
193 def getCenterRadius(self):
194 """Return the radius of the widget circle"""
196 return self.adjdev.width() / 2.
198 return self.adjdev.width() / 3.5
200 def drawHorizonRound(self, painter):
201 """Draw the horizon for round widget: the sky in blue,
202 the ground in marron."""
204 # set local pitch and roll
213 pitch = -180. - pitch
218 # we have to draw a partial circle delimited by its chord, define
219 # where the chord starts
220 start_angle = math.degrees(math.asin(pitch / 90.)) - roll
221 span = 2 * math.degrees(math.asin(pitch / 90.))
224 painter.setBrush(self.getSkyBrush())
225 # startAngle and spanAngle must be specified in 1/16th of a degree
226 painter.drawChord(self.adjdev, 16 * start_angle, 16 * (180. - span))
229 painter.setBrush(self.getGroundBrush())
230 # startAngle and spanAngle must be specified in 1/16th of a degree
231 painter.drawChord(self.adjdev, 16 * start_angle, -16 * (180. + span))
233 def drawHorizon(self, painter):
234 """Draw the horizon: the sky in blue, the ground in marron."""
236 painter.setBrush(self.getSkyBrush())
237 painter.drawRect(self.dev)
238 center = self.adjdev.center()
239 r = self.getCenterRadius()
240 # radius of the adjusted screen (same than r if roundWidget = True)
241 dev_r = self.adjdev.width() / 2.
243 if self.pitch < -90.:
244 pitch = -180 - self.pitch
245 elif self.pitch < 90.:
248 pitch = 180 - self.pitch
249 y_off = (pitch / self.CAM_ANGLE) * dev_r
250 painter.translate(center.x(), center.y())
252 ground_rect = QtCore.QRect(0, 0, self.max_dim * 5., self.max_dim * 5.)
253 if self.pitch < 90. and self.pitch > -90.:
254 ground_rect.moveCenter(QtCore.QPoint(0, -y_off + ground_rect.width()/2.))
256 ground_rect.moveCenter(QtCore.QPoint(0, y_off - ground_rect.width()/2.))
257 painter.setBrush(self.getGroundBrush())
258 painter.drawRect(ground_rect)
261 def drawCenterRef(self, painter):
262 """Draw the cross on the middle of the OSD"""
263 center = self.adjdev.center()
264 r = self.getCenterRadius()
265 pen = QtGui.QPen(QtCore.Qt.red, r / 100., QtCore.Qt.SolidLine)
267 pt1 = QtCore.QPoint(center.x() - 0.05 * r, center.y())
268 pt2 = QtCore.QPoint(center.x() + 0.05 * r, center.y())
269 painter.drawLine(pt1, pt2)
270 pt1 = QtCore.QPoint(center.x(), center.y() + -0.025 * r)
271 pt2 = QtCore.QPoint(center.x(), center.y() + 0.025 * r)
272 painter.drawLine(pt1, pt2)
274 def drawPitchGraduation(self, painter):
275 """Draw the pitch graduations."""
276 # change the reference
278 center = self.adjdev.center()
279 r = self.getCenterRadius()
280 # radius of the adjusted screen (same than r if roundWidget = True)
281 dev_r = self.adjdev.width() / 2.
283 x_off = (self.pitch / self.CAM_ANGLE) * dev_r * math.sin(math.radians(roll))
284 y_off = (self.pitch / self.CAM_ANGLE) * dev_r * math.cos(math.radians(roll))
285 painter.translate(center.x() + x_off, center.y() - y_off)
289 pen = QtGui.QPen(QtCore.Qt.white, r / 100., QtCore.Qt.SolidLine)
291 font = QtGui.QFont("Meiryo UI", 0, QtGui.QFont.Bold)
292 font.setPointSizeF(self.FONT_SIZE * r)
293 painter.setFont(font)
295 # round to nearest angle that is a multiple of step
296 a = self.pitch / self.PITCH_REFLINES_STEP_ANGLE
298 a = int(a * self.PITCH_REFLINES_STEP_ANGLE)
299 a -= self.PITCH_REFLINES_STEP_ANGLE * (self.PITCH_REFLINES_NUM_LINES / 2.)
300 angles = [ a + i * self.PITCH_REFLINES_STEP_ANGLE
301 for i in range(self.PITCH_REFLINES_NUM_LINES + 1) ]
304 if int(a) % int(self.PITCH_REFLINES_BOLD_STEP_ANGLE) != 0:
305 pen = QtGui.QPen(QtCore.Qt.white, r / 100., QtCore.Qt.SolidLine)
307 pt1 = QtCore.QPoint(-0.05 * r, dev_r / self.CAM_ANGLE * a)
308 pt2 = QtCore.QPoint(0.05 * r, dev_r / self.CAM_ANGLE * a)
309 painter.drawLine(pt1, pt2)
313 pen = QtGui.QPen(QtCore.Qt.white, r / 50., QtCore.Qt.SolidLine)
315 pt1 = QtCore.QPoint(-0.2 * r, dev_r / self.CAM_ANGLE * a)
316 pt2 = QtCore.QPoint(0.2 * r, dev_r / self.CAM_ANGLE * a)
317 painter.drawLine(pt1, pt2)
322 disp_val = 180. - disp_val
324 disp_val = -180. - disp_val
325 disp_val = str(int(disp_val))
326 metrics = painter.fontMetrics()
327 sz = metrics.size(QtCore.Qt.TextSingleLine, disp_val)
328 lefttxt = QtCore.QRect(QtCore.QPoint(0, 0), sz)
329 lefttxt.moveCenter(pt1 - QtCore.QPoint(0.2 * r, 0))
331 #brush = QtGui.QBrush(QtCore.Qt.white)
332 #painter.setBrush(brush)
333 #pen.setColor(QtCore.Qt.black);
335 #path = QtGui.QPainterPath()
336 #path.addText(lefttxt.center(), font, disp_val)
337 #painter.drawPath(path)
338 painter.drawText(lefttxt, QtCore.Qt.TextSingleLine, disp_val)
340 # flip the right text
342 painter.translate(pt2 + QtCore.QPoint(0.2 * r, 0))
344 painter.translate(-pt2 - QtCore.QPoint(0.2 * r, 0))
345 righttxt = QtCore.QRect(QtCore.QPoint(0, 0), sz)
346 righttxt.moveCenter(pt2 + QtCore.QPoint(0.2 * r, 0))
347 #path = QtGui.QPainterPath()
348 #path.addText(righttxt.center(), font, disp_val)
349 #painter.drawPath(path)
350 painter.drawText(righttxt, QtCore.Qt.TextSingleLine, disp_val)
355 def drawOneRollGraduation(self, painter, deg, disp_text):
356 # draw the graduiation
357 r = self.getCenterRadius()
358 center = self.adjdev.center()
359 x = center.x() - math.cos(math.radians(deg)) * r
360 y = center.y() - math.sin(math.radians(deg)) * r
361 pt = QtCore.QPoint(x, y)
362 path = QtGui.QPainterPath()
365 pt2 = path.pointAtPercent(0.075) # graduation len is 7.5% of the radius
366 painter.drawLine(pt, pt2)
368 if disp_text == True:
369 pt_txt = path.pointAtPercent(0.2)
370 font = QtGui.QFont("Meiryo UI", 0, QtGui.QFont.Bold)
371 font.setPointSizeF(self.FONT_SIZE * r)
372 painter.setFont(font)
375 disp_val = 180. - disp_val
376 disp_val = str(int(disp_val))
377 metrics = painter.fontMetrics()
378 sz = metrics.size(QtCore.Qt.TextSingleLine, disp_val)
379 txt = QtCore.QRect(QtCore.QPoint(0, 0), sz)
380 txt.moveCenter(pt_txt.toPoint())
381 painter.drawText(txt, QtCore.Qt.TextSingleLine, disp_val)
383 def drawRollGraduation(self, painter):
384 """Draw the roll graduations."""
385 center = self.adjdev.center()
386 r = self.getCenterRadius()
388 # draw the red reference lines (pitch 0)
390 painter.translate(center.x(), center.y())
391 painter.rotate(self.roll)
392 pen = QtGui.QPen(QtCore.Qt.red, r / 100., QtCore.Qt.SolidLine)
394 pt1 = QtCore.QPoint(-0.925 * r, 0)
395 pt2 = QtCore.QPoint(-0.85 * r, 0)
396 painter.drawLine(pt1, pt2)
397 pt1 = QtCore.QPoint(0.925 * r, 0)
398 pt2 = QtCore.QPoint(0.85 * r, 0)
399 painter.drawLine(pt1, pt2)
402 pen = QtGui.QPen(QtCore.Qt.white, r / 50., QtCore.Qt.SolidLine)
414 self.drawOneRollGraduation(painter, deg, disp_text)
417 def drawYaw(self, painter):
418 center = self.adjdev.center()
419 r = self.getCenterRadius()
420 pen = QtGui.QPen(QtCore.Qt.red, r / 100., QtCore.Qt.SolidLine)
422 font = QtGui.QFont("Meiryo UI", 0, QtGui.QFont.Bold)
423 font.setPointSizeF(self.FONT_SIZE * r)
424 painter.setFont(font)
425 if self.roundWidget == True:
426 y_txt = center.y() + r * 0.6
427 y1 = center.y() + r * 0.7
428 y2 = center.y() + r * 0.8
429 y3 = center.y() + r * 0.85
431 y_txt = center.y() + r * 1.
432 y1 = center.y() + r * 1.1
433 y2 = center.y() + r * 1.2
434 y3 = center.y() + r * 1.25
435 pt1 = QtCore.QPoint(center.x(), y2)
436 pt2 = QtCore.QPoint(center.x(), y3)
437 painter.drawLine(pt1, pt2)
439 # round to nearest angle multiple of step
440 a = self.yaw / self.YAW_REFLINES_STEP_ANGLE
442 a = int(a * self.YAW_REFLINES_STEP_ANGLE)
443 a -= self.YAW_REFLINES_STEP_ANGLE * (self.YAW_REFLINES_NUM_LINES / 2.)
444 angles = [ a + i * self.YAW_REFLINES_STEP_ANGLE
445 for i in range(self.YAW_REFLINES_NUM_LINES + 1) ]
450 pen = QtGui.QPen(QtCore.Qt.white, r / 50., QtCore.Qt.SolidLine)
454 pen = QtGui.QPen(QtCore.Qt.white, r / 100., QtCore.Qt.SolidLine)
457 x = center.x() - ((r / (self.YAW_REFLINES_TOTAL_ANGLE / 2.)) *
458 (self.yaw - a) * self.YAW_REFLINES_SIZE_FACTOR)
459 pt_txt = QtCore.QPoint(x, y_txt)
460 pt1 = QtCore.QPoint(x, y1)
461 pt2 = QtCore.QPoint(x, y2)
462 painter.drawLine(pt1, pt2)
463 if disp_text == False:
465 disp_val = ["N", "E", "S", "W"][(int(a)/90)%4]
466 metrics = painter.fontMetrics()
467 sz = metrics.size(QtCore.Qt.TextSingleLine, disp_val)
468 txt = QtCore.QRect(QtCore.QPoint(0, 0), sz)
469 txt.moveCenter(pt_txt)
470 painter.drawText(txt, QtCore.Qt.TextSingleLine, disp_val)
472 def drawSpeed(self, painter):
473 center = self.adjdev.center()
474 r = self.getCenterRadius()
475 pen = QtGui.QPen(QtCore.Qt.red, r / 100., QtCore.Qt.SolidLine)
477 font = QtGui.QFont("Meiryo UI", 0, QtGui.QFont.Bold)
478 font.setPointSizeF(self.FONT_SIZE * r)
479 painter.setFont(font)
480 x1 = center.x() - 1.5 * r
481 x2 = center.x() - 1.6 * r
482 pt1 = QtCore.QPoint(center.x() - 1.45 * r, center.y())
483 pt2 = QtCore.QPoint(x2, center.y())
484 painter.drawLine(pt1, pt2)
486 # round to nearest angle multiple of step
487 s = self.speed / self.SPEED_REFLINES_STEP
489 s = int(s * self.SPEED_REFLINES_STEP)
490 s -= self.SPEED_REFLINES_STEP * (self.SPEED_REFLINES_NUM_LINES / 2.)
491 speeds = [ s + i * self.SPEED_REFLINES_STEP
492 for i in range(self.SPEED_REFLINES_NUM_LINES + 1) ]
494 if int(s) % int(self.SPEED_REFLINES_BOLD_STEP) == 0:
496 pen = QtGui.QPen(QtCore.Qt.white, r / 50., QtCore.Qt.SolidLine)
500 pen = QtGui.QPen(QtCore.Qt.white, r / 100., QtCore.Qt.SolidLine)
503 y = center.y() + ((r / (self.SPEED_REFLINES_TOTAL/2.)) *
504 (self.speed - s) * self.SPEED_REFLINES_SIZE_FACTOR)
505 pt_txt = QtCore.QPoint(center.x() + r * -1.75, y)
506 pt1 = QtCore.QPoint(x1, y)
507 pt2 = QtCore.QPoint(x2, y)
508 painter.drawLine(pt1, pt2)
509 if disp_text == False:
511 disp_val = str(int(s))
512 metrics = painter.fontMetrics()
513 sz = metrics.size(QtCore.Qt.TextSingleLine, disp_val)
514 txt = QtCore.QRect(QtCore.QPoint(0, 0), sz)
515 txt.moveCenter(pt_txt)
516 painter.drawText(txt, QtCore.Qt.TextSingleLine, disp_val)
518 def drawAlt(self, painter):
519 center = self.adjdev.center()
520 r = self.getCenterRadius()
521 pen = QtGui.QPen(QtCore.Qt.red, r / 100., QtCore.Qt.SolidLine)
523 font = QtGui.QFont("Meiryo UI", 0, QtGui.QFont.Bold)
524 font.setPointSizeF(self.FONT_SIZE * r)
525 painter.setFont(font)
526 x1 = center.x() + 1.5 * r
527 x2 = center.x() + 1.6 * r
528 pt1 = QtCore.QPoint(center.x() + 1.45 * r, center.y())
529 pt2 = QtCore.QPoint(x2, center.y())
530 painter.drawLine(pt1, pt2)
532 # round to nearest angle multiple of step
533 a = self.alt / self.ALT_REFLINES_STEP
535 a = int(a * self.ALT_REFLINES_STEP)
536 a -= self.ALT_REFLINES_STEP * (self.ALT_REFLINES_NUM_LINES / 2.)
537 alts = [ a + i * self.ALT_REFLINES_STEP
538 for i in range(self.ALT_REFLINES_NUM_LINES + 1) ]
540 if int(a) % int(self.ALT_REFLINES_BOLD_STEP) == 0:
542 pen = QtGui.QPen(QtCore.Qt.white, r / 50., QtCore.Qt.SolidLine)
546 pen = QtGui.QPen(QtCore.Qt.white, r / 100., QtCore.Qt.SolidLine)
549 y = center.y() + ((r / (self.ALT_REFLINES_TOTAL / 2.)) *
550 (self.alt - a) * self.ALT_REFLINES_SIZE_FACTOR)
551 pt_txt = QtCore.QPoint(center.x() + r * 1.75, y)
552 pt1 = QtCore.QPoint(x1, y)
553 pt2 = QtCore.QPoint(x2, y)
554 painter.drawLine(pt1, pt2)
555 if disp_text == False:
557 disp_val = str(int(a))
558 metrics = painter.fontMetrics()
559 sz = metrics.size(QtCore.Qt.TextSingleLine, disp_val)
560 txt = QtCore.QRect(QtCore.QPoint(0, 0), sz)
561 txt.moveCenter(pt_txt)
562 painter.drawText(txt, QtCore.Qt.TextSingleLine, disp_val)
564 def drawReturnToHome(self, painter):
565 center = self.adjdev.center()
566 r = self.getCenterRadius()
567 dev_r = self.adjdev.width() / 2.
569 painter.translate(center.x(), center.y() - 0.9 * dev_r)
570 painter.rotate(self.yaw) # XXX
571 pen = QtGui.QPen(QtCore.Qt.white, r / 100., QtCore.Qt.SolidLine)
573 poly = QtGui.QPolygonF()
574 poly.append(QtCore.QPoint(0., -0.08 * r))
575 poly.append(QtCore.QPoint(0.04 * r, 0.08 * r))
576 poly.append(QtCore.QPoint(-0.04 * r, 0.08 * r))
577 poly.append(QtCore.QPoint(0., -0.08 * r))
578 path = QtGui.QPainterPath()
579 path.addPolygon(poly)
580 brush = QtGui.QBrush(QtCore.Qt.darkGray)
581 painter.setBrush(brush)
582 painter.drawPath(path)
585 def drawTxtInfo(self, painter):
586 center = self.adjdev.center()
587 dev_r = self.adjdev.width() / 2.
588 r = self.getCenterRadius()
589 pen = QtGui.QPen(QtCore.Qt.white, r / 100., QtCore.Qt.SolidLine)
591 font = QtGui.QFont("Meiryo UI", 0, QtGui.QFont.Bold)
592 font.setPointSizeF(self.FONT_SIZE * r)
593 metrics = painter.fontMetrics()
595 sz = metrics.size(QtCore.Qt.AlignLeft, self.left_txt)
596 txt = QtCore.QRect(QtCore.QPoint(0, 0), sz)
597 pt_txt = QtCore.QPoint(center.x() + dev_r * -0.95,
598 center.y() + dev_r * -0.95)
599 txt.moveTopLeft(pt_txt)
600 painter.drawText(txt, QtCore.Qt.AlignLeft, self.left_txt)
602 sz = metrics.size(QtCore.Qt.AlignRight, self.right_txt)
603 txt = QtCore.QRect(QtCore.QPoint(0, 0), sz)
604 pt_txt = QtCore.QPoint(center.x() + dev_r * 0.95,
605 center.y() + dev_r * -0.95)
606 txt.moveTopRight(pt_txt)
607 painter.drawText(txt, QtCore.Qt.AlignRight, self.right_txt)
609 def setPitch(self, pitch):
610 """set the pitch in degrees, between -180 and 180"""
614 self.user_pitch = pitch
616 def setRoll(self, roll):
617 """set the roll in degrees, between -180 and 180"""
621 self.user_roll = roll
623 def setYaw(self, yaw):
624 """set the yaw in degrees, between 0 and 360"""
628 def setSpeed(self, speed):
630 self.user_speed = speed
632 def setAlt(self, alt):
636 def setReturnToHomeAngle(self, angle):
637 """set the left text"""
638 self.user_rthome = angle
640 def setLeftTxt(self, txt):
641 """set the right text"""
644 def setRightTxt(self, txt):
645 """set the left text"""
648 def setFrameCb(self, user_frame_cb):
649 """set a function that is called every frame, before updating the widget"""
650 self.user_frame_cb = user_frame_cb
652 class Ui_MainWindow(object):
653 def __init__(self, filename = None, roundWidget = False):
654 self.roundWidget = roundWidget
655 self.filename = filename
657 def update_fpv_info(self):
659 self.osd.user_speed = self.osd.user_speed + 1
660 self.osd.setRoll(self.fpv.roll)
661 self.osd.setPitch(self.fpv.pitch)
662 self.osd.setYaw(self.fpv.yaw)
664 def setupUi(self, MainWindow):
665 MainWindow.setObjectName(_fromUtf8("MainWindow"))
666 MainWindow.resize(400, 300)
667 self.centralWidget = QtGui.QWidget(MainWindow)
668 self.centralWidget.setObjectName(_fromUtf8("centralWidget"))
669 self.gridLayout = QtGui.QGridLayout(self.centralWidget)
670 self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
672 self.pitchSlider = QtGui.QSlider(self.centralWidget)
673 self.pitchSlider.setMinimum(-180)
674 self.pitchSlider.setMaximum(180)
675 self.pitchSlider.setOrientation(QtCore.Qt.Vertical)
676 self.pitchSlider.setObjectName(_fromUtf8("pitchSlider"))
677 self.pitchSlider.valueChanged[int].connect(self.changePitch)
678 self.gridLayout.addWidget(self.pitchSlider, 0, 0)
680 self.osd = OSDWidget(self.roundWidget)
682 self.fpv = serialfpv.SerialFPV()
683 self.fpv.open_file(self.filename)
684 self.osd.setFrameCb(self.update_fpv_info)
685 self.gridLayout.addWidget(self.osd, 0, 1)
687 self.rollSlider = QtGui.QSlider(self.centralWidget)
688 self.rollSlider.setMinimum(-180)
689 self.rollSlider.setMaximum(180)
690 self.rollSlider.setOrientation(QtCore.Qt.Horizontal)
691 self.rollSlider.setObjectName(_fromUtf8("rollSlider"))
692 self.rollSlider.valueChanged[int].connect(self.changeRoll)
693 self.gridLayout.addWidget(self.rollSlider, 1, 1)
695 self.yawSlider = QtGui.QSlider(self.centralWidget)
696 self.yawSlider.setMaximum(360)
697 self.yawSlider.setProperty("value", 180)
699 self.yawSlider.setOrientation(QtCore.Qt.Horizontal)
700 self.yawSlider.setObjectName(_fromUtf8("yawSlider"))
701 self.yawSlider.valueChanged[int].connect(self.changeYaw)
702 self.gridLayout.addWidget(self.yawSlider, 2, 1)
704 MainWindow.setCentralWidget(self.centralWidget)
705 self.menuBar = QtGui.QMenuBar(MainWindow)
706 self.menuBar.setGeometry(QtCore.QRect(0, 0, 400, 23))
707 self.menuBar.setObjectName(_fromUtf8("menuBar"))
708 MainWindow.setMenuBar(self.menuBar)
709 self.mainToolBar = QtGui.QToolBar(MainWindow)
710 self.mainToolBar.setObjectName(_fromUtf8("mainToolBar"))
711 MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.mainToolBar)
712 self.statusBar = QtGui.QStatusBar(MainWindow)
713 self.statusBar.setObjectName(_fromUtf8("statusBar"))
714 MainWindow.setStatusBar(self.statusBar)
716 self.retranslateUi(MainWindow)
717 QtCore.QMetaObject.connectSlotsByName(MainWindow)
719 def retranslateUi(self, MainWindow):
720 MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
722 def changePitch(self, value):
723 self.osd.setPitch(value)
726 def changeRoll(self, value):
727 self.osd.setRoll(value)
730 def changeYaw(self, value):
731 self.osd.setYaw(value)
734 if __name__ == "__main__":
736 app = QtGui.QApplication(sys.argv)
737 if "round" in sys.argv:
741 MainWindow = QtGui.QMainWindow()
742 if len(sys.argv) > 1:
743 ui = Ui_MainWindow(sys.argv[1], roundWidget)
745 ui = Ui_MainWindow(roundWidget = roundWidget)
746 ui.setupUi(MainWindow)
748 sys.exit(app.exec_())