def test_save_prefs(self): coolant_range = Range(1, 10, color=[2, 2, 2, 2]) rpm_range = Range(100, 10000, color=[3, 3, 3, 3]) self.userprefs.set_range_alert('Coolant', coolant_range) self.userprefs.set_range_alert('RPM', rpm_range) self.userprefs.save() #Did it create the file in the right location? self.assertTrue( os.path.isfile(self.data_dir + '/' + self.userprefs.prefs_file_name)) newprefs = UserPrefs(self.data_dir, save_timeout=1000) #newprefs should load the prefs file new_coolant = newprefs.get_range_alert('Coolant') new_rpm = newprefs.get_range_alert('RPM') self.assertEquals(coolant_range.min, new_coolant.min, "Range min not saved and loaded from prefs file") self.assertEquals(coolant_range.max, new_coolant.max, "Range max not saved and loaded from prefs file") self.assertEquals(coolant_range.color, new_coolant.color, "Range color not saved and loaded from prefs file") self.assertEquals(rpm_range.min, new_rpm.min, "Range min not saved and loaded from prefs file") self.assertEquals(rpm_range.max, new_rpm.max, "Range max not saved and loaded from prefs file") self.assertEquals(rpm_range.color, new_rpm.color, "Range color not saved and loaded from prefs file")
def init_view(self): channel = self.channel channelMeta = self.channelMeta if channel and channelMeta: self.valueFormat = '{0:.' + str(self.channelMeta.precision) + 'f}' warnRange = self.settings.userPrefs.get_range_alert( self.getWarnPrefsKey(channel), Range(min=channelMeta.max, max=channelMeta.max, color=Range.DEFAULT_WARN_COLOR)) alertRange = self.settings.userPrefs.get_range_alert( self.getAlertPrefsKey(channel), Range(min=channelMeta.max, max=channelMeta.max, color=Range.DEFAULT_ALERT_COLOR)) self.setupSlider(self.ids.warnLowSlider, channelMeta, warnRange.min) self.setupSlider(self.ids.warnHighSlider, channelMeta, warnRange.max) self.setupSlider(self.ids.alertLowSlider, channelMeta, alertRange.min) self.setupSlider(self.ids.alertHighSlider, channelMeta, alertRange.max) self.ids.selectedWarnColor.color = warnRange.color self.ids.selectedAlertColor.color = alertRange.color self.alertRange = alertRange self.warnRange = warnRange
def test_range_to_json(self): expected = '{"color": [2, 2, 2, 2], "max": 10, "min": 0}' min = 0 max = 10 color = [2, 2, 2, 2] range = Range(min, max, color=color) range_json = range.to_json() self.assertEquals(expected, range_json, "Range to_json output does not match expected output")
def test_range_from_dict(self): min = 0 max = 10 color = [2, 2, 2, 2] original_range = Range(min, max, color=color) range_dict = original_range.to_dict() new_range = Range.from_dict(range_dict) self.assertEquals(original_range.max, new_range.max, "New and old range max do not match") self.assertEquals(original_range.min, new_range.min, "New and old range min do not match") self.assertEquals(original_range.color, new_range.color, "New and old range color does not match")
def __init__(self, **kwargs): self.settings = None self.channel = None self.channelMeta = None self.warnRange = Range() self.alertRange = Range() self.valueFormat = '{0:.0f}' super(ChannelCustomizationView, self).__init__(**kwargs) self.register_event_type('on_channel_customization_close') self.settings = kwargs.get('settings') self.channel = kwargs.get('channel') self.channelMeta = self.settings.runtimeChannels.findChannelMeta(self.channel) self.init_view()
def test_set_get_range_alert(self): test_range = Range(1, 10) self.userprefs.set_range_alert('Coolant', test_range) fetched_range = self.userprefs.get_range_alert('Coolant') self.assertEquals(test_range.min, fetched_range.min, "Saved range and fetched range do not match")
def test_range_constructor(self): min = 0 max = 10 color = [2, 2, 2, 2] range = Range(minimum=min, maximum=max, color=color) self.assertEquals(min, range.min, msg="Range did not set min property") self.assertEquals(max, range.max, msg="Range did not set max property") self.assertEquals(color, range.color, msg="Range did not set color property")
def save_timer(self): prefs = UserPrefs(self.data_dir, save_timeout=1) rpm_range = Range(1000, 8000) prefs.set_range_alert('RPM', rpm_range) time.sleep(3) new_prefs = UserPrefs(self.data_dir, save_timeout=1000) new_rpm_range = new_prefs.get_range_alert('RPM') self.assertEquals(rpm_range.min, new_rpm_range.min, "UserPrefs not saved automatically")
def test_range_is_in_range(self): min = 0 max = 10 color = [2, 2, 2, 2] range = Range(min, max, color=color) self.assertTrue(range.is_in_range(0)) self.assertTrue(range.is_in_range(10)) self.assertTrue(range.is_in_range(5)) self.assertFalse(range.is_in_range(-1)) self.assertFalse(range.is_in_range(11))
class CustomizableGauge(ButtonBehavior, SingleChannelGauge): _popup = None _customizeGaugeBubble = None warning = ObjectProperty(Range()) alert = ObjectProperty(Range()) min = NumericProperty(DEFAULT_MIN) max = NumericProperty(DEFAULT_MAX) _dismiss_customization_popup_trigger = None is_removable = BooleanProperty(True) is_channel_selectable = BooleanProperty(True) def __init__(self, **kwargs): super(CustomizableGauge, self).__init__(**kwargs) self._dismiss_customization_popup_trigger = Clock.create_trigger( self._dismiss_popup, POPUP_DISMISS_TIMEOUT_LONG) def _remove_customization_bubble(self, *args): try: if self._customizeGaugeBubble: self._customizeGaugeBubble.dismiss() self._customizeGaugeBubble = None except: pass def _get_warn_prefs_key(self, channel): return '{}.warn'.format(self.channel) def _get_alert_prefs_key(self, channel): return '{}.alert'.format(self.channel) def _update_channel_ranges(self): channel = self.channel user_prefs = self.settings.userPrefs self.warning = user_prefs.get_range_alert( self._get_warn_prefs_key(channel), self.warning) self.alert = user_prefs.get_range_alert( self._get_alert_prefs_key(channel), self.alert) def removeChannel(self): self._remove_customization_bubble() channel = self.channel if channel: self.data_bus.removeChannelListener(channel, self.setValue) self.channel = None def customizeGauge(self, *args): self._remove_customization_bubble() self.showChannelConfigDialog() def selectChannel(self, *args): self._remove_customization_bubble() self.showChannelSelectDialog() def select_alert_color(self): value = self.value color = self.normal_color if self.alert and self.alert.is_in_range(value): color = self.alert.color elif self.warning and self.warning.is_in_range(value): color = self.warning.color return color def updateColors(self): view = self.valueView if view: view.color = self.select_alert_color() def showChannelSelectDialog(self): content = ChannelSelectView(settings=self.settings, channel=self.channel) content.bind(on_channel_selected=self.channel_selected) content.bind(on_channel_cancel=self._dismiss_popup) popup = Popup(title="Select Channel", content=content, size_hint=(0.5, 0.7)) popup.bind(on_dismiss=self.popup_dismissed) popup.open() self._popup = popup self._dismiss_customization_popup_trigger() def on_channel_customization_close(self, instance, warn_range, alert_range, *args): try: self.warning = warn_range self.alert = alert_range except Exception as e: Logger.error("Gauge: Error customizing channel: " + str(e)) self._dismiss_popup() def showChannelConfigDialog(self): content = ChannelCustomizationView(settings=self.settings, channel=self.channel) content.bind( on_channel_customization_close=self.on_channel_customization_close) popup = Popup(title='Customize {}'.format(self.channel), content=content, size_hint=(0.6, 0.8)) popup.bind(on_dismiss=self.popup_dismissed) popup.open() self._popup = popup self._dismiss_customization_popup_trigger() def channel_selected(self, instance, value): if self.channel: self.data_bus.removeChannelListener(self.channel, self.setValue) self.value = None self.channel = value self.settings.userPrefs.set_gauge_config(self.rcid, value) self._dismiss_popup() def popup_dismissed(self, *args): self._popup = None def _dismiss_popup(self, *args): if self._popup: self._popup.dismiss() self._popup = None def on_release(self): if not self.channel: self.showChannelSelectDialog() else: bubble = CustomizeGaugeBubble() buttons = [] if self.is_removable: buttons.append( BubbleButton(text='Remove', on_press=lambda a: self.removeChannel())) if self.is_channel_selectable: buttons.append( BubbleButton(text='Select Channel', on_press=lambda a: self.selectChannel())) buttons.append( BubbleButton(text='Customize', on_press=lambda a: self.customizeGauge())) if len(buttons) == 1: buttons[0].dispatch('on_press') else: for b in buttons: bubble.add_widget(b) bubble_height = dp(150) bubble_width = dp(200) bubble.size = (bubble_width, bubble_height) bubble.center_on_limited(self) bubble.auto_dismiss_timeout(POPUP_DISMISS_TIMEOUT_SHORT) self._customizeGaugeBubble = bubble self.add_widget(bubble)
class Gauge(ButtonBehavior, AnchorLayout): _customizeGaugeBubble = None _valueView = None is_removable = BooleanProperty(True) is_channel_selectable = BooleanProperty(True) settings = ObjectProperty(None) value_size = NumericProperty(0) title_size = NumericProperty(0) channel = StringProperty(None, allownone=True) title = StringProperty('') value = NumericProperty(None, allownone=True) valueFormat = "{:.0f}" precision = NumericProperty(DEFAULT_PRECISION) warning = ObjectProperty(Range()) alert = ObjectProperty(Range()) min = NumericProperty(DEFAULT_MIN) max = NumericProperty(DEFAULT_MAX) title_color = ObjectProperty(DEFAULT_NORMAL_COLOR) normal_color = ObjectProperty(DEFAULT_NORMAL_COLOR) pressed = ListProperty([0, 0]) data_bus = ObjectProperty(None) rcid = None _popup = None _dismiss_customization_popup_trigger = None def __init__(self, **kwargs): super(Gauge, self).__init__(**kwargs) self.rcid = kwargs.get('rcid', self.rcid) self.data_bus = kwargs.get('dataBus', self.data_bus) self.settings = kwargs.get('settings', self.settings) self.channel = kwargs.get('targetchannel', self.channel) self._dismiss_customization_popup_trigger = Clock.create_trigger( self._dismiss_popup, POPUP_DISMISS_TIMEOUT_LONG) def _remove_customization_bubble(self, *args): try: if self._customizeGaugeBubble: self._customizeGaugeBubble.dismiss() self._customizeGaugeBubble = None except: pass def _get_warn_prefs_key(self, channel): return '{}.warn'.format(self.channel) def _get_alert_prefs_key(self, channel): return '{}.alert'.format(self.channel) def _update_channel_ranges(self): channel = self.channel user_prefs = self.settings.userPrefs self.warning = user_prefs.get_range_alert( self._get_warn_prefs_key(channel), self.warning) self.alert = user_prefs.get_range_alert( self._get_alert_prefs_key(channel), self.alert) def removeChannel(self): self._remove_customization_bubble() channel = self.channel if channel: self.data_bus.removeChannelListener(channel, self.setValue) self.channel = None def customizeGauge(self, *args): self._remove_customization_bubble() self.showChannelConfigDialog() def selectChannel(self, *args): self._remove_customization_bubble() self.showChannelSelectDialog() @property def valueView(self): if not self._valueView: self._valueView = kvFind(self, 'rcid', 'value') return self._valueView @property def titleView(self): return kvFind(self, 'rcid', 'title') def select_alert_color(self): value = self.value color = self.normal_color if self.alert and self.alert.is_in_range(value): color = self.alert.color elif self.warning and self.warning.is_in_range(value): color = self.warning.color return color def updateColors(self): view = self.valueView if view: view.color = self.select_alert_color() def on_value(self, instance, value): view = self.valueView if value != None: if view: view.text = self.valueFormat.format(value) self.updateColors() else: view.text = '' def on_title(self, instance, value): if not value == None: view = kvFind(self, 'rcid', 'title') view.text = str(value) def on_precision(self, instance, value): self.valueFormat = '{:.' + str(value) + 'f}' def on_title_color(self, instance, value): self.titleView.color = value def on_value_size(self, instance, value): view = self.valueView if view: view.font_size = value def on_title_size(self, instance, value): view = self.titleView if view: view.font_size = value def setValue(self, value): self.value = value def showChannelSelectDialog(self): content = ChannelSelectView(settings=self.settings, channel=self.channel) content.bind(on_channel_selected=self.channel_selected) content.bind(on_channel_cancel=self._dismiss_popup) popup = Popup(title="Select Channel", content=content, size_hint=(0.5, 0.7)) popup.bind(on_dismiss=self.popup_dismissed) popup.open() self._popup = popup self._dismiss_customization_popup_trigger() def on_channel_customization_close(self, instance, warn_range, alert_range, *args): try: self.warning = warn_range self.alert = alert_range except Exception as e: print("Error customizing channel: " + str(e)) self._dismiss_popup() def showChannelConfigDialog(self): content = ChannelCustomizationView(settings=self.settings, channel=self.channel) content.bind( on_channel_customization_close=self.on_channel_customization_close) popup = Popup(title='Customize {}'.format(self.channel), content=content, size_hint=(0.6, 0.7)) popup.bind(on_dismiss=self.popup_dismissed) popup.open() self._popup = popup self._dismiss_customization_popup_trigger() def channel_selected(self, instance, value): if self.channel: self.data_bus.removeChannelListener(self.channel, self.setValue) self.value = None self.channel = value self.settings.userPrefs.set_gauge_config(self.rcid, value) self._dismiss_popup() def popup_dismissed(self, *args): self._popup = None def _dismiss_popup(self, *args): if self._popup: self._popup.dismiss() self._popup = None def on_channel(self, instance, value): try: self._update_display() self.update_title() self._update_channel_binding() self._update_channel_ranges() except Exception as e: print('Error setting channel {} {}'.format(value, str(e))) def on_settings(self, instance, value): #Do I have an id so I can track my settings? if self.rcid: channel = self.settings.userPrefs.get_gauge_config(self.rcid) if channel: self.channel = channel def on_data_bus(self, instance, value): self._update_channel_binding() def update_title(self): try: channel = self.channel if channel: channelMeta = self.settings.systemChannels.channels.get( channel) title = channelMeta.name if channelMeta.units and len(channelMeta.units): title += '\n({})'.format(channelMeta.units) self.title = title else: self.title = '' except Exception as e: print('Failed to update gauge title & units ' + str(e)) def _update_display(self): try: channelMeta = self.settings.systemChannels.channels.get( self.channel) if channelMeta: self.min = channelMeta.min self.max = channelMeta.max self.precision = channelMeta.precision else: self.min = DEFAULT_MIN self.max = DEFAULT_MAX self.precision = DEFAULT_PRECISION self.value = DEFAULT_VALUE except Exception as e: print('Failed to update gauge min/max ' + str(e)) def _update_channel_binding(self): dataBus = self.data_bus channel = self.channel if dataBus and channel: dataBus.addChannelListener(str(channel), self.setValue) def on_release(self): if not self.channel: self.showChannelSelectDialog() else: bubble = CustomizeGaugeBubble() buttons = [] if self.is_removable: buttons.append( BubbleButton(text='Remove', on_press=lambda a: self.removeChannel())) if self.is_channel_selectable: buttons.append( BubbleButton(text='Select Channel', on_press=lambda a: self.selectChannel())) buttons.append( BubbleButton(text='Customize', on_press=lambda a: self.customizeGauge())) if len(buttons) == 1: buttons[0].dispatch('on_press') else: for b in buttons: bubble.add_widget(b) bubble_height = dp(150) bubble_width = dp(200) bubble.size = (bubble_width, bubble_height) bubble.center_on_limited(self) bubble.auto_dismiss_timeout(POPUP_DISMISS_TIMEOUT_SHORT) self._customizeGaugeBubble = bubble self.add_widget(bubble)