timeline_view.py
Go to the documentation of this file.
1 # Software License Agreement (BSD License)
2 #
3 # Copyright (c) 2012, Willow Garage, Inc.
4 # All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 #
10 # * Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # * Redistributions in binary form must reproduce the above
13 # copyright notice, this list of conditions and the following
14 # disclaimer in the documentation and/or other materials provided
15 # with the distribution.
16 # * Neither the name of Willow Garage, Inc. nor the names of its
17 # contributors may be used to endorse or promote products derived
18 # from this software without specific prior written permission.
19 #
20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 # POSSIBILITY OF SUCH DAMAGE.
32 #
33 # Author: Isaac Saito, Ze'ev Klapow, Austin Hendrix
34 
35 from math import floor
36 from collections import deque
37 import rospy
38 
39 from python_qt_binding.QtCore import QPointF, Signal, Slot
40 from python_qt_binding.QtGui import QColor, QIcon
41 from python_qt_binding.QtWidgets import QGraphicsPixmapItem, QGraphicsView, \
42  QGraphicsScene
43 
45 from diagnostic_msgs.msg import DiagnosticStatus
46 
47 
48 class TimelineView(QGraphicsView):
49  """
50  This class draws a graphical representation of a timeline.
51 
52  This is ONLY the bar and colored boxes.
53 
54  When you instantiate this class, do NOT forget to call set_init_data to
55  set necessary data.
56  """
57 
58  paused = Signal(bool)
59  position_changed = Signal(int)
60  redraw = Signal()
61 
62  def __init__(self, parent=None):
63  """Cannot take args other than parent due to loadUi limitation."""
64 
65  super(TimelineView, self).__init__(parent=parent)
66  self._timeline_marker = QIcon.fromTheme('system-search')
67 
68  self._min = 0
69  self._max = 0
70  self._xpos_marker = 5
71 
74  self._last_marker_at = 2
75 
76  self.setUpdatesEnabled(True)
77  self._scene = QGraphicsScene(self)
78  self.setScene(self._scene)
79 
80  self._levels = None
81 
82  self.redraw.connect(self._signal_redraw)
83 
84  def mouseReleaseEvent(self, event):
85  """
86  :type event: QMouseEvent
87  """
88  xpos = self.pos_from_x(event.x())
89  self.set_marker_pos(xpos)
90 
91  def mousePressEvent(self, event):
92  """
93  :type event: QMouseEvent
94  """
95  # Pause the timeline
96  self.paused.emit(True)
97 
98  xpos = self.pos_from_x(event.x())
99  self.set_marker_pos(xpos)
100 
101  def mouseMoveEvent(self, event):
102  """
103  :type event: QMouseEvent
104  """
105  xpos = self.pos_from_x(event.x())
106  self.set_marker_pos(xpos)
107 
108  def pos_from_x(self, x):
109  """
110  Get the index in the timeline from the mouse click position
111 
112  :param x: Position relative to self widget.
113  :return: Index
114  """
115  width = self.size().width()
116  # determine value from mouse click
117  width_cell = width / float(max(len(self._levels), 1))
118  return int(floor(x / width_cell))
119 
120  @Slot(int)
121  def set_marker_pos(self, xpos):
122  """
123  Set marker position from index
124 
125  :param xpos: Marker index
126  """
127  if self._levels is None:
128  rospy.logwarn('Called set_marker_pos before set_levels')
129  return
130 
131  if xpos == -1:
132  # stick to the latest when position is -1
133  self._xpos_marker = xpos
134  self.redraw.emit()
135  return
136 
137  self._xpos_marker = self._clamp(xpos, self._min, self._max)
138 
139  if self._xpos_marker == self._last_marker_at:
140  # Clicked the same pos as last time.
141  return
142  elif self._xpos_marker >= len(self._levels):
143  # When clicked out-of-region
144  return
145 
146  self._last_marker_at = self._xpos_marker
147 
148  # Set timeline position. This broadcasts the message at that position
149  # to all of the other viewers
150  self.position_changed.emit(self._xpos_marker)
151  self.redraw.emit()
152 
153  def _clamp(self, val, min, max):
154  """
155  Judge if val is within the range given by min & max.
156  If not, return either min or max.
157 
158  :type val: any number format
159  :type min: any number format
160  :type max: any number format
161  :rtype: int
162  """
163  if (val < min):
164  return min
165  if (val > max):
166  return max
167  return val
168 
169  @Slot(list)
170  def set_levels(self, levels):
171  self._levels = levels
172  self.redraw.emit()
173 
174  @Slot()
175  def _signal_redraw(self):
176  """
177  Gets called either when new msg comes in or when marker is moved by
178  user.
179  """
180  if self._levels is None:
181  return
182 
183  # update the limits
184  self._min = 0
185  self._max = len(self._levels)-1
186 
187  self._scene.clear()
188 
189  qsize = self.size()
190  width_tl = qsize.width()
191 
192  w = width_tl / float(max(len(self._levels), 1))
193  is_enabled = self.isEnabled()
194 
195  for i, level in enumerate(self._levels):
196  h = self.viewport().height()
197 
198  # Figure out each cell's color.
199  qcolor = QColor('grey')
200  if is_enabled and level is not None:
201  if level > DiagnosticStatus.ERROR:
202  # Stale items should be reported as errors unless all stale
203  level = DiagnosticStatus.ERROR
204  qcolor = util.level_to_color(level)
205 # TODO Use this code for adding gradation to the cell color.
206 # end_color = QColor(0.5 * QColor('red').value(),
207 # 0.5 * QColor('green').value(),
208 # 0.5 * QColor('blue').value())
209 
210  self._scene.addRect(w * i, 0, w, h, QColor('white'), qcolor)
211 
212  # Setting marker.
213  xpos_marker = self._xpos_marker
214  while xpos_marker < 0:
215  xpos_marker += len(self._levels)
216  xpos_marker = (xpos_marker * w +
217  (w / 2.0) - (self._timeline_marker_width / 2.0))
218  pos_marker = QPointF(xpos_marker, 0)
219 
220  # Need to instantiate marker everytime since it gets deleted
221  # in every loop by scene.clear()
222  timeline_marker = self._instantiate_tl_icon()
223  timeline_marker.setPos(pos_marker)
224  self._scene.addItem(timeline_marker)
225 
227  timeline_marker_icon = QIcon.fromTheme('system-search')
228  timeline_marker_icon_pixmap = timeline_marker_icon.pixmap(
231  return QGraphicsPixmapItem(timeline_marker_icon_pixmap)


rqt_robot_monitor
Author(s): Austin Hendrix, Isaac Saito, Ze'ev Klapow, Kevin Watts, Josh Faust
autogenerated on Thu Jun 4 2020 03:46:53