class Employee(HasTraits): # Define the traits: name = Str dept = Str email = Str # Define the view: view = View(VGroup( VGroup( Item('name', show_label=False, editor=ImageEditor( image=ImageResource('info', search_path=search_path)))), VGroup( Item('name'), Item('dept'), Item('email'), Item('picture', editor=ImageEditor(scale=True, preserve_aspect_ratio=True, allow_upscaling=True), springy=True), )), resizable=True)
def test_image_editor_resource(self): obj1 = ImageDisplay(image=ImageResource(filename1)) view = View(Item('image', editor=ImageEditor())) # This should not fail. with create_ui(obj1, dict(view=view)) as ui: obj1.image = ImageResource(filename2)
def default_traits_view(self): table_editor = TableEditor(columns=[ ObjectColumn(name="name", label="name", resize_mode="stretch"), ObjectColumn(name="tag", label="File Type", resize_mode="fixed") ], auto_size=False, selected='object.selected_files', selection_mode='rows', editable=False) file_editor = FileEditor(allow_dir=True, filter=['*.tif']) image_editor = ImageEditor(scale=True, allow_upscaling=False, preserve_aspect_ratio=True) traits_view = View(VGroup( Group(UItem('image', editor=image_editor)), Group(Item('file_search', editor=file_editor, style='custom'), Item('add_file_button', label='Add File'), show_labels=False), HGroup( Item('key', editor=TextEditor(), style='simple'), Item('filter_file_button', label='Filter'), ), Group(Item('file_table', editor=table_editor), Item('remove_file_button', label='Remove File'), show_labels=False)), style='custom', resizable=True) return traits_view
def test_image_editor_none(self): obj1 = ImageDisplay(image=None) view = View(Item('image', editor=ImageEditor())) # This should not fail. with create_ui(obj1, dict(view=view)) as ui: pass
class ImageItem(HasPrivateTraits): # The name of the item being displayed: name = Str # The image being displayed: image = Image #-- Traits UI View Definitions --------------------------------------------- view = View(Item('image', show_label=False, editor=ImageEditor()))
class ImageInfo(MFileDialogModel): """ Defines a file dialog extension that display an image file's dimensions and content. """ # The ImageResource object for the current file: image = Property(depends_on='file_name') # The width of the current image: width = Property(depends_on='image') # The height of the current image: height = Property(depends_on='image') #-- Traits View Definitions ------------------------------------------------ view = View( VGroup( VGroup(Item('width', style='readonly'), Item('height', style='readonly'), label='Image Dimensions', show_border=True), VGroup(Item('image', show_label=False, editor=ImageEditor()), label='Image', show_border=True, springy=True))) #-- Property Implementations ----------------------------------------------- @cached_property def _get_image(self): path, name = split(self.file_name) if splitext(name)[1] in ('.png', '.gif', '.jpg', '.jpeg'): image = ImageResource(name, search_path=[path]) else: image = ImageResource('unknown') self._cur_image = image.create_image() return image @cached_property def _get_width(self): try: return str(toolkit().image_size(self._cur_image)[0]) + ' pixels' except: return '---' @cached_property def _get_height(self): try: return str(toolkit().image_size(self._cur_image)[1]) + ' pixels' except: return '---'
class ImageViewerPane(TraitsTaskPane): model = Instance(ImageViewer, ()) view = View( Item('image', editor=ImageEditor( scale=False, preserve_aspect_ratio=True, ), show_label=False, visible_when='image_file != ""'), scrollable=True, resizable=True, )
def default_traits_view(self): traits_view = View( Group( UItem( 'image', editor=ImageEditor( scale=True, allow_upscaling=False, preserve_aspect_ratio=True) ) ) ) return traits_view
class ImageViewer(HasTraits): path = File('saturn.jpg') image = Property(Instance(ImageResource), depends_on=['path']) @cached_property def _get_image(self): return ImageResource(self.path) view = View( Item('image', editor=ImageEditor(scale=False, preserve_aspect_ratio=True, allow_upscaling=True), springy=True, show_label=False, visible_when='image_file != ""'), scrollable=True, resizable=True, )
def test_image_editor_pillow(self): try: import PIL.Image from pyface.api import PILImage except ImportError: self.skipTest("Pillow is not available") if is_qt: try: # is ImageQt available as well from PIL.ImageQt import ImageQt except ImportError: self.skipTest("ImageQt is not available") pil_image_1 = PIL.Image.open(filename1) pil_image_2 = PIL.Image.open(filename2) obj1 = ImageDisplay(image=PILImage(image=pil_image_1)) view = View(Item('image', editor=ImageEditor())) # This should not fail. with create_ui(obj1, dict(view=view)) as ui: obj1.image = PILImage(image=pil_image_2)
def test_image_editor_array(self): try: import numpy as np from pyface.api import ArrayImage except ImportError: self.skipTest("NumPy is not available") gradient1 = np.empty(shape=(256, 256, 3), dtype='uint8') gradient1[:, :, 0] = np.arange(256).reshape(256, 1) gradient1[:, :, 1] = np.arange(256).reshape(1, 256) gradient1[:, :, 2] = np.arange(255, -1, -1).reshape(1, 256) gradient2 = np.empty(shape=(256, 256, 3), dtype='uint8') gradient2[:, :, 0] = np.arange(255, -1, -1).reshape(256, 1) gradient2[:, :, 1] = np.arange(256).reshape(1, 256) gradient2[:, :, 2] = np.arange(255, -1, -1).reshape(1, 256) obj1 = ImageDisplay(image=ArrayImage(data=gradient1)) view = View(Item('image', editor=ImageEditor())) # This should not fail. with create_ui(obj1, dict(view=view)) as ui: obj1.image = ArrayImage(data=gradient2)
class FileExistsHandler(Handler): """ Controller for the 'file already exists' popup. """ # The current status message: message = Str # The OK and Cancel buttons: ok = Button('OK') cancel = Button('Cancel') #-- Traits View Definitions ------------------------------------------------ view = View(VGroup( HGroup(Item('handler.message', editor=ImageEditor(image='@icons:dialog-warning')), Item('handler.message', style='readonly'), show_labels=False), HGroup(spring, Item('handler.ok'), Item('handler.cancel'), show_labels=False)), kind='popup') #-- Handler Event Handlers ------------------------------------------------- def handler_ok_changed(self, info): """ Handles the user clicking the OK button. """ parent = info.ui.parent info.ui.dispose(True) parent.dispose(True) def handler_cancel_changed(self, info): """ Handles the user clicking the Cancel button. """ info.ui.dispose(False)
class Employee ( HasTraits ): # Define the traits: name = Str dept = Str email = Str # Define the view: view = View( VGroup( VGroup( Item( 'name', show_label = False, editor = ImageEditor( image = ImageResource( 'info', search_path = search_path) ) ) ), VGroup( Item( 'name' ), Item( 'dept' ), Item( 'email' ) ) ) )
class SwiftConsole(HasTraits): """Traits-defined Swift Console. link : object Serial driver update : bool Update the firmware log_level_filter : str Syslog string, one of "ERROR", "WARNING", "INFO", "DEBUG". skip_settings : bool Don't read the device settings. Set to False when the console is reading from a network connection only. """ link = Instance(sbpc.Handler) console_output = Instance(OutputList()) python_console_env = Dict device_serial = Str('') dev_id = Str('') tracking_view = Instance(TrackingView) solution_view = Instance(SolutionView) baseline_view = Instance(BaselineView) observation_view = Instance(ObservationView) networking_view = Instance(SbpRelayView) observation_view_base = Instance(ObservationView) system_monitor_view = Instance(SystemMonitorView) settings_view = Instance(SettingsView) update_view = Instance(UpdateView) log_level_filter = Enum(list(SYSLOG_LEVELS.itervalues())) """" mode : baseline and solution view - SPP, Fixed or Float num_sat : baseline and solution view - number of satellites port : which port is Piksi connected to directory_name : location of logged files json_logging : enable JSON logging csv_logging : enable CSV logging is_valid_directory : check to see if chosen directory is valid """ mode = Str('') num_signals = Int(0) port = Str('') latency = Int() directory_name = Directory json_logging = Bool(True) csv_logging = Bool(False) cnx_icon = Str('') heartbeat_count = Int() last_timer_heartbeat = Int() solid_connection = Bool(False) timer = Any() is_valid_directory = Bool (True) csv_logging_button = SVGButton( toggle=True, label='CSV log', tooltip='start CSV logging', toggle_tooltip='stop CSV logging', filename=os.path.join(determine_path(), 'images', 'iconic', 'pause.svg'), toggle_filename=os.path.join(determine_path(), 'images', 'iconic', 'play.svg'), orientation = 'vertical', width=2, height=2, ) json_logging_button = SVGButton( toggle=True, label='JSON log', tooltip='start JSON logging', toggle_tooltip='stop JSON logging', filename=os.path.join(determine_path(), 'images', 'iconic', 'pause.svg'), toggle_filename=os.path.join(determine_path(), 'images', 'iconic', 'play.svg'), orientation = 'vertical', width=2, height=2, ) paused_button = SVGButton( label='', tooltip='Pause console update', toggle_tooltip='Resume console update', toggle=True, filename=os.path.join(determine_path(), 'images', 'iconic', 'pause.svg'), toggle_filename=os.path.join(determine_path(), 'images', 'iconic', 'play.svg'), width=8, height=8 ) clear_button = SVGButton( label='', tooltip='Clear console buffer', filename=os.path.join(determine_path(), 'images', 'iconic', 'x.svg'), width=8, height=8 ) view = View( VSplit( Tabbed( Item('tracking_view', style='custom', label='Tracking'), Item('solution_view', style='custom', label='Solution'), Item('baseline_view', style='custom', label='Baseline'), VSplit( Item('observation_view', style='custom', show_label=False), Item('observation_view_base', style='custom', show_label=False), label='Observations', ), Item('settings_view', style='custom', label='Settings'), Item('update_view', style='custom', label='Firmware Update'), Tabbed( Item('system_monitor_view', style='custom', label='System Monitor'), Item('networking_view', label='Networking', style='custom', show_label=False), Item('python_console_env', style='custom', label='Python Console', editor=ShellEditor()), label='Advanced', show_labels=False ), show_labels=False ), VGroup( VGroup( HGroup( Spring(width=4, springy=False), Item('paused_button', show_label=False, padding=0, width=8, height=8), Item('clear_button', show_label=False, width=8, height=8), Item('', label='Console Log', emphasized=True), Item('csv_logging_button', emphasized=True, show_label=False, width=12, height=-30, padding=0), Item('json_logging_button', emphasized=True, show_label=False, width=12, height=-30, padding=0), Item('directory_name', show_label=False, springy=True, tooltip='Choose location for file logs. Default is home/SwiftNav.', height=-25, enabled_when='not(json_logging or csv_logging)'), UItem('log_level_filter', style='simple', padding=0, height=8, show_label=True, tooltip='Show log levels up to and including the selected level of severity.\nThe CONSOLE log level is always visible.'), ), Item( 'console_output', style='custom', editor=InstanceEditor(), height=125, show_label=False, full_size=True ), ), HGroup( Spring(width=4, springy=False), Item('', label='PORT:', emphasized=True, tooltip='Serial Port that Piksi is connected to'), Item('port', show_label=False, style = 'readonly'), Item('', label='FIX TYPE:', emphasized = True, tooltip='Piksi Mode: SPS, Float RTK, Fixed RTK'), Item('mode', show_label = False, style = 'readonly'), Item('', label='#Signals:', emphasized=True, tooltip='Number of signals acquired by Piksi'), Item('num_signals', padding=2, show_label=False, style = 'readonly'), Item('', label='Base Latency:', emphasized=True, tooltip='Corrections latency (-1 means no corrections)'), Item('latency', padding=2, show_label=False, style = 'readonly'), Spring(springy=True), Item('cnx_icon', show_label = False, padding=0, width=8, height=8, visible_when='solid_connection', springy=False, editor=ImageEditor(allow_clipping=False, image = ImageResource( 'arrows_blue.png', search_path=[os.path.join(determine_path(), 'images', 'iconic')]))), Item('cnx_icon', show_label = False, padding=0, width=8, height=8, visible_when='not solid_connection', springy=False, editor=ImageEditor(allow_clipping=False, image = ImageResource( 'arrows_grey.png', search_path=[os.path.join(determine_path(), 'images', 'iconic')]))), Spring(width=4, height=-2, springy=False), ), Spring(height=1, springy=False), ), ), icon=icon, resizable=True, width=800, height=600, handler=ConsoleHandler(), title=CONSOLE_TITLE ) def print_message_callback(self, sbp_msg, **metadata): try: encoded = sbp_msg.payload.encode('ascii', 'ignore') for eachline in reversed(encoded.split('\n')): self.console_output.write_level(eachline, str_to_log_level(eachline.split(':')[0])) except UnicodeDecodeError: print "Critical Error encoding the serial stream as ascii." def log_message_callback(self, sbp_msg, **metadata): try: encoded = sbp_msg.text.encode('ascii', 'ignore') for eachline in reversed(encoded.split('\n')): self.console_output.write_level(eachline, sbp_msg.level) except UnicodeDecodeError: print "Critical Error encoding the serial stream as ascii." def ext_event_callback(self, sbp_msg, **metadata): e = MsgExtEvent(sbp_msg) print 'External event: %s edge on pin %d at wn=%d, tow=%d, time qual=%s' % ( "Rising" if (e.flags & (1<<0)) else "Falling", e.pin, e.wn, e.tow, "good" if (e.flags & (1<<1)) else "unknown") def _paused_button_fired(self): self.console_output.paused = not self.console_output.paused def _log_level_filter_changed(self): """ Takes log level enum and translates into the mapped integer. Integer stores the current filter value inside OutputList. """ self.console_output.log_level_filter = str_to_log_level(self.log_level_filter) def _clear_button_fired(self): self.console_output.clear() def _directory_name_changed(self): if os.path.isdir(self.directory_name): self.is_valid_directory = True if self.baseline_view and self.solution_view: self.baseline_view.directory_name_b = self.directory_name self.solution_view.directory_name_p = self.directory_name self.solution_view.directory_name_v = self.directory_name if self.observation_view and self.observation_view_base: self.observation_view.dirname = self.directory_name self.observation_view_base.dirname = self.directory_name else: print "Please enter a valid directory!" self.is_valid_directory = False def check_heartbeat(self): # if our heartbeat hasn't changed since the last timer interval the connection must have dropped if self.heartbeat_count == self.last_timer_heartbeat: self.solid_connection = False else: self.solid_connection = True self.last_timer_heartbeat = self.heartbeat_count def update_on_heartbeat(self, sbp_msg, **metadata): self.heartbeat_count += 1 # First initialize the state to nothing, if we can't update, it will be none temp_mode = "None" temp_num_signals = 0 view = None # If we have a recent baseline update, we use the baseline info if time.time() - self.baseline_view.last_btime_update < 10: view = self.baseline_view # Otherwise, if we have a recent SPP update, we use the SPP elif time.time() - self.solution_view.last_stime_update < 10: view = self.solution_view if view: if view.last_soln: # if all is well we update state temp_mode = view.mode_string(view.last_soln) temp_num_signals = view.last_soln.n_sats self.mode = temp_mode self.num_signals = temp_num_signals if self.settings_view: # for auto populating surveyed fields self.settings_view.lat = self.solution_view.latitude self.settings_view.lon = self.solution_view.longitude self.settings_view.alt = self.solution_view.altitude if self.system_monitor_view: self.latency = self.system_monitor_view.msg_obs_window_latency_ms def _csv_logging_button_fired(self): if self.is_valid_directory: if self.csv_logging and self.baseline_view.logging_b and self.solution_view.logging_p and self.solution_view.logging_v: print "Stopped CSV logging" self.csv_logging = False self.baseline_view.logging_b = False self.solution_view.logging_p = False self.solution_view.logging_v = False else: print "Started CSV logging at %s" % self.directory_name self.csv_logging = True self.baseline_view.logging_b = True self.solution_view.logging_p = True self.solution_view.logging_v = True else: print "Directory not valid" def _start_json_logging(self, override_filename=None): if override_filename: filename = override_filename else: filename = s.logfilename() filename = os.path.normpath(os.path.join(self.directory_name, filename)) self.logger = s.get_logger(True, filename) self.forwarder = sbpc.Forwarder(self.link, self.logger) self.forwarder.start() def _stop_json_logging(self): fwd = self.forwarder fwd.stop() self.logger.flush() self.logger.close() def _json_logging_button_fired(self): if self.is_valid_directory: if self.first_json_press and self.json_logging: print "JSON Logging initiated via CMD line. Please press button again to stop logging" elif self.json_logging: self._stop_json_logging() self.json_logging = False print "Stopped JSON logging" else: self._start_json_logging() self.json_logging = True self.first_json_press = False else: print "Directory not valid" def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): self.console_output.close() def __init__(self, link, update, log_level_filter, skip_settings=False, error=False, port=None, json_logging=False, log_dirname=None): self.error = error self.port = port self.dev_id = str(os.path.split(port)[1]) self.num_signals = 0 self.mode = '' self.forwarder = None self.latency = -1 # if we have passed a logfile, we set our directory to it override_filename = None swift_path = None home = expanduser("~") swift_path = os.path.normpath(os.path.join(home, 'SwiftNav')) try: os.makedirs(swift_path) except OSError: if not os.path.isdir(swift_path): raise if log_dirname: self.directory_name = log_dirname else: self.directory_name = swift_path # Start swallowing sys.stdout and sys.stderr self.console_output = OutputList(tfile=True, outdir=self.directory_name) sys.stdout = self.console_output self.console_output.write("Console: starting...") if not error: sys.stderr = self.console_output self.log_level_filter = log_level_filter self.console_output.log_level_filter = str_to_log_level(log_level_filter) try: self.link = link self.link.add_callback(self.print_message_callback, SBP_MSG_PRINT_DEP) self.link.add_callback(self.log_message_callback, SBP_MSG_LOG) self.link.add_callback(self.ext_event_callback, SBP_MSG_EXT_EVENT) self.link.add_callback(self.update_on_heartbeat, SBP_MSG_HEARTBEAT) self.dep_handler = DeprecatedMessageHandler(link) settings_read_finished_functions = [] self.tracking_view = TrackingView(self.link) self.solution_view = SolutionView(self.link, dirname=self.directory_name) self.baseline_view = BaselineView(self.link, dirname=self.directory_name) self.observation_view = ObservationView(self.link, name='Local', relay=False, dirname=self.directory_name) self.observation_view_base = ObservationView(self.link, name='Remote', relay=True, dirname=self.directory_name) self.system_monitor_view = SystemMonitorView(self.link) self.update_view = UpdateView(self.link, prompt=update) settings_read_finished_functions.append(self.update_view.compare_versions) self.networking_view = SbpRelayView(self.link) self.json_logging = json_logging self.csv_logging = False self.first_json_press = True if json_logging: self._start_json_logging(override_filename) self.json_logging = True # we set timer interval to 1200 milliseconds because we expect a heartbeat each second self.timer = Timer(1200, self.check_heartbeat) # Once we have received the settings, update device_serial with # the Piksi serial number which will be displayed in the window # title. This callback will also update the header route as used # by the networking view. def update_serial(): serial_string = self.settings_view.settings['system_info']['serial_number'].value self.device_serial = 'PK%04d' % int(serial_string) if serial_string: self.networking_view.set_route(int(serial_string)) settings_read_finished_functions.append(update_serial) self.settings_view = SettingsView(self.link, settings_read_finished_functions, skip=skip_settings) self.update_view.settings = self.settings_view.settings self.python_console_env = { 'send_message': self.link, 'link': self.link, } self.python_console_env.update(self.tracking_view.python_console_cmds) self.python_console_env.update(self.solution_view.python_console_cmds) self.python_console_env.update(self.baseline_view.python_console_cmds) self.python_console_env.update(self.observation_view.python_console_cmds) self.python_console_env.update(self.networking_view.python_console_cmds) self.python_console_env.update(self.system_monitor_view.python_console_cmds) self.python_console_env.update(self.update_view.python_console_cmds) self.python_console_env.update(self.settings_view.python_console_cmds) except: import traceback traceback.print_exc() if self.error: sys.exit(1)
class OptionsPane(TraitsDockPane): id = 'pyfibre.options_pane' name = 'Options Pane' #: Remove the possibility to close the pane closable = False #: Remove the possibility to detach the pane from the GUI floatable = False #: Remove the possibility to move the pane in the GUI movable = False #: Make the pane visible by default visible = True # Overwrite options ow_metric = Bool(False) ow_segment = Bool(False) ow_network = Bool(False) save_figures = Bool(False) # Image analysis parameters sigma = Float(0.5) low_intensity = Int(1) high_intensity = Int(99) n_denoise = Int(5) m_denoise = Int(35) alpha = Float(0.5) image_editor = ImageEditor(scale=True, allow_upscaling=False, preserve_aspect_ratio=True) int_range_editor = RangeEditor(low=1, high=100, mode='slider') pix_range_editor = RangeEditor(low=2, high=50, mode='slider') traits_view = View( VGroup( Item('ow_network', label="Overwrite Network?"), Item('ow_segment', label="Overwrite Segments?"), Item('ow_metric', label="Overwrite Metrics?"), Item('save_figures', label="Save Figures?"), Item('sigma', label="Gaussian Std Dev (pix)"), Item('alpha', label="Alpha network coefficient"), Group( Item('low_intensity', editor=int_range_editor, style='custom', label="Low Clip Intensity (%)"), Item('high_intensity', editor=int_range_editor, style='custom', label="High Clip Intensity (%)")), Group( Item('n_denoise', editor=pix_range_editor, style='custom', label="NL-Mean Neighbourhood 1 (pix)"), Item('m_denoise', editor=pix_range_editor, style='custom', label="NL-Mean Neighbourhood 2 (pix)"))))
class NewAccountView(ModelView): """ Account creation dialog example. """ #: Text explaining the dialog. explanation = Property(HTML, depends_on=['_password_suggestions', '+view_error']) #: The user's password entered a second time. password = Password #: The user's password strength. password_strength = Range(0, 4) #: Alert icon for username error. password_strength_icon = Property(Image, depends_on='password_strength') #: Alert icon for username error. username_icon = Image('@std:alert16') #: Alert icon for second password error. password_match_icon = Image('@std:alert16') # private traits --------------------------------------------------------- #: The suggestions for a stronger password. _password_suggestions = Unicode #: Whether there is anything entered for the username. _username_error = Bool(False, view_error=True) #: Whether the password is strong enough. _password_strength_error = Bool(False, view_error=True) #: Whether the two entered passwords match. _password_match_error = Bool(False, view_error=True) # ------------------------------------------------------------------------ # Handler interface # ------------------------------------------------------------------------ def init(self, info): """ Initialize the error state of the object. """ obj = info.object model = info.model # check for initial error states obj._check_username(model.username) obj._check_password_strength(model.password) obj._check_password_match(model.password) super(NewAccountView, self).init(info) def close(self, info, is_ok): """ Handles the user attempting to close the dialog. If it is via the OK dialog button, try to create an account before closing. If this fails, display an error message and veto the close by returning false. """ if is_ok: success, message = info.model.create_account() if not success: dlg = MessageDialog(message="Cannot create account", informative=message, severity='error') dlg.open() return False return True # UI change handlers ----------------------------------------------------- def model_username_changed(self, ui_info): """ Set error condition if the model's username is empty. """ if ui_info.initialized: ui_info.object._username_error = (ui_info.model.username == '') def model_password_changed(self, ui_info): """ Check the quality of the password that the user entered. """ if ui_info.initialized: obj = ui_info.object password = ui_info.model.password obj._check_password_strength(password) obj._check_password_match(password) def object_password_changed(self, ui_info): """ Check if the re-enteredpassword matches the original. """ if ui_info.initialized: obj = ui_info.object password = ui_info.model.password obj._check_password_match(password) # ------------------------------------------------------------------------ # private interface # ------------------------------------------------------------------------ def _check_username(self, username): """ Check whether the passwords match. """ self._username_error = (username == '') def _check_password_strength(self, password): """ Check the strength of the password This sets the password strength, suggestions for making a better password and an error state if the password is not strong enough. """ if password: password_check = test_strength(password) self.password_strength = password_check['score'] feedback = password_check.get('feedback', {}) if feedback.get('warnings'): warnings = '<em>{}</em> '.format(feedback['warnings']) else: warnings = '' suggestions = feedback.get('suggestions', []) self._password_suggestions = warnings + ' '.join(suggestions) else: self.password_strength = 0 self._password_suggestions = 'The password cannot be empty.' self._password_strength_error = (self.password_strength < 3) def _check_password_match(self, password): """ Check whether the passwords match. """ self._password_match_error = (not password or password != self.password) # Trait change handlers -------------------------------------------------- @on_trait_change("+view_error") def _view_error_updated(self, new_error): """ One of the error traits changed: update the error count. """ if self.info and self.info.ui: if new_error: self.info.ui.errors += 1 else: self.info.ui.errors -= 1 # Traits property handlers ----------------------------------------------- @cached_property def _get_password_strength_icon(self): """ Get the icon for password strength. """ return strength_map[self.password_strength] @cached_property def _get_explanation(self): """ Get the explanatory HTML. """ text = '' if self._username_error: text += 'The username cannot be empty. ' if self._password_match_error: text += 'The passwords must match. ' if self._password_suggestions: text += self._password_suggestions if not text: text = ("The username is valid, the password is strong and both " + "password fields match.") return explanation_template.format(css=css, text=text) # TraitsUI view ---------------------------------------------------------- view = View( VGroup( Item('explanation', show_label=False), VGrid( Item('model.username', tooltip='The username to use when logging in.', editor=TextEditor(invalid='_username_error')), Item( 'username_icon', editor=ImageEditor(), show_label=False, visible_when='_username_error', tooltip='User name must not be empty.', ), Item('model.password', tooltip='The password to use when logging in.', editor=TextEditor( invalid='_password_strength_error', password=True, )), Item( 'password_strength_icon', editor=ImageEditor(), show_label=False, ), Item('password', label='Re-enter Password:'******'Enter the password a second time.', editor=TextEditor( invalid='_password_match_error', password=True, )), Item( 'password_match_icon', editor=ImageEditor(), show_label=False, visible_when='_password_match_error', tooltip='Passwords must match.', ), columns=2, show_border=True, ), ), title='Create User Account', buttons=OKCancelButtons, width=480, height=280, )
class SwiftConsole(HasTraits): """Traits-defined Swift Console. link : object Serial driver update : bool Update the firmware log_level_filter : str Syslog string, one of "ERROR", "WARNING", "INFO", "DEBUG". """ link = Instance(sbpc.Handler) console_output = Instance(OutputList()) python_console_env = Dict device_serial = Str('') dev_id = Str('') tracking_view = Instance(TrackingView) solution_view = Instance(SolutionView) baseline_view = Instance(BaselineView) skyplot_view = Instance(SkyplotView) observation_view = Instance(ObservationView) networking_view = Instance(SbpRelayView) observation_view_base = Instance(ObservationView) system_monitor_view = Instance(SystemMonitorView) settings_view = Instance(SettingsView) update_view = Instance(UpdateView) imu_view = Instance(IMUView) mag_view = Instance(MagView) spectrum_analyzer_view = Instance(SpectrumAnalyzerView) log_level_filter = Enum(list(SYSLOG_LEVELS.values())) """" mode : baseline and solution view - SPP, Fixed or Float num_sat : baseline and solution view - number of satellites port : which port is Swift Device is connected to directory_name : location of logged files json_logging : enable JSON logging csv_logging : enable CSV logging """ mode = Str('') ins_status_string = Str('') num_sats_str = Str('') cnx_desc = Str('') age_of_corrections = Str('') uuid = Str('') directory_name = Directory json_logging = Bool(True) csv_logging = Bool(False) cnx_icon = Str('') heartbeat_count = Int() last_timer_heartbeat = Int() driver_data_rate = Str() solid_connection = Bool(False) csv_logging_button = SVGButton( toggle=True, label='CSV log', tooltip='start CSV logging', toggle_tooltip='stop CSV logging', filename=resource_filename('console/images/iconic/pause.svg'), toggle_filename=resource_filename('console/images/iconic/play.svg'), orientation='vertical', width=2, height=2, ) json_logging_button = SVGButton( toggle=True, label='JSON log', tooltip='start JSON logging', toggle_tooltip='stop JSON logging', filename=resource_filename('console/images/iconic/pause.svg'), toggle_filename=resource_filename('console/images/iconic/play.svg'), orientation='vertical', width=2, height=2, ) paused_button = SVGButton( label='', tooltip='Pause console update', toggle_tooltip='Resume console update', toggle=True, filename=resource_filename('console/images/iconic/pause.svg'), toggle_filename=resource_filename('console/images/iconic/play.svg'), width=8, height=8) clear_button = SVGButton( label='', tooltip='Clear console buffer', filename=resource_filename('console/images/iconic/x.svg'), width=8, height=8) view = View( VSplit( Tabbed( Tabbed( Item('tracking_view', style='custom', label='Signals', show_label=False), Item('skyplot_view', style='custom', label='Sky Plot', show_label=False), label="Tracking"), Item('solution_view', style='custom', label='Solution'), Item('baseline_view', style='custom', label='Baseline'), VSplit( Item('observation_view', style='custom', show_label=False), Item( 'observation_view_base', style='custom', show_label=False), label='Observations', ), Item('settings_view', style='custom', label='Settings'), Item('update_view', style='custom', label='Update'), Tabbed( Item( 'system_monitor_view', style='custom', label='System Monitor'), Item('imu_view', style='custom', label='IMU'), Item('mag_view', style='custom', label='Magnetometer'), Item( 'networking_view', label='Networking', style='custom', show_label=False), Item( 'spectrum_analyzer_view', label='Spectrum Analyzer', style='custom'), label='Advanced', show_labels=False), show_labels=False), VGroup( VGroup( HGroup( Spring(width=4, springy=False), Item( 'paused_button', show_label=False, padding=0, width=8, height=8), Item( 'clear_button', show_label=False, width=8, height=8), Item('', label='Console Log', emphasized=True), Item( 'csv_logging_button', emphasized=True, show_label=False, width=12, height=-30, padding=0), Item( 'json_logging_button', emphasized=True, show_label=False, width=12, height=-30, padding=0), Item( 'directory_name', show_label=False, springy=True, tooltip='Choose location for file logs. Default is home/SwiftNav.', height=-25, enabled_when='not(json_logging or csv_logging)', editor_args={'auto_set': True}), UItem( 'log_level_filter', style='simple', padding=0, height=8, show_label=True, tooltip='Show log levels up to and including the selected level of severity.\nThe CONSOLE log level is always visible.' ), ), Item( 'console_output', style='custom', editor=InstanceEditor(), height=125, show_label=False, full_size=True), ), HGroup( Spring(width=4, springy=False), Item( '', label='Interface:', emphasized=True, tooltip='Interface for communicating with Swift device' ), Item('cnx_desc', show_label=False, style='readonly'), Item( '', label='FIX TYPE:', emphasized=True, tooltip='Device Mode: SPS, Float RTK, Fixed RTK'), Item('mode', show_label=False, style='readonly'), Item( '', label='#Sats:', emphasized=True, tooltip='Number of satellites used in solution'), Item( 'num_sats_str', padding=2, show_label=False, style='readonly'), Item( '', label='Corr Age:', emphasized=True, tooltip='Age of corrections (-- means invalid / not present)' ), Item( 'age_of_corrections', padding=2, show_label=False, style='readonly'), Item( '', label='INS Status:', emphasized=True, tooltip='INS Status String' ), Item( 'ins_status_string', padding=2, show_label=False, style='readonly', width=6), Spring(springy=True), Item('driver_data_rate', style='readonly', show_label=False), Item( 'cnx_icon', show_label=False, padding=0, width=8, height=8, visible_when='solid_connection', springy=False, editor=ImageEditor( allow_clipping=False, image=ImageResource(resource_filename('console/images/iconic/arrows_blue.png')) )), Item( 'cnx_icon', show_label=False, padding=0, width=8, height=8, visible_when='not solid_connection', springy=False, editor=ImageEditor( allow_clipping=False, image=ImageResource( resource_filename('console/images/iconic/arrows_grey.png') ))), Spring(width=4, height=-2, springy=False), ), Spring(height=1, springy=False), ), ), icon=icon, resizable=True, width=800, height=600, handler=ConsoleHandler(), title=CONSOLE_TITLE) def print_message_callback(self, sbp_msg, **metadata): try: encoded = sbp_msg.payload.encode('ascii', 'ignore') for eachline in reversed(encoded.split('\n')): self.console_output.write_level( eachline, str_to_log_level(eachline.split(':')[0])) except UnicodeDecodeError as e: print("Error encoding msg_print: {}".format(e)) def log_message_callback(self, sbp_msg, **metadata): encoded = sbp_msg.text.decode('utf8') for eachline in reversed(encoded.split('\n')): self.console_output.write_level(eachline, sbp_msg.level) def ext_event_callback(self, sbp_msg, **metadata): e = MsgExtEvent(sbp_msg) print( 'External event: %s edge on pin %d at wn=%d, tow=%d, time qual=%s' % ("Rising" if (e.flags & (1 << 0)) else "Falling", e.pin, e.wn, e.tow, "good" if (e.flags & (1 << 1)) else "unknown")) def cmd_resp_callback(self, sbp_msg, **metadata): r = MsgCommandResp(sbp_msg) print( "Received a command response message with code {0}".format(r.code)) def _paused_button_fired(self): self.console_output.paused = not self.console_output.paused def _log_level_filter_changed(self): """ Takes log level enum and translates into the mapped integer. Integer stores the current filter value inside OutputList. """ self.console_output.log_level_filter = str_to_log_level( self.log_level_filter) def _clear_button_fired(self): self.console_output.clear() def _directory_name_changed(self): if self.baseline_view and self.solution_view: self.baseline_view.directory_name_b = self.directory_name self.solution_view.directory_name_p = self.directory_name self.solution_view.directory_name_v = self.directory_name if self.observation_view and self.observation_view_base: self.observation_view.dirname = self.directory_name self.observation_view_base.dirname = self.directory_name def check_heartbeat(self): # if our heartbeat hasn't changed since the last timer interval the connection must have dropped if self.heartbeat_count == self.last_timer_heartbeat: self.solid_connection = False self.ins_status_string = "None" self.mode = "None" self.num_sats_str = EMPTY_STR else: self.solid_connection = True self.last_timer_heartbeat = self.heartbeat_count total_bytes = self.driver.total_bytes_read self.driver_data_rate = "{0:.2f} KB/s".format((total_bytes - self.last_driver_bytes_read) / (1.2 * 1024)) self.last_driver_bytes_read = total_bytes def update_on_heartbeat(self, sbp_msg, **metadata): self.heartbeat_count += 1 # --- determining which mode, llh or baseline, to show in the status bar --- llh_display_mode = "None" llh_num_sats = 0 llh_is_differential = False baseline_display_mode = "None" baseline_num_sats = 0 baseline_is_differential = False # determine the latest llh solution mode if self.solution_view: llh_solution_mode = self.solution_view.last_pos_mode llh_display_mode = mode_dict.get(llh_solution_mode, EMPTY_STR) if llh_solution_mode > 0 and self.solution_view.last_soln: llh_num_sats = self.solution_view.last_soln.n_sats llh_is_differential = (llh_solution_mode in DIFFERENTIAL_MODES) if getattr(self.solution_view, 'ins_used', False) and llh_solution_mode != DR_MODE: llh_display_mode += "+INS" # determine the latest baseline solution mode if self.baseline_view and self.settings_view and self.settings_view.dgnss_enabled(): baseline_solution_mode = self.baseline_view.last_mode baseline_display_mode = mode_dict.get(baseline_solution_mode, EMPTY_STR) if baseline_solution_mode > 0 and self.baseline_view.last_soln: baseline_num_sats = self.baseline_view.last_soln.n_sats baseline_is_differential = (baseline_solution_mode in DIFFERENTIAL_MODES) # determine the latest INS mode if self.solution_view and (monotonic() - self.solution_view.last_ins_status_receipt_time) < 1: ins_flags = self.solution_view.ins_status_flags ins_mode = ins_flags & 0x7 ins_type = (ins_flags >> 29) & 0x7 odo_status = (ins_flags >> 8) & 0x3 ins_error = (ins_flags >> 4) & 0xF if ins_error != 0: ins_status_string = ins_error_dict.get(ins_error, "Unk Error") else: ins_status_string = ins_type_dict.get(ins_type, "unk") + "-" ins_status_string += ins_mode_dict.get(ins_mode, "unk") if odo_status == 1: ins_status_string += "+Odo" self.ins_status_string = ins_status_string # select the solution mode displayed in the status bar: # * baseline if it's a differential solution but llh isn't # * otherwise llh (also if there is no solution, in which both are "None") if baseline_is_differential and not(llh_is_differential): self.mode = baseline_display_mode self.num_sats_str = "{}".format(baseline_num_sats) else: self.mode = llh_display_mode self.num_sats_str = "{}".format(llh_num_sats) # --- end of status bar mode determination section --- if self.settings_view: # for auto populating surveyed fields self.settings_view.lat = self.solution_view.latitude self.settings_view.lon = self.solution_view.longitude self.settings_view.alt = self.solution_view.altitude if self.baseline_view: if self.baseline_view.age_corrections is not None: self.age_of_corrections = "{0} s".format( self.baseline_view.age_corrections) else: self.age_of_corrections = EMPTY_STR def _csv_logging_button_action(self): if self.csv_logging and self.baseline_view.logging_b and self.solution_view.logging_p and self.solution_view.logging_v: print("Stopped CSV logging") self.csv_logging = False self.baseline_view.logging_b = False self.solution_view.logging_p = False self.solution_view.logging_v = False else: print("Started CSV logging at %s" % self.directory_name) self.csv_logging = True self.baseline_view.logging_b = True self.solution_view.logging_p = True self.solution_view.logging_v = True def _start_json_logging(self, override_filename=None): if override_filename: filename = override_filename else: filename = time.strftime("swift-gnss-%Y%m%d-%H%M%S.sbp.json") filename = os.path.normpath( os.path.join(self.directory_name, filename)) self.logger = s.get_logger(True, filename, self.expand_json) self.forwarder = sbpc.Forwarder(self.link, self.logger) self.forwarder.start() if self.settings_view: self.settings_view._settings_read_all() def _stop_json_logging(self): fwd = self.forwarder fwd.stop() self.logger.flush() self.logger.close() def _json_logging_button_action(self): if self.first_json_press and self.json_logging: print( "JSON Logging initiated via CMD line. Please press button again to stop logging" ) elif self.json_logging: self._stop_json_logging() self.json_logging = False print("Stopped JSON logging") else: self._start_json_logging() self.json_logging = True self.first_json_press = False def _json_logging_button_fired(self): if not os.path.exists(self.directory_name) and not self.json_logging: confirm_prompt = CallbackPrompt( title="Logging directory creation", actions=[ok_button], callback=self._json_logging_button_action) confirm_prompt.text = "\nThe selected logging directory does not exist and will be created." confirm_prompt.run(block=False) else: self._json_logging_button_action() def _csv_logging_button_fired(self): if not os.path.exists(self.directory_name) and not self.csv_logging: confirm_prompt = CallbackPrompt( title="Logging directory creation", actions=[ok_button], callback=self._csv_logging_button_action) confirm_prompt.text = "\nThe selected logging directory does not exist and will be created." confirm_prompt.run(block=False) else: self._csv_logging_button_action() def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): self.console_output.close() def __init__(self, link, driver, update, log_level_filter, error=False, cnx_desc=None, json_logging=False, log_dirname=None, override_filename=None, log_console=False, connection_info=None, expand_json=False ): self.error = error self.cnx_desc = cnx_desc self.connection_info = connection_info self.dev_id = cnx_desc self.num_sats_str = EMPTY_STR self.mode = '' self.ins_status_string = "None" self.forwarder = None self.age_of_corrections = '--' self.expand_json = expand_json # if we have passed a logfile, we set our directory to it override_filename = override_filename self.last_status_update_time = 0 self.last_driver_bytes_read = 0 self.driver = driver if log_dirname: self.directory_name = log_dirname if override_filename: override_filename = os.path.join(log_dirname, override_filename) else: self.directory_name = swift_path # Start swallowing sys.stdout and sys.stderr self.console_output = OutputList( tfile=log_console, outdir=self.directory_name) sys.stdout = self.console_output self.console_output.write("Console: " + CONSOLE_VERSION + " starting...") if not error: sys.stderr = self.console_output self.log_level_filter = log_level_filter self.console_output.log_level_filter = str_to_log_level( log_level_filter) try: self.link = link self.link.add_callback(self.print_message_callback, SBP_MSG_PRINT_DEP) self.link.add_callback(self.log_message_callback, SBP_MSG_LOG) self.link.add_callback(self.ext_event_callback, SBP_MSG_EXT_EVENT) self.link.add_callback(self.cmd_resp_callback, SBP_MSG_COMMAND_RESP) self.link.add_callback(self.update_on_heartbeat, SBP_MSG_HEARTBEAT) self.dep_handler = DeprecatedMessageHandler(link) settings_read_finished_functions = [] self.tracking_view = TrackingView(self.link) self.solution_view = SolutionView( self.link, dirname=self.directory_name) self.baseline_view = BaselineView( self.link, dirname=self.directory_name) self.skyplot_view = SkyplotView(self.link, self.tracking_view) self.observation_view = ObservationView( self.link, name='Local', relay=False, dirname=self.directory_name, tracking_view=self.tracking_view) self.observation_view_base = ObservationView( self.link, name='Remote', relay=True, dirname=self.directory_name) self.system_monitor_view = SystemMonitorView(self.link) self.update_view = UpdateView( self.link, download_dir=swift_path, prompt=update, connection_info=self.connection_info) self.imu_view = IMUView(self.link) self.mag_view = MagView(self.link) self.spectrum_analyzer_view = SpectrumAnalyzerView(self.link) settings_read_finished_functions.append( self.update_view.compare_versions) self.networking_view = SbpRelayView(self.link) self.json_logging = json_logging self.csv_logging = False self.first_json_press = True if json_logging: self._start_json_logging(override_filename) self.json_logging = True # we set timer interval to 1200 milliseconds because we expect a heartbeat each second self.timer_cancel = call_repeatedly(1.2, self.check_heartbeat) # Once we have received the settings, update device_serial with # the Swift serial number which will be displayed in the window # title. This callback will also update the header route as used # by the networking view. def update_serial(): mfg_id = None try: self.uuid = self.settings_view.settings['system_info'][ 'uuid'].value mfg_id = self.settings_view.settings['system_info'][ 'serial_number'].value except KeyError: pass if mfg_id: self.device_serial = 'PK' + str(mfg_id) skip_settings_read = False if 'mode' in self.connection_info: if self.connection_info['mode'] == 'file': skip_settings_read = True settings_read_finished_functions.append(update_serial) self.settings_view = SettingsView( self.link, settings_read_finished_functions, skip_read=skip_settings_read) self.update_view.settings = self.settings_view.settings self.python_console_env = { 'send_message': self.link, 'link': self.link, } self.python_console_env.update( self.tracking_view.python_console_cmds) self.python_console_env.update( self.solution_view.python_console_cmds) self.python_console_env.update( self.baseline_view.python_console_cmds) self.python_console_env.update( self.skyplot_view.python_console_cmds) self.python_console_env.update( self.observation_view.python_console_cmds) self.python_console_env.update( self.networking_view.python_console_cmds) self.python_console_env.update( self.system_monitor_view.python_console_cmds) self.python_console_env.update( self.update_view.python_console_cmds) self.python_console_env.update(self.imu_view.python_console_cmds) self.python_console_env.update(self.mag_view.python_console_cmds) self.python_console_env.update( self.settings_view.python_console_cmds) self.python_console_env.update( self.spectrum_analyzer_view.python_console_cmds) except: # noqa import traceback traceback.print_exc() if self.error: os._exit(1)
class Visualization(HasTraits): logo = [] # start_pause_update = Button() check_cargo_thread = Instance(CheckCargoThread) # active_update = False update_scene_thread = Instance(UpdateSceneThread) # update_display_thread = Instance(UpdateDisplayThread) scene = Instance(MlabSceneModel, ()) display = Instance(TextDisplay, ()) log = Instance(LogDisplay, ()) plots = [] idx = [-1, 0] # idx = [curr_idx, next_idx] def __init__(self, display=None): # Do not forget to call the parent's __init__ HasTraits.__init__(self) if display: self.display = display self.check_cargo_thread = CheckCargoThread(self.idx) # self.check_cargo_thread.idx = self.idx self.check_cargo_thread.wants_abort = False self.check_cargo_thread.start() self.update_scene_thread = UpdateSceneThread(self.idx) self.update_scene_thread.wants_abort = False self.update_scene_thread.scene = self.scene self.update_scene_thread.plots = self.plots self.update_scene_thread.display = self.display self.update_scene_thread.log = self.log self.update_scene_thread.start() # self.active_update = True def do_start_pause_update(self): if self.check_cargo_thread and not self.check_cargo_thread.isAlive(): return if self.update_scene_thread and self.update_scene_thread.isAlive(): self.plots = self.update_scene_thread.plots self.update_scene_thread.wants_abort = True self.log.update('Active update is off!\n') else: self.update_scene_thread = UpdateSceneThread(self.idx) self.update_scene_thread.wants_abort = False self.update_scene_thread.scene = self.scene self.update_scene_thread.plots = self.plots self.update_scene_thread.display = self.display self.update_scene_thread.log = self.log self.update_scene_thread.start() self.log.update('Active update is on!\n') def do_stop_all_threading(self): if self.check_cargo_thread: self.check_cargo_thread.wants_abort = True if self.update_scene_thread: self.update_scene_thread.wants_abort = True self.log.update('All threading stopped!\n') def do_prev_cargo(self): if self.check_cargo_thread and not self.check_cargo_thread.isAlive(): return if self.update_scene_thread.isAlive(): self.log.update('Still in Active! Please pause first!\n') return else: if self.idx[0] == 0: self.log.update('Have reached the first cargo!\n') return else: self.idx[0] -= 1 # self.update_scene() self.log.update('Change to Cargo ' + str(self.idx[0]+1) + " (" + str( self.idx[1]) + "). \nClick 'Refresh' to start plot\n") # self.update_scene_thread.updateOne() return def do_next_cargo(self): if self.check_cargo_thread and not self.check_cargo_thread.isAlive(): return if self.update_scene_thread.isAlive(): self.log.update('Still in Active! Please pause first!\n') return else: if self.idx[0] == self.idx[1]-1: self.log.update('Have reached the last cargo!\n') return else: self.idx[0] += 1 # self.update_scene() self.log.update('Change to Cargo ' + str(self.idx[0]+1) + " (" + str( self.idx[1]) + "). \nClick 'Refresh' to start plot\n") # self.update_scene_thread.updateOne() return def do_refresh_scene(self): if self.check_cargo_thread and not self.check_cargo_thread.isAlive(): return if self.update_scene_thread.isAlive(): self.log.update('Still in Active! Please pause first!\n') return self.update_scene_thread.updateOne() return def do_prev_cargo_show(self): if self.check_cargo_thread and not self.check_cargo_thread.isAlive(): return if self.update_scene_thread.isAlive(): self.log.update('Still in Active! Please pause first!\n') return else: if self.idx[0] == 0: self.log.update('Have reached the first cargo!\n') return else: self.idx[0] -= 1 # self.update_scene() self.do_refresh_scene() return def do_next_cargo_show(self): if self.check_cargo_thread and not self.check_cargo_thread.isAlive(): return if self.update_scene_thread.isAlive(): self.log.update('Still in Active! Please pause first!\n') return else: if self.idx[0] == self.idx[1]-1: self.log.update('Have reached the last cargo!\n') return else: self.idx[0] += 1 # self.update_scene() self.do_refresh_scene() return def do_restart(self): self.do_stop_all_threading() time.sleep(1) self.idx = [-1, 0] self.plots = [] self.check_cargo_thread = CheckCargoThread(self.idx) self.check_cargo_thread.wants_abort = False self.check_cargo_thread.start() self.update_scene_thread = UpdateSceneThread(self.idx) self.update_scene_thread.wants_abort = False self.update_scene_thread.scene = self.scene self.update_scene_thread.plots = self.plots self.update_scene_thread.display = self.display self.update_scene_thread.log = self.log self.update_scene_thread.start() self.log.update('Threading restarted!\n') def do_close(self): self.do_stop_all_threading() start_pause_update = Action(name="Start/Pause", action="do_start_pause_update") stop_all_threading = Action(name="Terminate", action="do_stop_all_threading") prev_cargo = Action(name="Prev Cargo", action="do_prev_cargo") next_cargo = Action(name="Next Cargo", action="do_next_cargo") refresh_scene = Action(name="Refresh", action="do_refresh_scene") prev_cargo_show = Action(name="Show Prev", action="do_prev_cargo_show") next_cargo_show = Action(name="Show Next", action="do_next_cargo_show") close_button = Action(name="Close", action="do_close") restart = Action(name='Restart', action='do_restart') view = View( Group( HGroup( Item('logo', editor=ImageEditor(scale=True, image=ImageResource('panasonic-logo-small', search_path=['./res'])), show_label=False), Item('logo', editor=ImageEditor(scale=True, image=ImageResource('umsjtu-logo', search_path=['./res'])), show_label=False), # orientation='horizontal' ), HGroup( Item('scene', editor=SceneEditor(scene_class=MayaviScene), height=500, width=500, show_label=False), Group( Item('log', style='custom', height=60, show_label=False), Item('display', style='custom', height=60, show_label=False), ), # orientation='horizontal' # Item('start_pause_update', show_label=False), # Item('last_cargo', show_label=False), # Item('next_cargo', show_label=False), # Item('text', show_label=False, springy=True, height=100, style='custom'), ), orientation='vertical' ), buttons=[refresh_scene, prev_cargo, next_cargo, prev_cargo_show, next_cargo_show, start_pause_update, restart, stop_all_threading], ) def __del__(self): # print "END" if self.check_cargo_thread: self.check_cargo_thread.wants_abort = True if self.update_scene_thread: self.update_scene_thread.wants_abort = True
class ImageView(ModelView): """A model view of an image with actions. """ #: The image model being viewed. model = Instance(ImageModel, (), allow_none=False) #: The image to display. image = Image() def rotate_left(self): """Rotate the image anticlockwise.""" self.model.rotate("anticlockwise") def rotate_right(self): """Rotate the image clockwise.""" self.model.rotate("clockwise") def flip_horizontal(self): """Flip the image horizontally.""" self.model.flip("horizontal") def flip_vertical(self): """Flip the image vertically.""" self.model.flip("vertical") def reload(self): """Reload the image from disk.""" self.model.load_image() @observe('model.data') def _update_image(self, event): self.image = ArrayImage(data=self.model.data) def _image_default(self): return ArrayImage(data=self.model.data) view = View( HSplit( Item( 'model.image_path', editor=FileEditor( dialog_style='open', filter=["*.png", "*.jpg", "*.jpeg"] ), style='custom', ), Item( 'image', editor=ImageEditor( scale=True, preserve_aspect_ratio=True, allow_upscaling=True, ), springy=True, resizable=True, ), show_labels=False, # NOTE: this id means the position of the sash will be saved id='viewer_split' ), resizable=True, toolbar=ToolBar( ActionGroup( Action( name="Rotate Left", tooltip="Rotate Left", action='rotate_left', image='rotate_left', ), Action( name="Rotate Right", tooltip="Rotate Right", action='rotate_right', image='rotate_right', ), Action( name="Flip Horizontally", tooltip="Flip Horizontally", action='flip_horizontal', image='flip_horizontal', ), Action( name="Flip Vertically", tooltip="Flip Vertically", action='flip_vertical', image='flip_vertical', ), name="Transpose Group", id="transpose_group", ), ActionGroup( Action( name="Denoise", tooltip="Denoise", action='denoise', image='denoise', ), name="Filter Group", id="filter_group", ), image_size=(24, 24), show_tool_names=False, ), menubar=MenuBar( Menu( Action(name="Revert Image", action="revert"), name="File", id="file_menu", ), Menu( ActionGroup( Action(name="Rotate Left", action='rotate_left'), Action(name="Rotate Right", action='rotate_right'), Action(name="Flip Horizontally", action='flip_horizontal'), Action(name="Flip Vertically", action='flip_vertical'), name="Transpose Group", id="transpose_group", ), ActionGroup( Action(name="Denoise", action='denoise'), name="Filter Group", id="filter_group", ), name="Edit", id="edit_menu", ), ), # NOTE: this id means the size of the window will be saved id='image_preview', )
def get_view(self): return View(UItem('name', editor=ImageEditor(image=self.object)))
class SwiftConsole(HasTraits): """Traits-defined Swift Console. link : object Serial driver update : bool Update the firmware log_level_filter : str Syslog string, one of "ERROR", "WARNING", "INFO", "DEBUG". skip_settings : bool Don't read the device settings. Set to False when the console is reading from a network connection only. """ link = Instance(sbpc.Handler) console_output = Instance(OutputList()) python_console_env = Dict device_serial = Str('') dev_id = Str('') tracking_view = Instance(TrackingView) solution_view = Instance(SolutionView) baseline_view = Instance(BaselineView) observation_view = Instance(ObservationView) networking_view = Instance(SbpRelayView) observation_view_base = Instance(ObservationView) system_monitor_view = Instance(SystemMonitorView) settings_view = Instance(SettingsView) update_view = Instance(UpdateView) imu_view = Instance(IMUView) spectrum_analyzer_view = Instance(SpectrumAnalyzerView) log_level_filter = Enum(list(SYSLOG_LEVELS.itervalues())) """" mode : baseline and solution view - SPP, Fixed or Float num_sat : baseline and solution view - number of satellites port : which port is Swift Device is connected to directory_name : location of logged files json_logging : enable JSON logging csv_logging : enable CSV logging """ mode = Str('') num_sats = Int(0) cnx_desc = Str('') latency = Str('') directory_name = Directory json_logging = Bool(True) csv_logging = Bool(False) cnx_icon = Str('') heartbeat_count = Int() last_timer_heartbeat = Int() solid_connection = Bool(False) csv_logging_button = SVGButton( toggle=True, label='CSV log', tooltip='start CSV logging', toggle_tooltip='stop CSV logging', filename=os.path.join(determine_path(), 'images', 'iconic', 'pause.svg'), toggle_filename=os.path.join(determine_path(), 'images', 'iconic', 'play.svg'), orientation='vertical', width=2, height=2, ) json_logging_button = SVGButton( toggle=True, label='JSON log', tooltip='start JSON logging', toggle_tooltip='stop JSON logging', filename=os.path.join(determine_path(), 'images', 'iconic', 'pause.svg'), toggle_filename=os.path.join(determine_path(), 'images', 'iconic', 'play.svg'), orientation='vertical', width=2, height=2, ) paused_button = SVGButton(label='', tooltip='Pause console update', toggle_tooltip='Resume console update', toggle=True, filename=os.path.join(determine_path(), 'images', 'iconic', 'pause.svg'), toggle_filename=os.path.join( determine_path(), 'images', 'iconic', 'play.svg'), width=8, height=8) clear_button = SVGButton(label='', tooltip='Clear console buffer', filename=os.path.join(determine_path(), 'images', 'iconic', 'x.svg'), width=8, height=8) view = View(VSplit( Tabbed(Item('tracking_view', style='custom', label='Tracking'), Item('solution_view', style='custom', label='Solution'), Item('baseline_view', style='custom', label='Baseline'), VSplit( Item('observation_view', style='custom', show_label=False), Item('observation_view_base', style='custom', show_label=False), label='Observations', ), Item('settings_view', style='custom', label='Settings'), Item('update_view', style='custom', label='Firmware Update'), Tabbed(Item('system_monitor_view', style='custom', label='System Monitor'), Item('imu_view', style='custom', label='IMU'), Item('networking_view', label='Networking', style='custom', show_label=False), Item('spectrum_analyzer_view', label='Spectrum Analyzer', style='custom'), Item('python_console_env', style='custom', label='Python Console', editor=ShellEditor()), label='Advanced', show_labels=False), show_labels=False), VGroup( VGroup( HGroup( Spring(width=4, springy=False), Item('paused_button', show_label=False, padding=0, width=8, height=8), Item('clear_button', show_label=False, width=8, height=8), Item('', label='Console Log', emphasized=True), Item('csv_logging_button', emphasized=True, show_label=False, width=12, height=-30, padding=0), Item('json_logging_button', emphasized=True, show_label=False, width=12, height=-30, padding=0), Item( 'directory_name', show_label=False, springy=True, tooltip= 'Choose location for file logs. Default is home/SwiftNav.', height=-25, enabled_when='not(json_logging or csv_logging)', editor_args={'auto_set': True}), UItem( 'log_level_filter', style='simple', padding=0, height=8, show_label=True, tooltip= 'Show log levels up to and including the selected level of severity.\nThe CONSOLE log level is always visible.' ), ), Item('console_output', style='custom', editor=InstanceEditor(), height=125, show_label=False, full_size=True), ), HGroup( Spring(width=4, springy=False), Item('', label='Interface:', emphasized=True, tooltip='Interface for communicating with Swift device'), Item('cnx_desc', show_label=False, style='readonly'), Item('', label='FIX TYPE:', emphasized=True, tooltip='Device Mode: SPS, Float RTK, Fixed RTK'), Item('mode', show_label=False, style='readonly'), Item('', label='#Sats:', emphasized=True, tooltip='Number of satellites used in solution'), Item('num_sats', padding=2, show_label=False, style='readonly'), Item('', label='Base Latency:', emphasized=True, tooltip='Corrections latency (-1 means no corrections)'), Item('latency', padding=2, show_label=False, style='readonly'), Spring(springy=True), Item('cnx_icon', show_label=False, padding=0, width=8, height=8, visible_when='solid_connection', springy=False, editor=ImageEditor(allow_clipping=False, image=ImageResource( 'arrows_blue.png', search_path=[ os.path.join( determine_path(), 'images', 'iconic') ]))), Item('cnx_icon', show_label=False, padding=0, width=8, height=8, visible_when='not solid_connection', springy=False, editor=ImageEditor(allow_clipping=False, image=ImageResource( 'arrows_grey.png', search_path=[ os.path.join( determine_path(), 'images', 'iconic') ]))), Spring(width=4, height=-2, springy=False), ), Spring(height=1, springy=False), ), ), icon=icon, resizable=True, width=800, height=600, handler=ConsoleHandler(), title=CONSOLE_TITLE) def print_message_callback(self, sbp_msg, **metadata): try: encoded = sbp_msg.payload.encode('ascii', 'ignore') for eachline in reversed(encoded.split('\n')): self.console_output.write_level( eachline, str_to_log_level(eachline.split(':')[0])) except UnicodeDecodeError: print("Critical Error encoding the serial stream as ascii.") def log_message_callback(self, sbp_msg, **metadata): try: encoded = sbp_msg.text.encode('ascii', 'ignore') for eachline in reversed(encoded.split('\n')): self.console_output.write_level(eachline, sbp_msg.level) except UnicodeDecodeError: print("Critical Error encoding the serial stream as ascii.") def ext_event_callback(self, sbp_msg, **metadata): e = MsgExtEvent(sbp_msg) print( 'External event: %s edge on pin %d at wn=%d, tow=%d, time qual=%s' % ("Rising" if (e.flags & (1 << 0)) else "Falling", e.pin, e.wn, e.tow, "good" if (e.flags & (1 << 1)) else "unknown")) def cmd_resp_callback(self, sbp_msg, **metadata): r = MsgCommandResp(sbp_msg) print("Received a command response message with code {0}".format( r.code)) def _paused_button_fired(self): self.console_output.paused = not self.console_output.paused def _log_level_filter_changed(self): """ Takes log level enum and translates into the mapped integer. Integer stores the current filter value inside OutputList. """ self.console_output.log_level_filter = str_to_log_level( self.log_level_filter) def _clear_button_fired(self): self.console_output.clear() def _directory_name_changed(self): if self.baseline_view and self.solution_view: self.baseline_view.directory_name_b = self.directory_name self.solution_view.directory_name_p = self.directory_name self.solution_view.directory_name_v = self.directory_name if self.observation_view and self.observation_view_base: self.observation_view.dirname = self.directory_name self.observation_view_base.dirname = self.directory_name def check_heartbeat(self): # if our heartbeat hasn't changed since the last timer interval the connection must have dropped if self.heartbeat_count == self.last_timer_heartbeat: self.solid_connection = False else: self.solid_connection = True self.last_timer_heartbeat = self.heartbeat_count def update_on_heartbeat(self, sbp_msg, **metadata): self.heartbeat_count += 1 # First initialize the state to nothing, if we can't update, it will be none temp_mode = "None" temp_num_sats = 0 view = None if self.baseline_view and self.solution_view: # If we have a recent baseline update, we use the baseline info if time.time() - self.baseline_view.last_btime_update < 10: view = self.baseline_view # Otherwise, if we have a recent SPP update, we use the SPP elif time.time() - self.solution_view.last_stime_update < 10: view = self.solution_view if view: if view.last_soln: # if all is well we update state temp_mode = mode_dict.get(get_mode(view.last_soln), EMPTY_STR) temp_num_sats = view.last_soln.n_sats self.mode = temp_mode self.num_sats = temp_num_sats if self.settings_view: # for auto populating surveyed fields self.settings_view.lat = self.solution_view.latitude self.settings_view.lon = self.solution_view.longitude self.settings_view.alt = self.solution_view.altitude if self.system_monitor_view: if self.system_monitor_view.msg_obs_window_latency_ms != -1: self.latency = "{0} ms".format( self.system_monitor_view.msg_obs_window_latency_ms) else: self.latency = EMPTY_STR def _csv_logging_button_action(self): if self.csv_logging and self.baseline_view.logging_b and self.solution_view.logging_p and self.solution_view.logging_v: print("Stopped CSV logging") self.csv_logging = False self.baseline_view.logging_b = False self.solution_view.logging_p = False self.solution_view.logging_v = False else: print("Started CSV logging at %s" % self.directory_name) self.csv_logging = True self.baseline_view.logging_b = True self.solution_view.logging_p = True self.solution_view.logging_v = True def _start_json_logging(self, override_filename=None): if override_filename: filename = override_filename else: filename = time.strftime("swift-gnss-%Y%m%d-%H%M%S.sbp.json") filename = os.path.normpath( os.path.join(self.directory_name, filename)) self.logger = s.get_logger(True, filename) self.forwarder = sbpc.Forwarder(self.link, self.logger) self.forwarder.start() if self.settings_view: self.settings_view._settings_read_button_fired() def _stop_json_logging(self): fwd = self.forwarder fwd.stop() self.logger.flush() self.logger.close() def _json_logging_button_action(self): if self.first_json_press and self.json_logging: print( "JSON Logging initiated via CMD line. Please press button again to stop logging" ) elif self.json_logging: self._stop_json_logging() self.json_logging = False print("Stopped JSON logging") else: self._start_json_logging() self.json_logging = True self.first_json_press = False def _json_logging_button_fired(self): if not os.path.exists(self.directory_name) and not self.json_logging: confirm_prompt = CallbackPrompt( title="Logging directory creation", actions=[ok_button], callback=self._json_logging_button_action) confirm_prompt.text = "\nThe selected logging directory does not exist and will be created." confirm_prompt.run(block=False) else: self._json_logging_button_action() def _csv_logging_button_fired(self): if not os.path.exists(self.directory_name) and not self.csv_logging: confirm_prompt = CallbackPrompt( title="Logging directory creation", actions=[ok_button], callback=self._csv_logging_button_action) confirm_prompt.text = "\nThe selected logging directory does not exist and will be created." confirm_prompt.run(block=False) else: self._csv_logging_button_action() def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): self.console_output.close() def __init__(self, link, update, log_level_filter, skip_settings=False, error=False, cnx_desc=None, json_logging=False, log_dirname=None, override_filename=None, log_console=False, networking=None, serial_upgrade=False): self.error = error self.cnx_desc = cnx_desc self.dev_id = cnx_desc self.num_sats = 0 self.mode = '' self.forwarder = None self.latency = '--' # if we have passed a logfile, we set our directory to it override_filename = override_filename home = expanduser("~") swift_path = os.path.normpath(os.path.join(home, 'SwiftNav')) if log_dirname: self.directory_name = log_dirname if override_filename: override_filename = os.path.join(log_dirname, override_filename) else: self.directory_name = swift_path # Start swallowing sys.stdout and sys.stderr self.console_output = OutputList(tfile=log_console, outdir=self.directory_name) sys.stdout = self.console_output self.console_output.write("Console: " + CONSOLE_VERSION + " starting...") if not error: sys.stderr = self.console_output self.log_level_filter = log_level_filter self.console_output.log_level_filter = str_to_log_level( log_level_filter) try: self.link = link self.link.add_callback(self.print_message_callback, SBP_MSG_PRINT_DEP) self.link.add_callback(self.log_message_callback, SBP_MSG_LOG) self.link.add_callback(self.ext_event_callback, SBP_MSG_EXT_EVENT) self.link.add_callback(self.cmd_resp_callback, SBP_MSG_COMMAND_RESP) self.link.add_callback(self.update_on_heartbeat, SBP_MSG_HEARTBEAT) self.dep_handler = DeprecatedMessageHandler(link) settings_read_finished_functions = [] self.tracking_view = TrackingView(self.link) self.solution_view = SolutionView(self.link, dirname=self.directory_name) self.baseline_view = BaselineView(self.link, dirname=self.directory_name) self.observation_view = ObservationView( self.link, name='Local', relay=False, dirname=self.directory_name) self.observation_view_base = ObservationView( self.link, name='Remote', relay=True, dirname=self.directory_name) self.system_monitor_view = SystemMonitorView(self.link) self.update_view = UpdateView(self.link, download_dir=swift_path, prompt=update, serial_upgrade=serial_upgrade) self.imu_view = IMUView(self.link) self.spectrum_analyzer_view = SpectrumAnalyzerView(self.link) settings_read_finished_functions.append( self.update_view.compare_versions) if networking: import yaml try: networking_dict = yaml.load(networking) networking_dict.update({'show_networking': True}) except yaml.YAMLError: print( "Unable to interpret networking cmdline argument. It will be ignored." ) import traceback print(traceback.format_exc()) networking_dict = {'show_networking': True} else: networking_dict = {} networking_dict.update( {'whitelist': [SBP_MSG_POS_LLH, SBP_MSG_HEARTBEAT]}) self.networking_view = SbpRelayView(self.link, **networking_dict) self.json_logging = json_logging self.csv_logging = False self.first_json_press = True if json_logging: self._start_json_logging(override_filename) self.json_logging = True # we set timer interval to 1200 milliseconds because we expect a heartbeat each second self.timer_cancel = call_repeatedly(1.2, self.check_heartbeat) # Once we have received the settings, update device_serial with # the Swift serial number which will be displayed in the window # title. This callback will also update the header route as used # by the networking view. def update_serial(): uuid = None mfg_id = None try: uuid = self.settings_view.settings['system_info'][ 'uuid'].value mfg_id = self.settings_view.settings['system_info'][ 'serial_number'].value except KeyError: pass if mfg_id: self.device_serial = 'PK' + str(mfg_id)[-6:] self.networking_view.set_route(uuid=uuid, serial_id=mfg_id) if self.networking_view.connect_when_uuid_received: self.networking_view._connect_rover_fired() settings_read_finished_functions.append(update_serial) self.settings_view = SettingsView(self.link, settings_read_finished_functions, skip=skip_settings) self.update_view.settings = self.settings_view.settings self.python_console_env = { 'send_message': self.link, 'link': self.link, } self.python_console_env.update( self.tracking_view.python_console_cmds) self.python_console_env.update( self.solution_view.python_console_cmds) self.python_console_env.update( self.baseline_view.python_console_cmds) self.python_console_env.update( self.observation_view.python_console_cmds) self.python_console_env.update( self.networking_view.python_console_cmds) self.python_console_env.update( self.system_monitor_view.python_console_cmds) self.python_console_env.update( self.update_view.python_console_cmds) self.python_console_env.update(self.imu_view.python_console_cmds) self.python_console_env.update( self.settings_view.python_console_cmds) self.python_console_env.update( self.spectrum_analyzer_view.python_console_cmds) except: import traceback traceback.print_exc() if self.error: sys.exit(1)
class WorkflowInfo(HasTraits): # ------------------- # Required Attributes # ------------------- #: Filename for the current workflow (if any) workflow_filename = Str() #: A list of the loaded plugins plugins = List(Plugin) #: The factory currently selected in the SetupPane selected_factory_name = Str() #: An error message for the entire workflow error_message = Str() # --------------------- # Dependent Attributes # --------------------- #: The force project logo! Stored at images/Force_Logo.png image = ImageResource('Force_Logo.png') #: Message indicating currently loaded file workflow_filename_message = Str() #: A list of plugin names plugin_names = List(Str) # ----------- # View # ----------- traits_view = View( VGroup( horizontal_centre( Group(UItem('image', editor=ImageEditor(scale=True, allow_upscaling=False, preserve_aspect_ratio=True)), visible_when="selected_factory_name == 'Workflow'")), Group(UReadonly('plugin_names', editor=ListStrEditor(editable=False)), show_border=True, label='Available Plugins', visible_when="selected_factory_name not in ['KPI']"), Group( UReadonly('workflow_filename_message', editor=TextEditor()), show_border=True, label='Workflow Filename', ), Group(UReadonly('error_message', editor=TextEditor()), show_border=True, label='Workflow Errors', visible_when="selected_factory_name == 'Workflow'"), )) # ------------------- # Defaults # ------------------- def _plugin_names_default(self): return [plugin.name for plugin in self.plugins] def _workflow_filename_message_default(self): if self.workflow_filename == '': return 'No File Loaded' return 'Current File: ' + self.workflow_filename
class DataSourceWizardView(DataSourceWizard): #---------------------------------------------------------------------- # Private traits #---------------------------------------------------------------------- _top_label = Str('Describe your data') _info_text = Str('Array size do not match') _array_label = Str('Available arrays') _data_type_text = Str("What does your data represents?") _lines_text = Str("Connect the points with lines") _scalar_data_text = Str("Array giving the value of the scalars") _optional_scalar_data_text = Str("Associate scalars with the data points") _connectivity_text = Str("Array giving the triangles") _vector_data_text = Str("Associate vector components") _position_text = Property(depends_on="position_type_") _position_text_dict = { 'explicit': 'Coordinnates of the data points:', 'orthogonal grid': 'Position of the layers along each axis:', } def _get__position_text(self): return self._position_text_dict.get(self.position_type_, "") _shown_help_text = Str _data_sources_wrappers = Property(depends_on='data_sources') def _get__data_sources_wrappers(self): return [ ArrayColumnWrapper(name=name, shape=repr(self.data_sources[name].shape)) for name in self._data_sources_names ] # A traits pointing to the object, to play well with traitsUI _self = Instance(DataSourceWizard) _suitable_traits_view = Property(depends_on="data_type_") def _get__suitable_traits_view(self): return "_%s_data_view" % self.data_type_ ui = Any(False) _preview_button = Button(label='Preview structure') def __preview_button_fired(self): if self.ui: self.build_data_source() self.preview() _ok_button = Button(label='OK') def __ok_button_fired(self): if self.ui: self.ui.dispose() self.build_data_source() _cancel_button = Button(label='Cancel') def __cancel_button_fired(self): if self.ui: self.ui.dispose() _is_ok = Bool _is_not_ok = Bool def _anytrait_changed(self): """ Validates if the OK button is enabled. """ if self.ui: self._is_ok = self.check_arrays() self._is_not_ok = not self._is_ok _preview_window = Instance(PreviewWindow, ()) _info_image = Instance(ImageResource, ImageLibrary.image_resource('@std:alert16', )) #---------------------------------------------------------------------- # TraitsUI views #---------------------------------------------------------------------- _coordinates_group = \ HGroup( Item('position_x', label='x', editor=EnumEditor(name='_data_sources_names', invalid='_is_not_ok')), Item('position_y', label='y', editor=EnumEditor(name='_data_sources_names', invalid='_is_not_ok')), Item('position_z', label='z', editor=EnumEditor(name='_data_sources_names', invalid='_is_not_ok')), ) _position_group = \ Group( Item('position_type'), Group( Item('_position_text', style='readonly', resizable=False, show_label=False), _coordinates_group, visible_when='not position_type_=="image data"', ), Group( Item('grid_shape_source_', label='Grid shape', editor=EnumEditor( name='_grid_shape_source_labels', invalid='_is_not_ok')), HGroup( spring, Item('grid_shape', style='custom', editor=ArrayEditor(width=-60), show_label=False), enabled_when='grid_shape_source==""', ), visible_when='position_type_=="image data"', ), label='Position of the data points', show_border=True, show_labels=False, ), _connectivity_group = \ Group( HGroup( Item('_connectivity_text', style='readonly', resizable=False), spring, Item('connectivity_triangles', editor=EnumEditor(name='_data_sources_names'), show_label=False, ), show_labels=False, ), label='Connectivity information', show_border=True, show_labels=False, enabled_when='position_type_=="explicit"', ), _scalar_data_group = \ Group( Item('_scalar_data_text', style='readonly', resizable=False, show_label=False), HGroup( spring, Item('scalar_data', editor=EnumEditor(name='_data_sources_names', invalid='_is_not_ok')), show_labels=False, ), label='Scalar value', show_border=True, show_labels=False, ) _optional_scalar_data_group = \ Group( HGroup( 'has_scalar_data', Item('_optional_scalar_data_text', resizable=False, style='readonly'), show_labels=False, ), Item('_scalar_data_text', style='readonly', resizable=False, enabled_when='has_scalar_data', show_label=False), HGroup( spring, Item('scalar_data', editor=EnumEditor(name='_data_sources_names', invalid='_is_not_ok'), enabled_when='has_scalar_data'), show_labels=False, ), label='Scalar data', show_border=True, show_labels=False, ), _vector_data_group = \ VGroup( HGroup( Item('vector_u', label='u', editor=EnumEditor(name='_data_sources_names', invalid='_is_not_ok')), Item('vector_v', label='v', editor=EnumEditor(name='_data_sources_names', invalid='_is_not_ok')), Item('vector_w', label='w', editor=EnumEditor(name='_data_sources_names', invalid='_is_not_ok')), ), label='Vector data', show_border=True, ), _optional_vector_data_group = \ VGroup( HGroup( Item('has_vector_data', show_label=False), Item('_vector_data_text', style='readonly', resizable=False, show_label=False), ), HGroup( Item('vector_u', label='u', editor=EnumEditor(name='_data_sources_names', invalid='_is_not_ok')), Item('vector_v', label='v', editor=EnumEditor(name='_data_sources_names', invalid='_is_not_ok')), Item('vector_w', label='w', editor=EnumEditor(name='_data_sources_names', invalid='_is_not_ok')), enabled_when='has_vector_data', ), label='Vector data', show_border=True, ), _array_view = \ View( Item('_array_label', editor=TitleEditor(), show_label=False), Group( Item('_data_sources_wrappers', editor=TabularEditor( adapter = ArrayColumnAdapter(), ), ), show_border=True, show_labels=False )) _questions_view = View( Item('_top_label', editor=TitleEditor(), show_label=False), HGroup( Item('_data_type_text', style='readonly', resizable=False), spring, 'data_type', spring, show_border=True, show_labels=False, ), HGroup( Item( '_self', style='custom', editor=InstanceEditor(view_name='_suitable_traits_view'), ), Group( # FIXME: Giving up on context sensitive help # because of lack of time. #Group( # Item('_shown_help_text', editor=HTMLEditor(), # width=300, # label='Help', # ), # show_labels=False, # label='Help', #), #Group( Item('_preview_button', enabled_when='_is_ok'), Item('_preview_window', style='custom', label='Preview structure'), show_labels=False, #label='Preview structure', #), #layout='tabbed', #dock='tab', ), show_labels=False, show_border=True, ), ) _point_data_view = \ View(Group( Group(_coordinates_group, label='Position of the data points', show_border=True, ), HGroup( 'lines', Item('_lines_text', style='readonly', resizable=False), label='Lines', show_labels=False, show_border=True, ), _optional_scalar_data_group, _optional_vector_data_group, # XXX: hack to have more vertical space Label('\n'), Label('\n'), Label('\n'), )) _surface_data_view = \ View(Group( _position_group, _connectivity_group, _optional_scalar_data_group, _optional_vector_data_group, )) _vector_data_view = \ View(Group( _vector_data_group, _position_group, _optional_scalar_data_group, )) _volumetric_data_view = \ View(Group( _scalar_data_group, _position_group, _optional_vector_data_group, )) _wizard_view = View( Group( HGroup( Item( '_self', style='custom', show_label=False, editor=InstanceEditor(view='_array_view'), width=0.17, ), '_', Item( '_self', style='custom', show_label=False, editor=InstanceEditor(view='_questions_view'), ), ), HGroup( Item('_info_image', editor=ImageEditor(), visible_when="_is_not_ok"), Item('_info_text', style='readonly', resizable=False, visible_when="_is_not_ok"), spring, '_cancel_button', Item('_ok_button', enabled_when='_is_ok'), show_labels=False, ), ), title='Import arrays', resizable=True, ) #---------------------------------------------------------------------- # Public interface #---------------------------------------------------------------------- def __init__(self, **traits): DataSourceFactory.__init__(self, **traits) self._self = self def view_wizard(self): """ Pops up the view of the wizard, and keeps the reference it to be able to close it. """ # FIXME: Workaround for traits bug in enabled_when self.position_type_ self.data_type_ self._suitable_traits_view self.grid_shape_source self._is_ok self.ui = self.edit_traits(view='_wizard_view') def preview(self): """ Display a preview of the data structure in the preview window. """ self._preview_window.clear() self._preview_window.add_source(self.data_source) data = lambda name: self.data_sources[name] g = Glyph() g.glyph.glyph_source.glyph_source = \ g.glyph.glyph_source.glyph_list[0] g.glyph.scale_mode = 'data_scaling_off' if not (self.has_vector_data or self.data_type_ == 'vector'): g.glyph.glyph_source.glyph_source.glyph_type = 'cross' g.actor.property.representation = 'points' g.actor.property.point_size = 3. self._preview_window.add_module(g) if not self.data_type_ in ('point', 'vector') or self.lines: s = Surface() s.actor.property.opacity = 0.3 self._preview_window.add_module(s) if not self.data_type_ == 'point': self._preview_window.add_filter(ExtractEdges()) s = Surface() s.actor.property.opacity = 0.2 self._preview_window.add_module(s)