diff --git a/rqt_robot_dashboard/src/rqt_robot_dashboard/battery_dash_widget.py b/rqt_robot_dashboard/src/rqt_robot_dashboard/battery_dash_widget.py index 4c1fa0ba..89e25bb9 100644 --- a/rqt_robot_dashboard/src/rqt_robot_dashboard/battery_dash_widget.py +++ b/rqt_robot_dashboard/src/rqt_robot_dashboard/battery_dash_widget.py @@ -30,10 +30,16 @@ # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -from .icon_tool_button import IconToolButton +import os +import rospkg +from python_qt_binding.QtCore import Signal, QSize +from python_qt_binding.QtGui import QIcon, QLabel +from .util import IconHelper -class BatteryDashWidget(IconToolButton): +class BatteryDashWidget(QLabel): + + state_changed = Signal(int) """ A Widget which displays incremental battery state, including a status tip. To use this widget simply call :func:`update_perc` and :func:`update_time` to change the displayed charge percentage and time remaining, respectively. @@ -41,22 +47,83 @@ class BatteryDashWidget(IconToolButton): :param name: The name of this widget :type name: str """ - def __init__(self, name='Battery', icons=None, charge_icons=None, icon_paths=None): + def __init__(self, name='Battery', icons=None, charge_icons=None, icon_paths=None, suppress_overlays=False): + super(BatteryDashWidget, self).__init__() if icons == None: icons = [] charge_icons = [] for x in range(6): icons.append(['ic-battery-%s.svg' % (x * 20)]) charge_icons.append(['ic-battery-charge-%s.svg' % (x * 20)]) - super(BatteryDashWidget, self).__init__(name, icons, charge_icons, icon_paths=icon_paths) - self.setEnabled(False) - - self._charge_icons = self._clicked_icons - self.setStyleSheet('QToolButton:disabled {}') - + icon_paths = (icon_paths if icon_paths else []) + [['rqt_robot_dashboard', 'images']] + paths = [] + for path in icon_paths: + paths.append(os.path.join(rospkg.RosPack().get_path(path[0]), path[1])) + self._icon_helper = IconHelper(paths) + self.set_icon_lists(icons, charge_icons, suppress_overlays) + self._name = name self._charging = False - + self.__state = 0 + self.setMargin(5) + self.state_changed.connect(self._update_state) self.update_perc(0) + self.update_time(0) + + def _update_state(self, state): + if self._charging: + self.setPixmap(self._charge_icons[state].pixmap(QSize(60, 100))) + else: + self.setPixmap(self._icons[state].pixmap(QSize(60, 100))) + + @property + def state(self): + """ + Read-only accessor for the widgets current state. + """ + return self.__state + + def set_icon_lists(self, icons, charge_icons=None, suppress_overlays=False): + """ + Sets up the icon lists for the button states. + There must be one index in icons for each state. + + :raises IndexError: if ``icons`` is not a list of lists of strings + + :param icons: A list of lists of strings to create icons for the states of this button.\ + If only one is supplied then ok, warn, error, stale icons will be created with overlays + :type icons: list + :param charge_icons: A list of clicked state icons. len must equal icons + :type charge_icons: list + :param suppress_overlays: if false and there is only one icon path supplied + :type suppress_overlays: bool + """ + if charge_icons is not None and len(icons) != len(charge_icons): + rospy.logerr("%s: icons and clicked states are unequal" % self._name) + icons = charge_icons = ['ic-missing-icon.svg'] + if not (type(icons) is list and type(icons[0]) is list and type(icons[0][0] is str)): + raise(IndexError("icons must be a list of lists of strings")) + if len(icons) <= 0: + rospy.logerr("%s: Icons not supplied" % self._name) + icons = charge_icons = ['ic-missing-icon.svg'] + if len(icons) == 1 and suppress_overlays == False: + if icons[0][0][-4].lower() == '.svg': + icons.append(icons[0] + ['ol-warn-badge.svg']) + icons.append(icons[0] + ['ol-err-badge.svg']) + icons.append(icons[0] + ['ol-stale-badge.svg']) + else: + icons.append(icons[0] + ['warn-overlay.png']) + icons.append(icons[0] + ['err-overlay.png']) + icons.append(icons[0] + ['stale-overlay.png']) + if charge_icons is None: + charge_icons = [] + for name in icons: + charge_icons.append(name + ['ol-click.svg']) + self._icons = [] + for icon in icons: + self._icons.append(self._icon_helper.build_icon(icon)) + self._charge_icons = [] + for icon in charge_icons: + self._charge_icons.append(self._icon_helper.build_icon(icon)) def set_charging(self, value): self._charging = value @@ -70,15 +137,25 @@ def update_perc(self, val): """ self.update_state(round(val / 20.0)) - def _update_state(self, state): - if self._charging: - self.setIcon(self._charge_icons[state]) + def update_state(self, state): + """ + Set the state of this button. + This will also update the icon for the button based on the ``self._icons`` list + + :raises IndexError: If state is not a proper index to ``self._icons`` + + :param state: The state to set. + :type state: int + """ + if 0 <= state and state < len(self._icons): + self.__state = state + self.state_changed.emit(self.__state) else: - self.setIcon(self._icons[state]) + raise IndexError("%s update_state received invalid state: %s" % (self._name, state)) def update_time(self, value): try: fval = float(value) - self.setToolTip("%s: %.2f%% remaining" % (self.name, fval)) + self.setToolTip("%s: %.2f%% remaining" % (self._name, fval)) except ValueError: - self.setToolTip("%s: %s%% remaining" % (self.name, value)) + self.setToolTip("%s: %s%% remaining" % (self._name, value))