class BazNoModify(HasTraits): foo = Instance(Foo, ()) sd = Delegate('foo', prefix='s') t = Delegate('foo') def _s_changed(self, name, old, new): print 'BazNoModify._s_changed( %s, %s, %s, %s)' % (self, name, old, new) global baz_s_handler_self baz_s_handler_self = self return def _sd_changed(self, name, old, new): print 'BazNoModify._sd_changed( %s, %s, %s, %s)' % (self, name, old, new) global baz_sd_handler_self baz_sd_handler_self = self return def _t_changed(self, name, old, new): print 'BazNoModify._t_changed( %s, %s, %s, %s)' % (self, name, old, new) global baz_t_handler_self baz_t_handler_self = self return
class SetActivePerspectiveAction(WorkbenchAction): """ An action that sets the active perspective. """ #### 'Action' interface ################################################### # Is the action enabled? enabled = Delegate('perspective') # The action's unique identifier (may be None). id = Delegate('perspective') # The action's name (displayed on menus/tool bar tools etc). name = Delegate('perspective') # The action's style. style = 'radio' #### 'SetActivePerspectiveAction' interface ############################### # The perspective that we set the active perspective to. perspective = Instance(IPerspective) ########################################################################### # 'Action' interface. ########################################################################### def destroy(self): """ Destroy the action. """ self.window = None return def perform(self, event): """ Perform the action. """ self.window.active_perspective = self.perspective return ########################################################################### # Private interface. ########################################################################### @on_trait_change('perspective,window.active_perspective') def _refresh_checked(self): """ Refresh the checked state of the action. """ self.checked = self.perspective is not None \ and self.window is not None \ and self.window.active_perspective is not None \ and self.perspective.id is self.window.active_perspective.id return
class Child(HasTraits): age = Int # 验证: father属性的值必须是Parent类的实例 father = Instance(Parent) # 代理: Child的实例的last_name属性代理给其father属性的last_name last_name = Delegate('father') # 监听: 当age属性的值被修改时,下面的函数将被运行 def _age_changed(self, old, new): print 'Age changed from %s to %s ' % (old, new)
class Child(HasTraits): age = Int # VALIDATION: 'father' must be a Parent instance: father = Instance(Parent) # DELEGATION: 'last_name' is delegated to father's 'last_name': last_name = Delegate('father') # NOTIFICATION: This method is called when 'age' changes: def _age_changed(self, old, new): print 'Age changed from %s to %s ' % (old, new)
class BazModify(HasTraits): foo = Instance(Foo, ()) sd = Delegate('foo', prefix='s', modify=True) t = Delegate('foo', modify=True) def _s_changed(self, name, old, new): # should never be called print 'BazModify._s_changed( %s, %s, %s, %s)' % (self, name, old, new) global baz_s_handler_self baz_s_handler_self = self return def _sd_changed(self, name, old, new): print 'BazModify._sd_changed( %s, %s, %s, %s)' % (self, name, old, new) global baz_sd_handler_self baz_sd_handler_self = self return def _t_changed(self, name, old, new): print 'BazModify._t_changed( %s, %s, %s, %s)' % (self, name, old, new) global baz_t_handler_self baz_t_handler_self = self return
class VirtualDataName(HasPrivateTraits): # The TemplateDataName this is a virtual copy of: data_name = Instance(TemplateDataName) # The data name description: description = Delegate('data_name', modify=True) # The 'virtual' traits of this object: value0 = VirtualValue(index=0) value1 = VirtualValue(index=1) value2 = VirtualValue(index=2) value3 = VirtualValue(index=3) value4 = VirtualValue(index=4) value5 = VirtualValue(index=5)
class Foo(HasTraits): a = Any b = Bool s = Str i = Instance(HasTraits) e = Event d = Delegate('i') p = Property def _get_p(self): return self._p def _set_p(self, p): self._p = p # Read Only Property p_ro = Property def _get_p_ro(self): return id(self)
# The default dock style to use dock_style_trait = Enum('fixed', 'horizontal', 'vertical', 'tab', desc="the default docking style to use") # The default notebook tab image to use image_trait = Instance('enthought.pyface.image_resource.ImageResource', desc='the image to be displayed on notebook tabs') # The category of elements dragged out of the view export_trait = Str(desc='the category of elements dragged out of the view') # Delegate a trait value to the object's **container** trait container_delegate = Delegate('container') # An identifier for the external help context help_id_trait = Str(desc="the external help context identifier") # A button to add to a view a_button = Trait('', Str, Instance('enthought.traits.ui.menu.Action')) # The set of buttons to add to the view buttons_trait = List(a_button, desc='the action buttons to add to the bottom of ' 'the view') # View trait specified by name or instance: AView = Any #AView = Trait( '', Str, Instance( 'enthought.traits.ui.View' ) )
class EngineView(HasTraits): """ A view displaying the engine's object tree. """ # The MayaVi engine we are a view of. engine = Instance(Engine, allow_none=True) # Path used to search for images _image_path = [ join(resource_path(), 'images'), ] # The icon of the dialog icon = ImageResource('mv2.ico', search_path=_image_path) # Nodes on the tree. nodes = Any # TreeEditor tree_editor = Instance(TreeEditor) # Toolbar toolbar = Instance(ToolBar) # Toolbar actions. actions = List(Either(Action, Separator)) # Some delegates, for the toolbar to update scenes = Delegate('engine') current_selection = Delegate('engine') ########################################################################### # `object` interface. ########################################################################### def __init__(self, **traits): super(EngineView, self).__init__(**traits) ########################################################################### # `HasTraits` interface. ########################################################################### def default_traits_view(self): """The default traits view of the Engine View. """ view = View(Item(name='engine', id='engine', editor=self.tree_editor, resizable=True, show_label=False), id='enthought.mayavi.engine', help=False, resizable=True, scrollable=True, undo=False, revert=False, ok=False, cancel=False, icon=self.icon, title='Mayavi pipeline', toolbar=self.toolbar, handler=EngineViewHandler) return view def _nodes_default(self): """ The default value of the cached nodes list. """ # Now setup the view. nodes = [ TreeNode( node_for=[Engine], children='children_ui_list', label='=Mayavi', auto_open=False, copy=False, delete=False, rename=True, ), ObjectTreeNode( node_for=[Base], children='children_ui_list', label='name', auto_open=True, copy=True, delete=True, rename=True, tooltip='=Right click for more options', ), AdderTreeNode( node_for=[SceneAdderNode], icon_item='add_scene.png', ), AdderTreeNode( node_for=[SourceAdderNode], icon_item='add_source.png', ), AdderTreeNode( node_for=[ModuleFilterAdderNode], icon_item='add_module.png', ), ] return nodes def _tree_editor_default(self): return TreeEditor(editable=False, hide_root=True, on_dclick='handler._on_dclick', on_select='handler._on_select', orientation='vertical', selected='object.engine.current_selection', nodes=self.nodes) def _toolbar_default(self): toolbar = ToolBar(*self.actions) toolbar.image_size = (16, 16) toolbar.show_tool_names = False toolbar.show_divider = False return toolbar def _actions_default(self): add_scene = \ Action( image=ImageResource('add_scene.png', search_path=self._image_path), tooltip="Create a new scene", defined_when='True', enabled_when='True', perform=self._perform_new_scene, ) add_source = \ Action( image=ImageResource('add_source.png', search_path=self._image_path), tooltip="Add a data source", defined_when='True', enabled_when='len(scenes) > 0', perform=self._perform_add_source, ) add_module = \ Action( image=ImageResource('add_module.png', search_path=self._image_path), tooltip="Add a visualization module", defined_when='True', # isinstance doesn't work in enabled_when enabled_when=\ 'current_selection is not None and' '( hasattr(current_selection, "output_info")' 'or current_selection.__class__.__name__ ==' '"ModuleFilterAdderNode")', perform=self._perform_add_module, ) add_filter = \ Action( image=ImageResource('add_filter.png', search_path=self._image_path), tooltip="Add a processing filter", defined_when='True', enabled_when=\ 'current_selection is not None and' '( ( hasattr(current_selection, "output_info")' ' and not current_selection.type in (" module", ' ' " module manager"))' 'or current_selection.__class__.__name__ ==' '"ModuleFilterAdderNode")', perform=self._perform_add_filter, ) help = \ Action( image=ImageResource('help-action.png', search_path=self._image_path), tooltip="Help on the Mayavi pipeline", defined_when='True', enabled_when='True', perform=open_help_index, ) tvtk_docs = \ Action( image=ImageResource('reader.png', search_path=self._image_path), tooltip="Search the VTK class browser", defined_when='True', enabled_when='True', perform=open_tvtk_docs, ) record = \ Action( image=ImageResource('record.png', search_path=self._image_path), tooltip="Start/Stop script recording", style='toggle', checked=False, defined_when='True', enabled_when='engine is not None', perform=self._perform_record, ) # Check the record icon if the engine already has a recorder # set. if self.engine is not None and self.engine.recorder is not None: record.checked = True return [ tvtk_docs, Separator(), add_scene, add_source, add_module, add_filter, Separator(), help, record ] ########################################################################### # Private interface. ########################################################################### def _perform_new_scene(self): self.engine.new_scene() self.engine.current_selection = self.engine.current_scene def _perform_add_source(self): adder = SourceAdderNode(object=self.engine.current_scene) adder.edit_traits(view=adder.dialog_view()) def _perform_add_module(self): object = self.engine.current_selection if isinstance(object, AdderNode): object = object.object adder = ModuleAdderNode(object=object) adder.edit_traits(view=adder.dialog_view()) def _perform_add_filter(self): object = self.engine.current_selection if isinstance(object, AdderNode): object = object.object adder = FilterAdderNode(object=object) adder.edit_traits(view=adder.dialog_view()) def _perform_record(self): e = self.engine if e.recorder is None: start_recording(e, known=True, script_id='engine') else: stop_recording(e, save=False) def _recorder_changed_for_engine(self, recorder): """Called when the recorder trait on the engine trait of this object changes. This basically toggles the recording action when someone attaches a recorder to the engine. """ record_action = None for action in self.actions: if hasattr(action, 'tooltip') and \ action.tooltip.endswith('recording'): record_action = action break if record_action is not None: if recorder is not None: record_action.checked = True else: record_action.checked = False
class WorkbenchWindow(ApplicationWindow): """ A workbench window. """ #### 'IWorkbenchWindow' interface ######################################### # The view or editor that currently has the focus. active_part = Instance(IWorkbenchPart) # The editor manager is used to create/restore editors. editor_manager = Instance(IEditorManager) # The current selection within the window. selection = List # The workbench that the window belongs to. workbench = Instance('enthought.pyface.workbench.api.IWorkbench') #### Editors ####################### # The active editor. active_editor = Instance(IEditor) # The visible (open) editors. editors = List(IEditor) # The Id of the editor area. editor_area_id = Constant('enthought.pyface.workbench.editors') # The (initial) size of the editor area (the user is free to resize it of # course). editor_area_size = Tuple((100, 100)) # Fired when an editor is about to be opened (or restored). editor_opening = Delegate('layout') # Event(IEditor) # Fired when an editor has been opened (or restored). editor_opened = Delegate('layout') # Event(IEditor) # Fired when an editor is about to be closed. editor_closing = Delegate('layout') # Event(IEditor) # Fired when an editor has been closed. editor_closed = Delegate('layout') # Event(IEditor) #### Views ######################### # The active view. active_view = Instance(IView) # The available views (note that this is *all* of the views, not just those # currently visible). # # Views *cannot* be shared between windows as each view has a reference to # its toolkit-specific control etc. views = List(IView) #### Perspectives ################## # The active perspective. active_perspective = Instance(IPerspective) # The available perspectives. If no perspectives are specified then the # a single instance of the 'Perspective' class is created. perspectives = List(IPerspective) # The Id of the default perspective. # # There are two situations in which this is used: # # 1. When the window is being created from scratch (i.e., not restored). # # If this is the empty string, then the first perspective in the list of # perspectives is shown (if there are no perspectives then an instance # of the default 'Perspective' class is used). If this is *not* the # empty string then the perspective with this Id is shown. # # 2. When the window is being restored. # # If this is the empty string, then the last perspective that was # visible when the window last closed is shown. If this is not the empty # string then the perspective with this Id is shown. # default_perspective_id = Str #### 'WorkbenchWindow' interface ########################################## # The window layout is responsible for creating and managing the internal # structure of the window (i.e., it knows how to add and remove views and # editors etc). layout = Instance(WorkbenchWindowLayout) #### 'Private' interface ################################################## # The state of the window suitable for pickling etc. _memento = Instance(WorkbenchWindowMemento) ########################################################################### # 'Window' interface. ########################################################################### def open(self): """ Open the window. Overridden to make the 'opening' event vetoable. Return True if the window opened successfully; False if the open event was vetoed. """ logger.debug('window %s opening', self) # Trait notification. self.opening = event = Vetoable() if not event.veto: if self.control is None: self._create() self.show(True) # Trait notification. self.opened = self logger.debug('window %s opened', self) else: logger.debug('window %s open was vetoed', self) # fixme: This is not actually part of the Pyface 'Window' API (but # maybe it should be). We return this to indicate whether the window # actually opened. return self.control is not None def close(self): """ Closes the window. Overridden to make the 'closing' event vetoable. Return True if the window closed successfully (or was not even open!), False if the close event was vetoed. """ logger.debug('window %s closing', self) if self.control is not None: # Trait notification. self.closing = event = Vetoable() # fixme: Hack to mimic vetoable events! if not event.veto: # Give views and editors a chance to cleanup after themselves. self.destroy_views(self.views) self.destroy_editors(self.editors) # Cleanup the window layout (event handlers, etc.) self.layout.close() # Cleanup the toolkit-specific control. self.destroy() # Cleanup our reference to the control so that we can (at least # in theory!) be opened again. self.control = None # Trait notification. self.closed = self logger.debug('window %s closed', self) else: logger.debug('window %s close was vetoed', self) else: logger.debug('window %s is not open', self) # FIXME v3: This is not actually part of the Pyface 'Window' API (but # maybe it should be). We return this to indicate whether the window # actually closed. return self.control is None ########################################################################### # Protected 'Window' interface. ########################################################################### def _create_contents(self, parent): """ Create and return the window contents. """ # Create the initial window layout. contents = self.layout.create_initial_layout(parent) # Save the initial window layout so that we can reset it when changing # to a perspective that has not been seen yet. self._initial_layout = self.layout.get_view_memento() # Are we creating the window from scratch or restoring it from a # memento? if self._memento is None: self._memento = WorkbenchWindowMemento() else: self._restore_contents() # Set the initial perspective. self.active_perspective = self._get_initial_perspective() return contents ########################################################################### # 'WorkbenchWindow' interface. ########################################################################### #### Initializers ######################################################### def _editor_manager_default(self): """ Trait initializer. """ from editor_manager import EditorManager return EditorManager(window=self) def _layout_default(self): """ Trait initializer. """ return WorkbenchWindowLayout(window=self) #### Methods ############################################################## def activate_editor(self, editor): """ Activates an editor. """ self.layout.activate_editor(editor) return def activate_view(self, view): """ Activates a view. """ self.layout.activate_view(view) return def add_editor(self, editor, title=None): """ Adds an editor. If no title is specified, the editor's name is used. """ if title is None: title = editor.name self.layout.add_editor(editor, title) self.editors.append(editor) return def add_view(self, view, position=None, relative_to=None, size=(-1, -1)): """ Adds a view. """ self.layout.add_view(view, position, relative_to, size) # This case allows for views that are created and added dynamically # (i.e. they were not even known about when the window was created). if not view in self.views: self.views.append(view) return def close_editor(self, editor): """ Closes an editor. """ self.layout.close_editor(editor) return def close_view(self, view): """ Closes a view. fixme: Currently views are never 'closed' in the same sense as an editor is closed. Views are merely hidden. """ self.hide_view(view) return def create_editor(self, obj, kind=None): """ Create an editor for an object. Return None if no editor can be created for the object. """ return self.editor_manager.create_editor(self, obj, kind) def destroy_editors(self, editors): """ Destroy a list of editors. """ for editor in editors: if editor.control is not None: editor.destroy_control() return def destroy_views(self, views): """ Destroy a list of views. """ for view in views: if view.control is not None: view.destroy_control() return def edit(self, obj, kind=None, use_existing=True): """ Edit an object. 'kind' is simply passed through to the window's editor manager to allow it to create a particular kind of editor depending on context etc. If 'use_existing' is True and the object is already being edited in the window then the existing editor will be activated (i.e., given focus, brought to the front, etc.). If 'use_existing' is False, then a new editor will be created even if one already exists. """ if use_existing: # Is the object already being edited in the window? editor = self.get_editor(obj, kind) if editor is not None: # If so, activate the existing editor (i.e., bring it to the # front, give it the focus etc). self.activate_editor(editor) return editor # Otherwise, create an editor for it. editor = self.create_editor(obj, kind) if editor is None: logger.warn('no editor for object %s', obj) self.add_editor(editor) self.activate_editor(editor) return editor def get_editor(self, obj, kind=None): """ Return the editor that is editing an object. Return None if no such editor exists. """ return self.editor_manager.get_editor(self, obj, kind) def get_editor_by_id(self, id): """ Return the editor with the specified Id. Return None if no such editor exists. """ for editor in self.editors: if editor.id == id: break else: editor = None return editor def get_part_by_id(self, id): """ Return the workbench part with the specified Id. Return None if no such part exists. """ return self.get_view_by_id(id) or self.get_editor_by_id(id) def get_perspective_by_id(self, id): """ Return the perspective with the specified Id. Return None if no such perspective exists. """ for perspective in self.perspectives: if perspective.id == id: break else: if id == Perspective.DEFAULT_ID: perspective = Perspective() else: perspective = None return perspective def get_perspective_by_name(self, name): """ Return the perspective with the specified name. Return None if no such perspective exists. """ for perspective in self.perspectives: if perspective.name == name: break else: perspective = None return perspective def get_view_by_id(self, id): """ Return the view with the specified Id. Return None if no such view exists. """ for view in self.views: if view.id == id: break else: view = None return view def hide_editor_area(self): """ Hide the editor area. """ self.layout.hide_editor_area() return def hide_view(self, view): """ Hide a view. """ self.layout.hide_view(view) return def refresh(self): """ Refresh the window to reflect any changes. """ self.layout.refresh() return def reset_active_perspective(self): """ Reset the active perspective back to its original contents. """ perspective = self.active_perspective # If the perspective has been seen before then delete its memento. if perspective.id in self._memento.perspective_mementos: # Remove the perspective's memento. del self._memento.perspective_mementos[perspective.id] # Re-display the perspective (because a memento no longer exists for # the perspective, its 'create_contents' method will be called again). self._show_perspective(perspective, perspective) return def reset_all_perspectives(self): """ Reset all perspectives back to their original contents. """ # Remove all perspective mementos (except user perspectives). for id in self._memento.perspective_mementos.keys(): if not id.startswith('__user_perspective'): del self._memento.perspective_mementos[id] # Re-display the active perspective. self._show_perspective(self.active_perspective,self.active_perspective) return def reset_editors(self): """ Activate the first editor in every tab. """ self.layout.reset_editors() return def reset_views(self): """ Activate the first view in every tab. """ self.layout.reset_views() return def show_editor_area(self): """ Show the editor area. """ self.layout.show_editor_area() return def show_view(self, view): """ Show a view. """ # If the view is already in the window layout, but hidden, then just # show it. # # fixme: This is a little gorpy, reaching into the window layout here, # but currently this is the only thing that knows whether or not the # view exists but is hidden. if self.layout.contains_view(view): self.layout.show_view(view) # Otherwise, we have to add the view to the layout. else: self._add_view_in_default_position(view) self.refresh() return #### Methods for saving and restoring the layout ########################## def get_memento(self): """ Return the state of the window suitable for pickling etc. """ # The size and position of the window. self._memento.size = self.size self._memento.position = self.position # The Id of the active perspective. self._memento.active_perspective_id = self.active_perspective.id # The layout of the active perspective. self._memento.perspective_mementos[self.active_perspective.id] = ( self.layout.get_view_memento(), self.active_view and self.active_view.id or None ) # The layout of the editor area. self._memento.editor_area_memento = self.layout.get_editor_memento() return self._memento def set_memento(self, memento): """ Restore the state of the window from a memento. """ # All we do here is save a reference to the memento - we don't actually # do anything with it until the window is opened. # # This obviously means that you can't set the memento of a window # that is already open, but I can't see a use case for that anyway! self._memento = memento return ########################################################################### # Private interface. ########################################################################### def _add_view_in_default_position(self, view): """ Adds a view in its 'default' position. """ # Is the view in the current perspectives contents list? If it is then # we use the positioning information in the perspective item. Otherwise # we will use the default positioning specified in the view itself. item = self._get_perspective_item(self.active_perspective, view) if item is None: item = view # fixme: This only works because 'PerspectiveItem' and 'View' have the # identical 'position', 'relative_to', 'width' and 'height' traits! We # need to unify these somehow! relative_to = self.get_view_by_id(item.relative_to) size = (item.width, item.height) self.add_view(view, item.position, relative_to, size) return def _get_initial_perspective(self, *methods): """ Return the initial perspective. """ methods = [ # If a default perspective was specified then we prefer that over # any other perspective. self._get_default_perspective, # If there was no default perspective then try the perspective that # was active the last time the application was run. self._get_previous_perspective, # If there was no previous perspective, then try the first one that # we know about. self._get_first_perspective ] for method in methods: perspective = method() if perspective is not None: break # If we have no known perspectives, make a new blank one up. else: logger.warn('no known perspectives - creating a new one') perspective = Perspective() return perspective def _get_default_perspective(self): """ Return the default perspective. Return None if no default perspective was specified or it no longer exists. """ id = self.default_perspective_id if len(id) > 0: perspective = self.get_perspective_by_id(id) if perspective is None: logger.warn('default perspective %s no longer available', id) else: perspective = None return perspective def _get_previous_perspective(self): """ Return the previous perspective. Return None if there has been no previous perspective or it no longer exists. """ id = self._memento.active_perspective_id if len(id) > 0: perspective = self.get_perspective_by_id(id) if perspective is None: logger.warn('previous perspective %s no longer available', id) else: perspective = None return perspective def _get_first_perspective(self): """ Return the first perspective in our list of perspectives. Return None if no perspectives have been defined. """ if len(self.perspectives) > 0: perspective = self.perspectives[0] else: perspective = None return perspective def _get_perspective_item(self, perspective, view): """ Return the perspective item for a view. Return None if the view is not mentioned in the perspectives contents. """ # fixme: Errrr, shouldn't this be a method on the window?!? for item in perspective.contents: if item.id == view.id: break else: item = None return item def _hide_perspective(self, perspective): """ Hide a perspective. """ # fixme: This is a bit ugly but... when we restore the layout we ignore # the default view visibility. for view in self.views: view.visible = False # Save the current layout of the perspective. self._memento.perspective_mementos[perspective.id] = ( self.layout.get_view_memento(), self.active_view and self.active_view.id or None ) return def _show_perspective(self, old, new): """ Show a perspective. """ # If the perspective has been seen before then restore it. memento = self._memento.perspective_mementos.get(new.id) if memento is not None: view_memento, active_view_id = memento self.layout.set_view_memento(view_memento) # Make sure the active part, view and editor reflect the new # perspective. view = self.get_view_by_id(active_view_id) if view is not None: self.active_view = view # Otherwise, this is the first time the perspective has been seen # so create it. else: if old is not None: # Reset the window layout to its initial state. self.layout.set_view_memento(self._initial_layout) # Create the perspective in the window. new.create(self) # Make sure the active part, view and editor reflect the new # perspective. self.active_view = None # Show the editor area? if new.show_editor_area: self.show_editor_area() else: self.hide_editor_area() self.active_editor = None # Inform the perspective that it has been shown. new.show(self) # This forces the dock window to update its layout. if old is not None: self.refresh() return def _restore_contents(self): """ Restore the contents of the window. """ self.layout.set_editor_memento(self._memento.editor_area_memento) self.size = self._memento.size self.position = self._memento.position return #### Trait change handlers ################################################ #### Static #### def _active_perspective_changed(self, old, new): """ Static trait change handler. """ logger.debug('active perspective changed from <%s> to <%s>', old, new) # Hide the old perspective... if old is not None: self._hide_perspective(old) # ... and show the new one. if new is not None: self._show_perspective(old, new) return def _active_editor_changed(self, old, new): """ Static trait change handler. """ logger.debug('active editor changed from <%s> to <%s>', old, new) self.active_part = new return def _active_part_changed(self, old, new): """ Static trait change handler. """ if new is None: self.selection = [] else: self.selection = new.selection logger.debug('active part changed from <%s> to <%s>', old, new) return def _active_view_changed(self, old, new): """ Static trait change handler. """ logger.debug('active view changed from <%s> to <%s>', old, new) self.active_part = new return def _views_changed(self, old, new): """ Static trait change handler. """ # Cleanup any old views. for view in old: view.window = None # Initialize any new views. for view in new: view.window = self return def _views_items_changed(self, event): """ Static trait change handler. """ # Cleanup any old views. for view in event.removed: view.window = None # Initialize any new views. for view in event.added: view.window = self return #### Dynamic #### @on_trait_change('layout.editor_closed') def _on_editor_closed(self, editor): """ Dynamic trait change handler. """ index = self.editors.index(editor) del self.editors[index] if editor is self.active_editor: if len(self.editors) > 0: index = min(index, len(self.editors) - 1) # If the user closed the editor manually then this method is # being called from a toolkit-specific event handler. Because # of that we have to make sure that we don't change the focus # from within this method directly hence we activate the editor # later in the GUI thread. GUI.invoke_later(self.activate_editor, self.editors[index]) else: self.active_editor = None return @on_trait_change('editors.has_focus') def _on_editor_has_focus_changed(self, obj, trait_name, old, new): """ Dynamic trait change handler. """ if trait_name == 'has_focus' and new: self.active_editor = obj return @on_trait_change('views.has_focus') def _has_focus_changed_for_view(self, obj, trait_name, old, new): """ Dynamic trait change handler. """ if trait_name == 'has_focus' and new: self.active_view = obj return @on_trait_change('views.visible') def _visible_changed_for_view(self, obj, trait_name, old, new): """ Dynamic trait change handler. """ if trait_name == 'visible': if not new: if obj is self.active_view: self.active_view = None return
class PreferencesNode(TreeItem): """ Abstract base class for a node in a preferences dialog. A preferences node has a name and an image which are used to represent the node in a preferences dialog (usually in the form of a tree). """ #### 'PreferenceNode' interface ########################################### # The page's help identifier (optional). If a help Id *is* provided then # there will be a 'Help' button shown on the preference page. help_id = Delegate('page') # The page name (this is what is shown in the preferences dialog. name = Delegate('page') # The page that we are a node for. page = Instance(IPreferencesPage) ########################################################################### # 'object' interface. ########################################################################### def __str__(self): """ Returns the string representation of the item. """ if self.page is None: s = 'root' else: s = self.page.name return s __repr__ = __str__ ########################################################################### # 'PreferencesNode' interface. ########################################################################### def create_page(self, parent): """ Creates the preference page for this node. """ return self.page.create_control(parent) def lookup(self, name): """ Returns the child of this node with the specified Id. Returns None if no such child exists. """ for node in self.children: if node.name == name: break else: node = None return node ########################################################################### # Debugging interface. ########################################################################### def dump(self, indent=''): """ Pretty-print the node to stdout. """ print indent, 'Node', str(self) for child in self.children: child.dump(indent + ' ') return
class AbstractAdapterFactory(HasTraits): """ Abstract base class for all adapter factories. Adapter factories define behavioural extensions for classes. """ #### 'AbstractAdapterFactory' interface ################################### # The adapter manager that the factory is registered with (this will be # None iff the factory is not registered with a manager). adapter_manager = Instance(AdapterManager) # The type system used by the factory (it determines 'is_a' relationships # and type MROs etc). By default we use standard Python semantics. type_system = Delegate('adapter_manager') ########################################################################### # 'AbstractAdapterFactory' interface. ########################################################################### def adapt(self, adaptee, target_class, *args, **kw): """ Returns an adapter that adapts an object to the target class. Returns None if the factory cannot produce such an adapter. """ if self._can_adapt(adaptee, target_class, *args, **kw): adapter = self._adapt(adaptee, target_class, *args, **kw) if adapter is None: logger.warn(self._get_warning_message(adaptee, target_class)) else: adapter = None return adapter ########################################################################### # Protected 'AbstractAdapterFactory' interface. ########################################################################### def _can_adapt(self, adaptee, target_class, *args, **kw): """ Returns True if the factory can produce an appropriate adapter. """ raise NotImplementedError def _adapt(self, adaptee, target_class, *args, **kw): """ Returns an adapter that adapts an object to the target class. """ raise NotImplementedError ########################################################################### # Private interface. ########################################################################### def _get_warning_message(self, adaptee, target_class): """ Returns a warning message. The warning message is used when a factory fails to adapt something that it said it could! """ message = '%s failed to adapt %s to %s' % ( self.__class__.__name__, str(adaptee), target_class.__name__) return message
class DataSetClipper(Filter): # The version of this class. Used for persistence. __version__ = 0 # The widgets to be used for the Clipping Filter. widget = Instance(ImplicitWidgets, allow_none=False, record=True) # The clipping filter. filter = Instance(tvtk.Object, allow_none=False, record=True) # The update mode of the widget-- this is delegated to the # ImplicitWidgets. update_mode = Delegate('widget', modify=True) input_info = PipelineInfo(datasets=['any'], attribute_types=['any'], attributes=['any']) output_info = PipelineInfo(datasets=['any'], attributes=['any']) ######################################## # View related traits. # Button to reset the boundaries of the implicit_widget. reset_button = Button('Reset Boundaries') view = View(Group(Group(Item('update_mode'), ), Group(Item('reset_button'), Item(name='widget', style='custom', resizable=True), show_labels=False), label='ImplicitWidget'), Group(Group(Item('filter', style='custom'), show_labels=False), label='Clipper'), resizable=True) ######################################## # Private traits. _transform = Instance(tvtk.Transform, allow_none=False) ###################################################################### # `object` interface. ###################################################################### def __get_pure_state__(self): d = super(DataSetClipper, self).__get_pure_state__() for name in ('_first', '_observer_id'): d.pop(name, None) d['matrix'] = cPickle.dumps(self._transform.matrix) return d def __set_pure_state__(self, state): mat = state.pop('matrix') super(DataSetClipper, self).__set_pure_state__(state) state_pickler.set_state(self, state) self._transform.set_matrix(cPickle.loads(mat)) self.widget.set_transform(self._transform) ###################################################################### # `Filter` interface ###################################################################### def setup_pipeline(self): self.widget = ImplicitWidgets() self._transform = tvtk.Transform() self.filter = tvtk.ClipDataSet() self.widget.on_trait_change(self._handle_widget, 'widget') super(DataSetClipper, self).setup_pipeline() def update_pipeline(self): inputs = self.inputs if len(inputs) == 0: return widget = self.widget widget.inputs = inputs widget.update_pipeline() filter = self.filter filter.input = inputs[0].outputs[0] widget.update_implicit_function() filter.clip_function = widget.implicit_function filter.update() self._set_outputs([filter.output]) self.pipeline_changed = True def update_data(self): # Do nothing if there is no input. if len(self.inputs) == 0: return self.filter.update() # Propagate the data_changed event. self.data_changed = True ###################################################################### # Non-public methods. ###################################################################### def _on_interaction_event(self, obj, event): tfm = self._transform self.widget.widget.get_transform(tfm) recorder = self.recorder if recorder is not None: state = {} state['elements'] = tfm.matrix.__getstate__()['elements'] name = recorder.get_script_id(self) recorder.record('%s._transform.matrix.__setstate__(%s)'\ %(name, state)) recorder.record('%s.widget.widget.set_transform(%s._transform)'\ %(name, name)) recorder.record('%s.widget.update_implicit_function()' % name) recorder.record('%s.render()' % name) def _widget_changed(self, old, new): self.widgets = self.widget.widgets if len(self.inputs) > 0: new.inputs = self.inputs new.update_pipeline() self._observer_id = new.widget.add_observer(self.update_mode_, self._on_interaction_event) def _filter_changed(self, old, new): if old is not None: old.on_trait_change(self.render, remove=True) new.on_trait_change(self.render) if len(self.inputs) > 0: inp = self.inputs[0].outputs[0] new.input = inp self.outputs = [new.output] def _reset_button_fired(self): self.widget.widget.place_widget() self.widget.update_implicit_function() self.filter.update() self.render() def _handle_widget(self, value): self.widgets = self.widget.widgets f = self.filter f.clip_function = self.widget.implicit_function f.update() self.update_pipeline()
class Streamline(Module): # The version of this class. Used for persistence. __version__ = 0 # The streamline generator. stream_tracer = Instance(tvtk.StreamTracer, allow_none=False, record=True) # The seed for the streamlines. seed = Instance(SourceWidget, allow_none=False, record=True) # The update mode of the seed -- this is delegated to the # SourceWidget. update_mode = Delegate('seed', modify=True) # Determines if the streamlines are shown as lines or ribbons or # tubes. streamline_type = Trait('line', TraitPrefixList(['line', 'ribbon', 'tube']), desc='draw streamlines as lines/ribbons/tubes') # The ribbon filter. ribbon_filter = Instance(tvtk.RibbonFilter, allow_none=False, record=True) # The tube filter. tube_filter = Instance(tvtk.TubeFilter, allow_none=False, record=True) # The actor component that represents the visualization. actor = Instance(Actor, allow_none=False, record=True) input_info = PipelineInfo(datasets=['any'], attribute_types=['any'], attributes=['vectors']) ######################################## # Private traits. _first = Bool(True) ######################################## # View related code. # A button to update the streamlines. update_streamlines = Button('Update Streamlines') _tube_group = Group(Item(name='capping'), Item(name='sides_share_vertices'), Item(name='vary_radius'), Item(name='number_of_sides'), Item(name='radius'), Item(name='radius_factor'), Item(name='offset'), Item(name='on_ratio')) _ribbon_group = Group(Item(name='vary_width'), Item(name='width'), Item(name='width_factor'), Item(name='angle')) view = View(Group( Group(Item(name='update_mode'), ), Group( Item(name='update_streamlines'), show_labels=False, ), Group(Item(name='streamline_type'), Item(name='ribbon_filter', style='custom', visible_when='object.streamline_type == "ribbon"', editor=InstanceEditor(view=View(_ribbon_group))), Item(name='tube_filter', style='custom', visible_when='object.streamline_type == "tube"', editor=InstanceEditor(view=View(_tube_group))), show_labels=False, label='Streamline'), label='Streamline'), Group(Item(name='seed', style='custom', resizable=True), label='Seed', show_labels=False), Group(Item(name='stream_tracer', style='custom', resizable=True), label='StreamTracer', show_labels=False), Group(Item(name='actor', style='custom'), label='Actor', show_labels=False), resizable=True) ###################################################################### # `Module` interface ###################################################################### def setup_pipeline(self): """Override this method so that it *creates* the tvtk pipeline. This method is invoked when the object is initialized via `__init__`. Note that at the time this method is called, the tvtk data pipeline will *not* yet be setup. So upstream data will not be available. The idea is that you simply create the basic objects and setup those parts of the pipeline not dependent on upstream sources and filters. You should also set the `actors` attribute up at this point. """ # Create and setup the default objects. self.seed = SourceWidget() self.stream_tracer = tvtk.StreamTracer( maximum_propagation=50, integration_direction='forward', compute_vorticity=True, integrator_type='runge_kutta4', ) self.ribbon_filter = tvtk.RibbonFilter() self.tube_filter = tvtk.TubeFilter() self.actor = Actor() # Setup the actor suitably for this module. self.actor.property.line_width = 2.0 def update_pipeline(self): """Override this method so that it *updates* the tvtk pipeline when data upstream is known to have changed. This method is invoked (automatically) when any of the inputs sends a `pipeline_changed` event. """ mm = self.module_manager if mm is None: return src = mm.source self.stream_tracer.input = src.outputs[0] self.seed.inputs = [src] # Setup the radius/width of the tube/ribbon filters based on # given input. if self._first: b = src.outputs[0].bounds l = [(b[1] - b[0]), (b[3] - b[2]), (b[5] - b[4])] length = sqrt(l[0] * l[0] + l[1] * l[1] + l[2] * l[2]) self.ribbon_filter.width = length * 0.0075 self.tube_filter.radius = length * 0.0075 self._first = False self._streamline_type_changed(self.streamline_type) # Set the LUT for the mapper. self.actor.set_lut(mm.scalar_lut_manager.lut) self.pipeline_changed = True def update_data(self): """Override this method so that it flushes the vtk pipeline if that is necessary. This method is invoked (automatically) when any of the inputs sends a `data_changed` event. """ # Just set data_changed, the components should do the rest if # they are connected. self.data_changed = True ###################################################################### # Non-public methods. ###################################################################### def _streamline_type_changed(self, value): if self.module_manager is None: return st = self.stream_tracer rf = self.ribbon_filter tf = self.tube_filter if value == 'line': self.outputs = [st.output] elif value == 'ribbon': rf.input = st.output self.outputs = [rf.output] elif value == 'tube': tf.input = st.output self.outputs = [tf.output] self.render() def _update_streamlines_fired(self): self.seed.update_poly_data() self.render() def _stream_tracer_changed(self, old, new): if old is not None: old.on_trait_change(self.render, remove=True) seed = self.seed if seed is not None: new.source = seed.poly_data new.on_trait_change(self.render) mm = self.module_manager if mm is not None: new.input = mm.source.outputs[0] # A default output so there are no pipeline errors. The # update_pipeline call corrects this if needed. self.outputs = [new.output] self.update_pipeline() def _seed_changed(self, old, new): st = self.stream_tracer if st is not None: st.source = new.poly_data self._change_components(old, new) def _ribbon_filter_changed(self, old, new): if old is not None: old.on_trait_change(self.render, remove=True) new.on_trait_change(self.render) self._streamline_type_changed(self.streamline_type) def _tube_filter_changed(self, old, new): if old is not None: old.on_trait_change(self.render, remove=True) new.on_trait_change(self.render) self._streamline_type_changed(self.streamline_type) def _actor_changed(self, old, new): new.scene = self.scene new.inputs = [self] self._change_components(old, new)
class ToggleViewVisibilityAction(WorkbenchAction): """ An action that toggles a view's visibility (ie. hides/shows it). """ #### 'Action' interface ################################################### # The action's unique identifier (may be None). id = Delegate('view', modify=True) # The action's name (displayed on menus/tool bar tools etc). name = Delegate('view', modify=True) # The action's style. style = 'toggle' #### 'ViewAction' interface ############################################### # The view that we toggle the visibility for. view = Instance(IView) ########################################################################### # 'Action' interface. ########################################################################### def destroy(self): """ Called when the action is no longer required. """ if self.view is not None: self._remove_view_listeners(self.view) return def perform(self, event): """ Perform the action. """ self._toggle_view_visibility(self.view) return ########################################################################### # Private interface. ########################################################################### #### Trait change handlers ################################################ def _view_changed(self, old, new): """ Static trait change handler. """ if old is not None: self._remove_view_listeners(old) if new is not None: self._add_view_listeners(new) self._refresh_checked() return #### Methods ############################################################## def _add_view_listeners(self, view): """ Add listeners for trait events on a view. """ view.on_trait_change(self._refresh_checked, 'visible') view.on_trait_change(self._refresh_checked, 'window') return def _remove_view_listeners(self, view): """ Add listeners for trait events on a view. """ view.on_trait_change(self._refresh_checked, 'visible', remove=True) view.on_trait_change(self._refresh_checked, 'window', remove=True) return def _refresh_checked(self): """ Refresh the checked state of the action. """ self.checked = self.view is not None \ and self.view.window is not None \ and self.view.visible return def _toggle_view_visibility(self, view): """ Toggle the visibility of a view. """ if view.visible: view.hide() else: view.show() return
class CameraControl(HasTraits): # Traits positions = List(CameraPosition) yt_scene = Instance('YTScene') center = Delegate('yt_scene') scene = Delegate('yt_scene') camera = Instance(tvtk.OpenGLCamera) reset_position = Instance(CameraPosition) fps = Float(25.0) export_filename = 'frames' periodic = Bool # UI elements snapshot = Button() play = Button() export_frames = Button() reset_path = Button() recenter = Button() save_path = Button() load_path = Button() export_path = Button() table_def = TableEditor(columns=[ ObjectColumn(name='position'), ObjectColumn(name='focal_point'), ObjectColumn(name='view_up'), ObjectColumn(name='clipping_range'), ObjectColumn(name='num_steps') ], reorderable=True, deletable=True, sortable=True, sort_model=True, show_toolbar=True, selection_mode='row', selected='reset_position') default_view = View( VGroup( HGroup(Item('camera', show_label=False), Item('recenter', show_label=False), label='Camera'), HGroup(Item('snapshot', show_label=False), Item('play', show_label=False), Item('export_frames', show_label=False), Item('reset_path', show_label=False), Item('save_path', show_label=False), Item('load_path', show_label=False), Item('export_path', show_label=False), Item('export_filename'), Item('periodic'), Item('fps'), label='Playback'), VGroup(Item('positions', show_label=False, editor=table_def), label='Camera Path'), ), resizable=True, title="Camera Path Editor", ) def _reset_position_changed(self, old, new): if new is None: return cam = self.scene.camera cam.position = new.position cam.focal_point = new.focal_point cam.view_up = new.view_up cam.clipping_range = new.clipping_range self.scene.render() def __init__(self, **traits): HasTraits.__init__(self, **traits) def take_snapshot(self): cam = self.scene.camera self.positions.append( CameraPosition(position=cam.position, focal_point=cam.focal_point, view_up=cam.view_up, clipping_range=cam.clipping_range, distance=cam.distance, orientation_wxyz=cam.orientation_wxyz)) def _export_path_fired(self): dlg = pyface.FileDialog( action='save as', wildcard="*.cpath", ) if dlg.open() == pyface.OK: print "Saving:", dlg.path self.export_camera_path(dlg.path) def export_camera_path(self, fn): to_dump = dict(positions=[], focal_points=[], view_ups=[], clipping_ranges=[], distances=[], orientation_wxyzs=[]) def _write(cam): to_dump['positions'].append(cam.position) to_dump['focal_points'].append(cam.focal_point) to_dump['view_ups'].append(cam.view_up) to_dump['clipping_ranges'].append(cam.clipping_range) to_dump['distances'].append(cam.distance) to_dump['orientation_wxyzs'].append(cam.orientation_wxyz) self.step_through(0.0, callback=_write) pickle.dump(to_dump, open(fn, "wb")) def _save_path_fired(self): dlg = pyface.FileDialog( action='save as', wildcard="*.cpath", ) if dlg.open() == pyface.OK: print "Saving:", dlg.path self.dump_camera_path(dlg.path) def dump_camera_path(self, fn): to_dump = dict(positions=[], focal_points=[], view_ups=[], clipping_ranges=[], distances=[], orientation_wxyzs=[], num_stepss=[]) for p in self.positions: to_dump['positions'].append(p.position) to_dump['focal_points'].append(p.focal_point) to_dump['view_ups'].append(p.view_up) to_dump['clipping_ranges'].append(p.clipping_range) to_dump['distances'].append(p.distance) to_dump['num_stepss'].append(p.num_steps) # stupid s to_dump['orientation_wxyzs'].append(p.orientation_wxyz) pickle.dump(to_dump, open(fn, "wb")) def _load_path_fired(self): dlg = pyface.FileDialog( action='open', wildcard="*.cpath", ) if dlg.open() == pyface.OK: print "Loading:", dlg.path self.load_camera_path(dlg.path) def load_camera_path(self, fn): to_use = pickle.load(open(fn, "rb")) self.positions = [] for i in range(len(to_use['positions'])): dd = {} for kw in to_use: # Strip the s dd[kw[:-1]] = to_use[kw][i] self.positions.append(CameraPosition(**dd)) def _recenter_fired(self): self.camera.focal_point = self.center self.scene.render() def _snapshot_fired(self): self.take_snapshot() def _play_fired(self): self.step_through() def _export_frames_fired(self): self.step_through(save_frames=True) def _reset_path_fired(self): self.positions = [] def step_through(self, pause=1.0, callback=None, save_frames=False): cam = self.scene.camera frame_counter = 0 if self.periodic: cyclic_pos = self.positions + [self.positions[0]] else: cyclic_pos = self.positions for i in range(len(cyclic_pos) - 1): pos1 = cyclic_pos[i] pos2 = cyclic_pos[i + 1] r = pos1.num_steps for p in range(pos1.num_steps): po = _interpolate(pos1.position, pos2.position, p, r) fp = _interpolate(pos1.focal_point, pos2.focal_point, p, r) vu = _interpolate(pos1.view_up, pos2.view_up, p, r) cr = _interpolate(pos1.clipping_range, pos2.clipping_range, p, r) _set_cpos(cam, po, fp, vu, cr) self.scene.render() if callback is not None: callback(cam) if save_frames: self.scene.save("%s_%0.5d.png" % (self.export_filename, frame_counter)) else: time.sleep(pause * 1.0 / self.fps) frame_counter += 1
class YTScene(HasTraits): # Traits importer = Instance(HierarchyImporter) pf = Delegate("importer") min_grid_level = Delegate("importer") number_of_levels = Delegate("importer") field = Delegate("importer") center = CArray(shape=(3, ), dtype='float64') center_on_max = Delegate("importer") smoothed = Delegate("importer") cache = Delegate("importer") show_grids = Delegate("importer") camera_path = Instance(CameraControl) #window = Instance(ivtk.IVTKWithCrustAndBrowser) #python_shell = Delegate('window') #scene = Delegate('window') scene = Instance(HasTraits) operators = List(HasTraits) # State variables _grid_boundaries_actor = None # Views def _window_default(self): # Should experiment with passing in a pipeline browser # that has two root objects -- one for TVTKBases, i.e. the render # window, and one that accepts our objects return ivtk.IVTKWithCrustAndBrowser(size=(800, 600), stereo=1) def _camera_path_default(self): return CameraControl(yt_scene=self, camera=self.scene.camera) def __init__(self, **traits): HasTraits.__init__(self, **traits) max_level = min(self.pf.h.max_level, self.min_grid_level + self.number_of_levels - 1) self.extracted_pf = ExtractedParameterFile(self.pf, self.min_grid_level, max_level, offset=None) self.extracted_hierarchy = self.extracted_pf.h self._hdata_set = tvtk.HierarchicalBoxDataSet() self._ugs = [] self._grids = [] self._min_val = 1e60 self._max_val = -1e60 gid = 0 if self.cache: for grid_set in self.extracted_hierarchy.get_levels(): for grid in grid_set: grid[self.field] for l, grid_set in enumerate(self.extracted_hierarchy.get_levels()): gid = self._add_level(grid_set, l, gid) if self.show_grids: self.toggle_grid_boundaries() def _center_default(self): return self.extracted_hierarchy._convert_coords([0.5, 0.5, 0.5]) def do_center_on_max(self): self.center = self.extracted_hierarchy._convert_coords( self.pf.h.find_max("Density")[1]) self.scene.camera.focal_point = self.center def _add_level(self, grid_set, level, gid): for grid in grid_set: self._hdata_set.set_refinement_ratio(level, 2) gid = self._add_grid(grid, gid, level) return gid def _add_grid(self, grid, gid, level=0): mylog.debug("Adding grid %s on level %s (%s)", grid.id, level, grid.Level) if grid in self._grids: return self._grids.append(grid) scalars = grid.get_vertex_centered_data(self.field, smoothed=self.smoothed) left_index = grid.get_global_startindex() origin = grid.LeftEdge dds = grid.dds right_index = left_index + scalars.shape - 1 ug = tvtk.UniformGrid(origin=origin, spacing=dds, dimensions=grid.ActiveDimensions + 1) if self.field not in self.pf.field_info or \ self.pf.field_info[self.field].take_log: scalars = na.log10(scalars) ug.point_data.scalars = scalars.transpose().ravel() ug.point_data.scalars.name = self.field if grid.Level != self.min_grid_level + self.number_of_levels - 1: ug.cell_visibility_array = grid.child_mask.transpose().ravel() else: ug.cell_visibility_array = na.ones(grid.ActiveDimensions, dtype='int').ravel() self._ugs.append((grid, ug)) self._hdata_set.set_data_set(level, gid, left_index, right_index, ug) self._min_val = min(self._min_val, scalars.min()) self._max_val = max(self._max_val, scalars.max()) gid += 1 return gid def _add_data_to_ug(self, field): for g, ug in self._ugs: scalars_temp = grid.get_vertex_centered_data( field, smoothed=self.smoothed) ii = ug.point_data.add_array(scalars_temp.transpose().ravel()) ug.point_data.get_array(ii).name = field def zoom(self, dist, unit='1'): vec = self.scene.camera.focal_point - \ self.scene.camera.position self.scene.camera.position += \ vec * dist/self._grids[0].pf[unit] self.scene.render() def toggle_grid_boundaries(self): if self._grid_boundaries_actor is None: # We don't need to track this stuff right now. ocf = tvtk.OutlineCornerFilter( executive=tvtk.CompositeDataPipeline(), corner_factor=0.5) ocf.input = self._hdata_set ocm = tvtk.HierarchicalPolyDataMapper( input_connection=ocf.output_port) self._grid_boundaries_actor = tvtk.Actor(mapper=ocm) self.scene.add_actor(self._grid_boundaries_actor) else: self._grid_boundaries_actor.visibility = \ (not self._grid_boundaries_actor.visibility) def _add_sphere(self, origin=(0.0, 0.0, 0.0), normal=(0, 1, 0)): sphere = tvtk.Sphere(center=origin, radius=0.25) cutter = tvtk.Cutter(executive=tvtk.CompositeDataPipeline(), cut_function=sphere) cutter.input = self._hdata_set lut_manager = LUTManager(data_name=self.field, scene=self.scene) smap = tvtk.HierarchicalPolyDataMapper( scalar_range=(self._min_val, self._max_val), lookup_table=lut_manager.lut, input_connection=cutter.output_port) sactor = tvtk.Actor(mapper=smap) self.scene.add_actors(sactor) return sphere, lut_manager def _add_plane(self, origin=(0.0, 0.0, 0.0), normal=(0, 1, 0)): plane = tvtk.Plane(origin=origin, normal=normal) cutter = tvtk.Cutter(executive=tvtk.CompositeDataPipeline(), cut_function=plane) cutter.input = self._hdata_set lut_manager = LUTManager(data_name=self.field, scene=self.scene) smap = tvtk.HierarchicalPolyDataMapper( scalar_range=(self._min_val, self._max_val), lookup_table=lut_manager.lut, input_connection=cutter.output_port) sactor = tvtk.Actor(mapper=smap) self.scene.add_actors(sactor) return plane, lut_manager def add_plane(self, origin=(0.0, 0.0, 0.0), normal=(0, 1, 0)): self.operators.append(self._add_plane(origin, normal)) return self.operators[-1] def _add_axis_plane(self, axis): normal = [0, 0, 0] normal[axis] = 1 np, lut_manager = self._add_plane(self.center, normal=normal) LE = self.extracted_hierarchy.min_left_edge RE = self.extracted_hierarchy.max_right_edge self.operators.append( MappingPlane(vmin=LE[axis], vmax=RE[axis], vdefault=self.center[axis], post_call=self.scene.render, plane=np, axis=axis, coord=0.0, lut_manager=lut_manager, scene=self.scene)) def add_x_plane(self): self._add_axis_plane(0) return self.operators[-1] def add_y_plane(self): self._add_axis_plane(1) return self.operators[-1] def add_z_plane(self): self._add_axis_plane(2) return self.operators[-1] def add_contour(self, val=None): if val is None: if self._min_val != self._min_val: self._min_val = 1.0 val = (self._max_val + self._min_val) * 0.5 cubes = tvtk.MarchingCubes(executive=tvtk.CompositeDataPipeline()) cubes.input = self._hdata_set cubes.set_value(0, val) lut_manager = LUTManager(data_name=self.field, scene=self.scene) cube_mapper = tvtk.HierarchicalPolyDataMapper( input_connection=cubes.output_port, lookup_table=lut_manager.lut) cube_mapper.color_mode = 'map_scalars' cube_mapper.scalar_range = (self._min_val, self._max_val) cube_actor = tvtk.Actor(mapper=cube_mapper) self.scene.add_actors(cube_actor) self.operators.append( MappingMarchingCubes(operator=cubes, vmin=self._min_val, vmax=self._max_val, vdefault=val, mapper=cube_mapper, post_call=self.scene.render, lut_manager=lut_manager, scene=self.scene)) return self.operators[-1] def add_isocontour(self, val=None): if val is None: val = (self._max_val + self._min_val) * 0.5 isocontour = tvtk.ContourFilter(executive=tvtk.CompositeDataPipeline()) isocontour.input = self._hdata_set isocontour.generate_values(1, (val, val)) lut_manager = LUTManager(data_name=self.field, scene=self.scene) isocontour_normals = tvtk.PolyDataNormals( executive=tvtk.CompositeDataPipeline()) isocontour_normals.input_connection = isocontour.output_port iso_mapper = tvtk.HierarchicalPolyDataMapper( input_connection=isocontour_normals.output_port, lookup_table=lut_manager.lut) iso_mapper.scalar_range = (self._min_val, self._max_val) iso_actor = tvtk.Actor(mapper=iso_mapper) self.scene.add_actors(iso_actor) self.operators.append( MappingIsoContour(operator=isocontour, vmin=self._min_val, vmax=self._max_val, vdefault=val, mapper=iso_mapper, post_call=self.scene.render, lut_manager=lut_manager, scene=self.scene)) return self.operators[-1]
class Bar(HasTraits): foo = Instance(Foo, ()) s = Delegate('foo')
import SequenceTypes, container_delegate #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- # Group orientation trait Orientation = Trait( 'vertical', TraitPrefixList( 'vertical', 'horizontal' ) ) # Group layout trait Layout = Trait( 'normal', TraitPrefixList( 'normal', 'split', 'tabbed', 'flow' ) ) # Delegate trait to the object being "shadowed" ShadowDelegate = Delegate( 'shadow' ) # Amount of padding to add around item Padding = Range( 0, 15, desc = 'amount of padding to add around each item' ) #------------------------------------------------------------------------------- # 'Group' class: #------------------------------------------------------------------------------- class Group ( ViewSubElement ): """Represents a grouping of items in a user interface view. """ #--------------------------------------------------------------------------- # Trait definitions: #---------------------------------------------------------------------------
class GraphViewModel(ModelView): """ Defines a view model for Graphs. """ #-------------------------------------------------------------------------- # Trait definitions: #-------------------------------------------------------------------------- # File path to to use for saving. save_file = File # Is the tree view of the network displayed? show_tree = Bool(True, desc="that the network tree view is visible") # All graphs, subgraphs and clusters. # all_graphs = Property(List(Instance(HasTraits))) all_graphs = Delegate("model") # Select graph when adding to the graph? select_graph = Bool(True) # Working graph instance. selected_graph = Instance(BaseGraph, allow_none=False) # Exit confirmation. prompt_on_exit = Bool(False, desc="exit confirmation request") # Representation of the graph in the Dot language. dot_code = Code # Parse the dot_code and replace the existing model. parse_dot_code = Button("Parse", desc="dot code parsing action that " "replaces the existing model.") #-------------------------------------------------------------------------- # Views: #-------------------------------------------------------------------------- # Default model view. traits_view = View( HGroup( Item( name="model", editor=graph_tree_editor, show_label=False, id=".tree_editor", visible_when="show_tree==True", width=.14 ), Item("model", show_label=False), ), id="graph_view_model.graph_view", title="Godot", icon=frame_icon, resizable=True, style="custom", width=.81, height=.81, kind="live", buttons=NoButtons, menubar=menubar, # toolbar=toolbar, dock="vertical", # statusbar=[StatusItem(name="status", width=0.5), # StatusItem(name="versions", width=200)] ) # File selection view. # file_view = View( # Item(name="file", id="file"),#, editor=FileEditor(entries=6)), # id="graph_view_model.file_view", title="Select a file", # icon=frame_icon, resizable=True, width=.3, kind="livemodal", # buttons=OKCancelButtons # ) # Graph selection view. all_graphs_view = View( Item(name = "selected_graph", editor = InstanceEditor( name = "all_graphs", editable = False), label = "Graph"), Item("select_graph", label="Always ask?"), icon = frame_icon, kind = "livemodal", title = "Select a graph", buttons = OKCancelButtons, close_result = False ) # Model view options view. options_view = View( Item("prompt_on_exit"), "_", Item("select_graph"), Item("selected_graph", enabled_when = "not select_graph", editor = InstanceEditor( name = "all_graphs", editable = False ), label = "Graph" ), icon = frame_icon, kind = "livemodal", title = "Options", buttons = OKCancelButtons, close_result = True ) # Text representation of the graph viewed in a text editor dot_code_view = View( Item("dot_code", show_label=False, style="custom"), Item("parse_dot_code", show_label=False), id="godot.view_model.dot_code", icon = frame_icon, kind = "livemodal", title = "Dot Code", resizable = True, buttons = [], height = .3, width = .3 ) #-------------------------------------------------------------------------- # Trait intialisers: #-------------------------------------------------------------------------- def _selected_graph_default(self): """ Trait intialiser. """ return self.model def _parse_dot_code_fired(self): """ Parses the dot_code string and replaces the existing model. """ parser = GodotDataParser() graph = parser.parse_dot_data(self.dot_code) if graph is not None: self.model = graph #-------------------------------------------------------------------------- # Event handlers: #-------------------------------------------------------------------------- def _model_changed(self, old, new): """ Handles the model changing. """ self.selected_graph = new #-------------------------------------------------------------------------- # Action handlers: #-------------------------------------------------------------------------- def new_model(self, info): """ Handles the new Graph action. """ if info.initialized: retval = confirm(parent = info.ui.control, message = "Replace existing graph?", title = "New Graph", default = YES) if retval == YES: self.model = Graph() def open_file(self, info): """ Handles the open action. """ if not info.initialized: return # Escape. # retval = self.edit_traits(parent=info.ui.control, view="file_view") dlg = FileDialog( action = "open", wildcard = "Graphviz Files (*.dot, *.xdot, *.txt)|" "*.dot;*.xdot;*.txt|Dot Files (*.dot)|*.dot|" "All Files (*.*)|*.*|") if dlg.open() == OK: parser = GodotDataParser() model = parser.parse_dot_file(dlg.path) if model is not None: self.model = model else: print "error parsing: %s" % dlg.path self.save_file = dlg.path del dlg # fd = None # try: # fd = open(self.file, "rb") # parser = DotParser() # self.model = parser.parse_dot_file(self.file) ## except: ## error(parent=info.ui.control, title="Load Error", ## message="An error was encountered when loading\nfrom %s" ## % self.file) # finally: # if fd is not None: # fd.close() def save(self, info): """ Handles saving the current model to the last file. """ save_file = self.save_file if not isfile(save_file): self.save_as(info) else: fd = None try: fd = open(save_file, "wb") dot_code = str(self.model) fd.write(dot_code) finally: if fd is not None: fd.close() def save_as(self, info): """ Handles saving the current model to file. """ if not info.initialized: return # retval = self.edit_traits(parent=info.ui.control, view="file_view") dlg = FileDialog( action = "save as", wildcard = "Graphviz Files (*.dot, *.xdot, *.txt)|" \ "*.dot;*.xdot;*.txt|Dot Files (*.dot)|*.dot|" \ "All Files (*.*)|*.*|") if dlg.open() == OK: fd = None try: fd = open(dlg.path, "wb") dot_code = str(self.model) fd.write(dot_code) self.save_file = dlg.path except: error(parent=info.ui.control, title="Save Error", message="An error was encountered when saving\nto %s" % self.file) finally: if fd is not None: fd.close() del dlg def configure_graph(self, info): """ Handles display of the graph dot traits. """ if info.initialized: self.model.edit_traits(parent=info.ui.control, kind="live", view=attr_view) def configure_nodes(self, info): """ Handles display of the nodes editor. """ if info.initialized: self.model.edit_traits(parent=info.ui.control, kind="live", view=nodes_view) def configure_edges(self, info): """ Handles display of the edges editor. """ if info.initialized: self.model.edit_traits(parent=info.ui.control, kind="live", view=edges_view) def about_godot(self, info): """ Handles displaying a view about Godot. """ if info.initialized: self.edit_traits(parent=info.ui.control, kind="livemodal", view=about_view) def add_node(self, info): """ Handles adding a Node to the graph. """ if not info.initialized: return graph = self._request_graph(info.ui.control) if graph is None: return IDs = [v.ID for v in graph.nodes] node = Node(ID=make_unique_name("node", IDs)) graph.nodes.append(node) retval = node.edit_traits(parent=info.ui.control, kind="livemodal") if not retval.result: graph.nodes.remove(node) def add_edge(self, info): """ Handles adding an Edge to the graph. """ if not info.initialized: return graph = self._request_graph(info.ui.control) if graph is None: return n_nodes = len(graph.nodes) IDs = [v.ID for v in graph.nodes] if n_nodes == 0: tail_node = Node(ID=make_unique_name("node", IDs)) head_name = make_unique_name("node", IDs + [tail_node.ID]) head_node = Node(ID=head_name) elif n_nodes == 1: tail_node = graph.nodes[0] head_node = Node(ID=make_unique_name("node", IDs)) else: tail_node = graph.nodes[0] head_node = graph.nodes[1] edge = Edge(tail_node, head_node, _nodes=graph.nodes) retval = edge.edit_traits(parent=info.ui.control, kind="livemodal") if retval.result: graph.edges.append(edge) def add_subgraph(self, info): """ Handles adding a Subgraph to the main graph. """ if not info.initialized: return graph = self._request_graph(info.ui.control) if graph is not None: subgraph = Subgraph()#root=graph, parent=graph) retval = subgraph.edit_traits(parent = info.ui.control, kind = "livemodal") if retval.result: graph.subgraphs.append(subgraph) def add_cluster(self, info): """ Handles adding a Cluster to the main graph. """ if not info.initialized: return graph = self._request_graph(info.ui.control) if graph is not None: cluster = Cluster()#root=graph, parent=graph) retval = cluster.edit_traits(parent = info.ui.control, kind = "livemodal") if retval.result: graph.clusters.append(cluster) def _request_graph(self, parent=None): """ Displays a dialog for graph selection if more than one exists. Returns None if the dialog is canceled. """ if (len(self.all_graphs) > 1) and (self.select_graph): retval = self.edit_traits(parent = parent, view = "all_graphs_view") if not retval.result: return None if self.selected_graph is not None: return self.selected_graph else: return self.model def toggle_tree(self, info): """ Handles displaying the tree view """ if info.initialized: self.show_tree = not self.show_tree def godot_options(self, info): """ Handles display of the options menu. """ if info.initialized: self.edit_traits( parent = info.ui.control, kind = "livemodal", view = "options_view" ) def configure_dot_code(self, info): """ Handles display of the dot code in a text editor. """ if not info.initialized: return self.dot_code = str(self.model) retval = self.edit_traits( parent = info.ui.control, kind = "livemodal", view = "dot_code_view" ) # if retval.result: # parser = DotParser() # graph = parser.parse_dot_data(self.dot_code) # if graph is not None: # self.model = graph #--------------------------------------------------------------------------- # Handle the user attempting to exit Godot: #--------------------------------------------------------------------------- def on_exit(self, info): """ Handles the user attempting to exit Godot. """ if self.prompt_on_exit:# and (not is_ok): retval = confirm(parent = info.ui.control, message = "Exit Godot?", title = "Confirm exit", default = YES) if retval == YES: self._on_close( info ) else: self._on_close( info )