class SbpRelayView(HasTraits): """ Class allows user to specify port, IP address, and message set to relay over UDP. """ running = Bool(False) _network_info = List() configured = Bool(False) broadcasting = Bool(False) msg_enum = Enum('Observations', 'All') ip_ad = String(DEFAULT_UDP_ADDRESS) port = Int(DEFAULT_UDP_PORT) information = String( 'UDP Streaming\n\nBroadcast SBP information received by' ' the console to other machines or processes over UDP. With the \'Observations\'' ' radio button selected, the console will broadcast the necessary information' ' for a rover Piksi to acheive an RTK solution.' '\n\nThis can be used to stream observations to a remote Piksi through' ' aircraft telemetry via ground control software such as MAVProxy or' ' Mission Planner.') start = Button(label='Start', toggle=True, width=32) stop = Button(label='Stop', toggle=True, width=32) network_refresh_button = SVGButton( label='Refresh Network Status', tooltip='Refresh Network Status', filename=resource_filename('console/images/fontawesome/refresh.svg'), width=16, height=16, aligment='center') cell_modem_view = Instance(CellModemView) view = View( VGroup( spring, HGroup( VGroup( Item('msg_enum', label="Messages to broadcast", style='custom', enabled_when='not running'), Item('ip_ad', label='IP Address', enabled_when='not running'), Item('port', label="Port", enabled_when='not running'), HGroup( spring, UItem('start', enabled_when='not running', show_label=False), UItem('stop', enabled_when='running', show_label=False), spring)), VGroup( Item('information', label="Notes", height=10, editor=MultilineTextEditor( TextEditor(multi_line=True)), style='readonly', show_label=False, resizable=True, padding=15), spring, )), spring, HGroup( Item('cell_modem_view', style='custom', show_label=False), VGroup(Item( '_network_info', style='readonly', editor=TabularEditor(adapter=SimpleNetworkAdapter()), show_label=False, ), Item('network_refresh_button', show_label=False, width=0.50), show_border=True, label="Network"), ))) def _network_callback(self, m, **metadata): txstr = sizeof_fmt(m.tx_bytes), rxstr = sizeof_fmt(m.rx_bytes) if m.interface_name.startswith( b'ppp0'): # Hack for ppp tx and rx which doesn't work txstr = "---" rxstr = "---" elif m.interface_name.startswith(b'lo') or m.interface_name.startswith( b'sit0'): return table_row = ((m.interface_name.decode('ascii'), ip_bytes_to_string(m.ipv4_address), ((m.flags & (1 << 6)) != 0), txstr, rxstr)) exists = False for i, each in enumerate(self._network_info): if each[0][0] == table_row[0][0]: self._network_info[i] = table_row exists = True if not exists: self._network_info.append(table_row) def __init__(self, link): """ Traits tab with UI for UDP broadcast of SBP. Parameters ---------- link : sbp.client.handler.Handler Link for SBP transfer to/from Piksi. device_uid : str Piksi Device UUID (defaults to None) whitelist : [int] | None Piksi Device UUID (defaults to None) """ self.link = link # Whitelist used for UDP broadcast view self.cell_modem_view = CellModemView(link) self.msgs = OBS_MSGS # register a callback when the msg_enum trait changes self.on_trait_change(self.update_msgs, 'msg_enum') self.python_console_cmds = {'update': self} self.cellmodem_interface_name = "ppp0" self.link.add_callback(self._network_callback, SBP_MSG_NETWORK_STATE_RESP) def update_msgs(self): """Updates the instance variable msgs which store the msgs that we will send over UDP. """ if self.msg_enum == 'Observations': self.msgs = OBS_MSGS elif self.msg_enum == 'All': self.msgs = [None] else: raise NotImplementedError def _prompt_setting_error(self, text): """Nonblocking prompt for a device setting error. Parameters ---------- text : str Helpful error message for the user """ prompt = CallbackPrompt(title="Setting Error", actions=[close_button]) prompt.text = text prompt.run(block=False) def update_network_state(self): self._network_refresh_button_fired() def _network_refresh_button_fired(self): self._network_info = [] self.link(MsgNetworkStateReq()) def _start_fired(self): """Handle start udp broadcast button. Registers callbacks on self.link for each of the self.msgs If self.msgs is None, it registers one generic callback for all messages. """ self.running = True try: self.func = UdpLogger(self.ip_ad, self.port) self.link.add_callback(self.func, self.msgs) except: # noqa import traceback print(traceback.format_exc()) def _stop_fired(self): """Handle the stop udp broadcast button. It uses the self.funcs and self.msgs to remove the callbacks that were registered when the start button was pressed. """ try: self.link.remove_callback(self.func, self.msgs) self.func.__exit__() self.func = None self.running = False except: # noqa import traceback print(traceback.format_exc())
class ScatterPlot(Template): #-- Template Traits -------------------------------------------------------- # The plot index data source: index = TDataSource # The plot value data source: value = TDataSource # The title of the plot: title = TStr('Scatter Plot') # The type of marker to use. This is a mapped trait using strings as the # keys: marker = marker_trait(template='copy', event='update') # The pixel size of the marker (doesn't include the thickness of the # outline): marker_size = TRange(1, 5, 1, event='update') # The thickness, in pixels, of the outline to draw around the marker. If # this is 0, no outline will be drawn. line_width = TRange(0.0, 5.0, 1.0) # The fill color of the marker: color = TColor('red', event='update') # The color of the outline to draw around the marker outline_color = TColor('black', event='update') #-- Derived Traits --------------------------------------------------------- plot = TDerived # Instance( ScatterPlot ) #-- Traits UI Views -------------------------------------------------------- # The scatter plot view: template_view = View(VGroup( Item('title', show_label=False, style='readonly', editor=ThemedTextEditor(theme=Theme('@GBB', alignment='center'))), Item('plot', show_label=False, resizable=True, editor=EnableEditor(), item_theme=Theme('@GF5', margins=0))), resizable=True) # The scatter plot options view: options_view = View( VGroup( VGroup(Label('Scatter Plot Options', item_theme=Theme('@GBB', alignment='center')), show_labels=False), VGroup(Item('title', editor=TextEditor()), Item('marker'), Item('marker_size', editor=ThemedSliderEditor()), Item('line_width', label='Line Width', editor=ThemedSliderEditor()), Item('color', label='Fill Color'), Item('outline_color', label='Outline Color'), group_theme=Theme('@GF5', margins=(-5, -1)), item_theme=Theme('@G0B', margins=0)))) #-- Default Values --------------------------------------------------------- def _index_default(self): """ Returns the default value for the 'index' trait. """ return TemplateDataSource( items=[ValueDataNameItem(name='index', flatten=True)], description='Scatter Plot Index') def _value_default(self): """ Returns the default value for the 'value' trait. """ return TemplateDataSource( items=[ValueDataNameItem(name='value', flatten=True)], description='Scatter Plot Value') #-- ITemplate Interface Implementation ------------------------------------- def activate_template(self): """ Converts all contained 'TDerived' objects to real objects using the template traits of the object. This method must be overridden in subclasses. Returns ------- None """ # If our data sources are still unbound, then just exit; someone must # have marked them as optional: if ((self.index.context_data is Undefined) or (self.value.context_data is Undefined)): return # Create a plot data object and give it this data: pd = ArrayPlotData() pd.set_data('index', self.index.context_data) pd.set_data('value', self.value.context_data) # Create the plot: self.plot = plot = Plot(pd) plot.plot(('index', 'value'), type='scatter', index_sort='ascending', marker=self.marker, color=self.color, outline_color=self.outline_color, marker_size=self.marker_size, line_width=self.line_width, bgcolor='white') plot.set(padding_left=50, padding_right=0, padding_top=0, padding_bottom=20) # Attach some tools to the plot: plot.tools.append(PanTool(plot, constrain_key='shift')) zoom = SimpleZoom(component=plot, tool_mode='box', always_on=False) plot.overlays.append(zoom) #-- Trait Event Handlers --------------------------------------------------- def _update_changed(self): """ Handles a plot option being changed. """ self.plot = Undefined
def create_editor(self): """ Returns the default traits UI editor to use for a trait. """ from traitsui.api import TextEditor return TextEditor()
class TVTKClassChooser(HasTraits): # The selected object, is None if no valid class_name was made. object = Property # The TVTK class name to choose. class_name = Str('', desc='class name of TVTK class (case sensitive)') # The string to search for in the class docs -- the search supports # 'and' and 'or' keywords. search = Str('', desc='string to search in TVTK class documentation '\ 'supports the "and" and "or" keywords. '\ 'press <Enter> to start search. '\ 'This is case insensitive.') clear_search = Button # The class documentation. doc = Str(_search_help_doc) # Completions for the choice of class. completions = List(Str) # List of available class names as strings. available = List(TVTK_CLASSES) ######################################## # Private traits. finder = Instance(DocSearch) n_completion = Int(25) ######################################## # View related traits. view = View(Group( Item(name='class_name', editor=EnumEditor(name='available')), Item(name='class_name', has_focus=True), Item(name='search', editor=TextEditor(enter_set=True, auto_set=False)), Item(name='clear_search', show_label=False), Item('_'), Item(name='completions', editor=ListEditor(columns=3), style='readonly'), Item(name='doc', resizable=True, label='Documentation', style='custom')), id='tvtk_doc', resizable=True, width=800, height=600, title='TVTK class chooser', buttons=["OK", "Cancel"]) ###################################################################### # `object` interface. ###################################################################### def __init__(self, **traits): super(TVTKClassChooser, self).__init__(**traits) self._orig_available = list(self.available) ###################################################################### # Non-public interface. ###################################################################### def _get_object(self): o = None if len(self.class_name) > 0: try: o = getattr(tvtk, self.class_name)() except (AttributeError, TypeError): pass return o def _class_name_changed(self, value): av = self.available comp = [x for x in av if x.startswith(value)] self.completions = comp[:self.n_completion] if len(comp) == 1 and value != comp[0]: self.class_name = comp[0] o = self.object if o is not None: self.doc = get_tvtk_class_doc(o) else: self.doc = _search_help_doc def _finder_default(self): return DocSearch() def _clear_search_fired(self): self.search = '' def _search_changed(self, value): if len(value) < 3: self.available = self._orig_available return f = self.finder result = f.search(value) if len(result) == 0: self.available = self._orig_available elif len(result) == 1: self.class_name = result[0] else: self.available = result self.completions = result[:self.n_completion]