def traits_view(self): """ Returns the default traits view for the object's class. """ return View( VGroup(HGroup( VGroup(Label('Content', LabelTheme), Item('content', editor=margin_editor), show_labels=False), VGroup(Label('Label', LabelTheme), Item('label', editor=margin_editor), show_labels=False), VGroup(Label('Border', LabelTheme), Item('border', editor=margin_editor), show_labels=False)), HGroup(spring, Item('editor.mode'), '30', Item('alignment', style='custom'), spring, group_theme=Theme('@std:GL5', content=(0, 0, -7, -4))), Item('editor.items', show_label=False, height=270, editor=ListCanvasEditor( theme='@std:GL5', adapter=ThemeEditorAdapter(editor=self), scrollable=True, operations=['size'])), group_theme='@std:XG0'), kind='subpanel', )
class _MarginEditor(UIEditor): """ A custom editor for Margin/Border instances. """ # Mark the editor as being resizable: scrollable = True #-- Traits View Definitions ------------------------------------------------ view = View(VGroup(Item('left', editor=slider_editor), Item('right', editor=slider_editor), Item('top', editor=slider_editor), Item('bottom', editor=slider_editor), group_theme='@std:GL5', item_theme=Theme('@std:GreyItemInset', content=(-6, -6, -7, -2)), label_theme=Theme('@std:BlueLabelInset', content=(-6, -4, -7, 0), label=(-3, 8))), kind='subpanel')
class ThemedVerticalNotebook(HasPrivateTraits): """ Defines a ThemedVerticalNotebook class for displaying a series of pages organized vertically, as opposed to horizontally like a standard notebook. """ #-- Public Traits ---------------------------------------------------------- # The theme to use for 'closed' notebook pages: closed_theme = ATheme(Theme('@std:notebook_close', content=0)) # The theme to use for 'open' notebook pages: open_theme = ATheme(Theme('@std:notebook_open', content=0)) # Allow multiple open pages at once? multiple_open = Bool(False) # Should the notebook be scrollable? scrollable = Bool(False) # Use double clicks (True) or single clicks (False) to open/close pages: double_click = Bool(False) # The pages contained in the notebook: pages = List(ThemedPage) # The traits UI editor this notebook is associated with (if any): editor = Instance(Editor) #-- Private Traits --------------------------------------------------------- # The wxPython control used to represent the notebook: control = Instance(wx.Window) #-- Public Methods --------------------------------------------------------- def create_control(self, parent): """ Creates the underlying wxPython window used for the notebook. """ # Create the correct type of window based on whether or not it should # be scrollable: if self.scrollable: self.control = control = TraitsUIScrolledPanel(parent) control.SetScrollRate(6, 6) control.SetSize(wx.Size(0, 0)) else: self.control = control = TraitsUIPanel(parent, -1) control._image_slice = getattr(parent, '_image_slice', None) control.SetSizer(ThemedVerticalNotebookSizer(self)) # Set up the painting event handlers: control.Bind(wx.EVT_ERASE_BACKGROUND, self._erase_background) control.Bind(wx.EVT_PAINT, self._paint) return control def create_page(self): """ Creates a new **ThemedPage** object representing a notebook page and returns it as the result. """ return ThemedPage(notebook=self).set(closed_theme=self.closed_theme, open_theme=self.open_theme) def open(self, page): """ Handles opening a specified **ThemedPage** notebook page. """ if (page is not None) and (not page.is_open): if not self.multiple_open: for a_page in self.pages: a_page.is_open = False page.is_open = True self._refresh() def close(self, page): """ Handles closing a specified **ThemedPage** notebook page. """ if (page is not None) and page.is_open: page.is_open = False self._refresh() #-- Trait Event Handlers --------------------------------------------------- def _pages_changed(self, old, new): """ Handles the notebook's pages being changed. """ for page in old: page.close() self._refresh() def _pages_items_changed(self, event): """ Handles some of the notebook's pages being changed. """ for page in event.removed: page.close() self._refresh() def _multiple_open_changed(self, multiple_open): """ Handles the 'multiple_open' flag being changed. """ if not multiple_open: first = True for page in self.pages: if first and page.is_open: first = False else: page.is_open = False self._refresh() #-- wx.Python Event Handlers ----------------------------------------------- def _erase_background(self, event): """ Do not erase the background here (do it in the 'on_paint' handler). """ pass def _paint(self, event): """ Paint the background using the associated ImageSlice object. """ paint_parent(wx.PaintDC(self.control), self.control) #-- Private Methods -------------------------------------------------------- def _refresh(self): """ Refresh the layout and contents of the notebook. """ control = self.control if control is not None: # Set the virtual size of the canvas (so scroll bars work right): sizer = control.GetSizer() if control.GetSize().Get()[0] == 0: control.SetSize(sizer.CalcInit()) control.SetVirtualSize(sizer.CalcMin()) control.Layout() control.Refresh()
class ScatterPlot2(Template): #-- Template Traits -------------------------------------------------------- # The title of the plot: title = TStr('Dual Scatter Plots') # The type of marker to use. This is a mapped trait using strings as the # keys: marker = marker_trait(template='copy', event='update') # The pixel size of the marker (doesn't include the thickness of the # outline): marker_size = TRange(1, 5, 1, event='update') # The thickness, in pixels, of the outline to draw around the marker. If # this is 0, no outline will be drawn. line_width = TRange(0.0, 5.0, 1.0) # The fill color of the marker: color = TColor('red', event='update') # The color of the outline to draw around the marker outline_color = TColor('black', event='update') # The amount of space between plots: spacing = TRange(0.0, 20.0, 0.0) # The contained scatter plots: scatter_plot_1 = TInstance(ScatterPlot, ()) scatter_plot_2 = TInstance(ScatterPlot, ()) #-- Derived Traits --------------------------------------------------------- plot = TDerived #-- Traits UI Views -------------------------------------------------------- # The scatter plot view: template_view = View(VGroup( Item('title', show_label=False, style='readonly', editor=ThemedTextEditor(theme=Theme('@GBB', alignment='center'))), Item('plot', show_label=False, resizable=True, editor=EnableEditor(), item_theme=Theme('@GF5', margins=0))), resizable=True) # The scatter plot options view: options_view = View( VGroup( VGroup(Label('Scatter Plot Options', item_theme=Theme('@GBB', alignment='center')), show_labels=False), VGroup(Item('title', editor=TextEditor()), Item('marker'), Item('marker_size', editor=ThemedSliderEditor()), Item('line_width', label='Line Width', editor=ThemedSliderEditor()), Item('spacing', editor=ThemedSliderEditor()), Item('color', label='Fill Color'), Item('outline_color', label='Outline Color'), group_theme=Theme('@GF5', margins=(-5, -1)), item_theme=Theme('@G0B', margins=0)))) #-- ITemplate Interface Implementation ------------------------------------- def activate_template(self): """ Converts all contained 'TDerived' objects to real objects using the template traits of the object. This method must be overridden in subclasses. Returns ------- None """ plots = [ p for p in [self.scatter_plot_1.plot, self.scatter_plot_2.plot] if p is not None ] if len(plots) == 2: self.plot = HPlotContainer(spacing=self.spacing) self.plot.add(*plots) elif len(plots) == 1: self.plot = plots[0] #-- Default Values --------------------------------------------------------- def _scatter_plot_1_default(self): """ Returns the default value for the first scatter plot. """ result = ScatterPlot() result.index.description = 'Shared Plot Index' result.value.description += ' 1' return result def _scatter_plot_2_default(self): """ Returns the default value for the second scatter plot. """ result = ScatterPlot(index=self.scatter_plot_1.index) result.value.description += ' 2' result.value.optional = True return result #-- Trait Event Handlers --------------------------------------------------- def _update_changed(self, name, old, new): """ Handles a plot option being changed. """ setattr(self.scatter_plot_1, name, new) setattr(self.scatter_plot_2, name, new) self.plot = Undefined def _spacing_changed(self, spacing): """ Handles the spacing between plots being changed. """ self.plot = Undefined
class ScatterPlot ( Template ): #-- Template Traits -------------------------------------------------------- # The plot index data source: index = TDataSource # The plot value data source: value = TDataSource # The title of the plot: title = TStr( 'Scatter Plot' ) # The type of marker to use. This is a mapped trait using strings as the # keys: marker = marker_trait( template = 'copy', event = 'update' ) # The pixel size of the marker (doesn't include the thickness of the # outline): marker_size = TRange( 1, 5, 1, event = 'update' ) # The thickness, in pixels, of the outline to draw around the marker. If # this is 0, no outline will be drawn. line_width = TRange( 0.0, 5.0, 1.0 ) # The fill color of the marker: color = TColor( 'red', event = 'update' ) # The color of the outline to draw around the marker outline_color = TColor( 'black', event = 'update' ) #-- Derived Traits --------------------------------------------------------- plot = TDerived # Instance( ScatterPlot ) #-- Traits UI Views -------------------------------------------------------- # The scatter plot view: template_view = View( VGroup( Item( 'title', show_label = False, style = 'readonly', editor = ThemedTextEditor( theme = Theme( '@GBB', alignment = 'center' ) ) ), Item( 'plot', show_label = False, resizable = True, editor = EnableEditor(), item_theme = Theme( '@GF5', margins = 0 ) ) ), resizable = True ) # The scatter plot options view: options_view = View( VGroup( VGroup( Label( 'Scatter Plot Options', item_theme = Theme( '@GBB', alignment = 'center' ) ), show_labels = False ), VGroup( Item( 'title', editor = TextEditor() ), Item( 'marker' ), Item( 'marker_size', editor = ThemedSliderEditor() ), Item( 'line_width', label = 'Line Width', editor = ThemedSliderEditor() ), Item( 'color', label = 'Fill Color' ), Item( 'outline_color', label = 'Outline Color' ), group_theme = Theme( '@GF5', margins = ( -5, -1 ) ), item_theme = Theme( '@G0B', margins = 0 ) ) ) ) #-- Default Values --------------------------------------------------------- def _index_default ( self ): """ Returns the default value for the 'index' trait. """ return TemplateDataSource( items = [ ValueDataNameItem( name = 'index', flatten = True ) ], description = 'Scatter Plot Index' ) def _value_default ( self ): """ Returns the default value for the 'value' trait. """ return TemplateDataSource( items = [ ValueDataNameItem( name = 'value', flatten = True ) ], description = 'Scatter Plot Value' ) #-- ITemplate Interface Implementation ------------------------------------- def activate_template ( self ): """ Converts all contained 'TDerived' objects to real objects using the template traits of the object. This method must be overridden in subclasses. Returns ------- None """ # If our data sources are still unbound, then just exit; someone must # have marked them as optional: if ((self.index.context_data is Undefined) or (self.value.context_data is Undefined)): return # Create a plot data object and give it this data: pd = ArrayPlotData() pd.set_data( 'index', self.index.context_data ) pd.set_data( 'value', self.value.context_data ) # Create the plot: self.plot = plot = Plot( pd ) plot.plot( ( 'index', 'value' ), type = 'scatter', index_sort = 'ascending', marker = self.marker, color = self.color, outline_color = self.outline_color, marker_size = self.marker_size, line_width = self.line_width, bgcolor = 'white' ) plot.trait_set( padding_left = 50, padding_right = 0, padding_top = 0, padding_bottom = 20 ) # Attach some tools to the plot: plot.tools.append( PanTool( plot, constrain_key = 'shift' ) ) zoom = SimpleZoom( component = plot, tool_mode = 'box', always_on = False ) plot.overlays.append( zoom ) #-- Trait Event Handlers --------------------------------------------------- def _update_changed ( self ): """ Handles a plot option being changed. """ self.plot = Undefined
class TemplateView ( HasPrivateTraits ): """ A feature-based Traits UI plug-in for viewing templates. """ #-- Public Traits ---------------------------------------------------------- # The name of the plugin: name = Str( 'Template View' ) # The data context supplying the data to be viewed: context = Instance( ITemplateDataContext, connect = 'to: data context' ) # The name of the file containing a template view: file_name = File( drop_file = DropFile( extensions = [ '.py', '.tv', '.las' ], tooltip = 'Drop a LAS data file, a saved view template ' 'or a Python source file containing a view ' 'template here.' ), connect = 'to: template view' ) # The template to view: template = Instance( ITemplate ) #-- Private Traits --------------------------------------------------------- # The name of the file to save the template in: save_file_name = File # The current data names: data_names = Instance( TemplateDataNames ) # The TemplateDataNames or Message being viewed: names_view = Any( no_context ) # The name of the most recently loaded template file: template_file_name = File # The template or message being viewed: template_view = Any( no_template ) # The options view for the currently active template: options_view = Any( no_options ) # The event fired when the user wants to save the template: save_template = Button( 'Save Template' ) #-- Traits View Definitions ------------------------------------------------ view = View( VGroup( HGroup( Item( 'file_name', show_label = False, width = 350 ), TButton( 'save_template', label = 'Save Template', enabled_when = 'template is not None' ), group_theme = Theme( '@GFB', margins = ( -7, -5 ) ) ), Tabbed( VGroup( '8', Label( 'Data Bindings', item_theme = Theme( '@GBB', alignment = 'center' ) ), Item( 'names_view', style = 'custom', resizable = True, editor = InstanceEditor(), export = 'DockWindowShell', item_theme = Theme( '@GFB', margins = ( -5, -1 ) ) ), label = 'Data Bindings', show_labels = False ), Item( 'template_view', label = 'Template View', style = 'custom', resizable = True, editor = InstanceEditor( view = 'template_view' ), export = 'DockWindowShell' ), Item( 'options_view', label = 'Template Options', style = 'custom', resizable = True, editor = InstanceEditor( view = 'options_view' ), export = 'DockWindowShell' ), id = 'tabbed', dock = 'horizontal', show_labels = False ), ), id = 'template.test.template_view.TemplateView' ) #-- Trait Event Handlers --------------------------------------------------- def _context_changed ( self, context ): """ Handles the 'context' trait being changed. """ if context is None: self.names_view = no_context elif self.template is None: self.names_view = no_template else: self._create_view() def _template_changed ( self, template ): """ Handles the 'template' trait being changed. """ if self.context is None: self.template_view = no_context else: self._create_view() def _file_name_changed ( self, file_name ): """ Handles the 'file_name' trait being changed. """ ext = splitext( file_name )[1] if ext == '.py': self._load_python_template( file_name ) elif ext == '.tv': self._load_pickled_template( file_name ) elif ext == '.las': self._load_las_file( file_name ) else: # fixme: Display an informational message here... pass def _save_template_changed ( self ): """ Handles the user clicking the 'Save Template' button. """ self._save_pickled_template() @on_trait_change( 'data_names.unresolved_data_names' ) def _on_unresolved_data_names ( self ): if len( self.data_names.unresolved_data_names ) == 0: self._create_object_view() elif not isinstance( self.template_view, Message ): self.template_view = no_bindings self.options_view = no_options @on_trait_change( 'template.template_mutated?' ) def _on_template_mutated ( self ): """ Handles a mutable template changing. """ if self.context is not None: self._create_view() #-- Private Methods -------------------------------------------------------- def _load_python_template ( self, file_name ): """ Attempts to load a template from a Python source file. """ path, name = split( file_name ) sys.path[0:0] = [ path ] try: ###values = {} module_name, ext = splitext( name ) module = __import__( module_name ) values = module.__dict__ ###execfile( file_name, values ) template = values.get( 'template' ) if template is None: templates = [] for value in values.values(): try: if (issubclass( value, Template ) and ###(value.__module__ == '__builtin__')): (value.__module__ == module_name)): templates.append( value ) except: pass for i, template in enumerate( templates ): for t in templates[ i + 1: ]: if issubclass( template, t ): break else: break else: self.template_view = no_template_found return if not isinstance( template, Template ): template = template() self.template = template self.template_file_name = file_name except Exception as excp: self.template_view = Message( str( excp ) ) # Clean up the Python path: del sys.path[0] def _load_pickled_template ( self, file_name ): """ Attempts to load a template from a pickle. """ # fixme: Implement this...load template from .tv pickle file. fh = None delete = False try: fh = open( file_name, 'rb' ) file_name = load( fh ) path, name = split( file_name ) sys.path[0:0] = [ path ] delete = True module_name, ext = splitext( name ) module = __import__( module_name ) self.template = load( fh ) self.template_file_name = file_name except Exception as excp: import traceback traceback.print_exc() self.template_view = Message( str( excp ) ) if fh is not None: fh.close() if delete: del sys.path[0] def _load_las_file ( self, file_name ): """ Creates a data context from the specified LAS file. """ try: self.context = import_log_files( file_name, 'las' ) except Exception as excp: self.names_view = Message( str( excp ) ) def _save_pickled_template ( self ): file_name = self.save_file_name or self.file_name fd = FileDialog( action = 'save as', default_path = file_name ) #wildcard = 'Template files (*.tv)|*.tv|' ) if fd.open() == OK: self.save_file_name = file_name = fd.path fh = None try: fh = open( file_name, 'wb' ) dump( self.template_file_name, fh, -1 ) dump( self.template.template_from_object(), fh, -1 ) except: # fixme: Display an informational message here... import traceback traceback.print_exc() if fh is not None: fh.close() def _create_view ( self ): """ Begins the process of creating a live view from a template and data context object. """ self.data_names = self.names_view = nv = TemplateDataNames( context = self.context, data_names = self.template.names_from_template() ) if len( nv.unresolved_data_names ) == 0: self._create_object_view() else: self.template_view = no_bindings def _create_object_view ( self ): """ Create the object view from the current template. """ self.template.object_from_template() self.template_view = self.options_view = self.template
class ScatterPlotNM(MutableTemplate): #-- Template Traits -------------------------------------------------------- # The title of the plot: title = TStr('NxM Scatter Plots') # The type of marker to use. This is a mapped trait using strings as the # keys: marker = marker_trait(template='copy', event='update') # The pixel size of the marker (doesn't include the thickness of the # outline): marker_size = TRange(1, 5, 1, event='update') # The thickness, in pixels, of the outline to draw around the marker. If # this is 0, no outline will be drawn. line_width = TRange(0.0, 5.0, 1.0) # The fill color of the marker: color = TColor('red', event='update') # The color of the outline to draw around the marker outline_color = TColor('black', event='update') # The number of rows of plots: rows = TRange(1, 3, 1, event='grid') # The number of columns of plots: columns = TRange(1, 5, 1, event='grid') # The contained scatter plots: scatter_plots = TList(ScatterPlot) #-- Derived Traits --------------------------------------------------------- plot = TDerived #-- Traits UI Views -------------------------------------------------------- # The scatter plot view: template_view = View( VGroup( Item( 'title', show_label=False, style='readonly', editor=ThemedTextEditor(theme=Theme( '@GBB', alignment='center'))), Item( 'plot', show_label=False, resizable=True, editor=EnableEditor(), item_theme=Theme( '@GF5', margins=0))), resizable=True) # The scatter plot options view: options_view = View( VGroup( VGroup( Label( 'Scatter Plot Options', item_theme=Theme( '@GBB', alignment='center')), show_labels=False), VGroup( Item( 'title', editor=TextEditor()), Item('marker'), Item( 'marker_size', editor=ThemedSliderEditor()), Item( 'line_width', label='Line Width', editor=ThemedSliderEditor()), Item( 'color', label='Fill Color'), Item( 'outline_color', label='Outline Color'), Item( 'rows', editor=ThemedSliderEditor()), Item( 'columns', editor=ThemedSliderEditor()), group_theme=Theme( '@GF5', margins=(-5, -1)), item_theme=Theme( '@G0B', margins=0)))) #-- ITemplate Interface Implementation ------------------------------------- def activate_template(self): """ Converts all contained 'TDerived' objects to real objects using the template traits of the object. This method must be overridden in subclasses. Returns ------- None """ plots = [] i = 0 for r in range(self.rows): row = [] for c in range(self.columns): plot = self.scatter_plots[i].plot if plot is None: plot = PlotComponent() row.append(plot) i += 1 plots.append(row) self.plot = GridPlotContainer(shape=(self.rows, self.columns)) self.plot.component_grid = plots #-- Default Values --------------------------------------------------------- def _scatter_plots_default(self): """ Returns the default value for the scatter plots list. """ plots = [] for i in range(self.rows * self.columns): plots.append(ScatterPlot()) self._update_plots(plots) return plots #-- Trait Event Handlers --------------------------------------------------- def _update_changed(self, name, old, new): """ Handles a plot option being changed. """ for sp in self.scatter_plots: setattr(sp, name, new) self.plot = Undefined def _grid_changed(self): """ Handles the grid size being changed. """ n = self.rows * self.columns plots = self.scatter_plots if n < len(plots): self.scatter_plots = plots[:n] else: for j in range(len(plots), n): plots.append(ScatterPlot()) self._update_plots(plots) self.template_mutated = True #-- Private Methods -------------------------------------------------------- def _update_plots(self, plots): """ Update the data sources for all of the current plots. """ index = None i = 0 for r in range(self.rows): for c in range(self.columns): sp = plots[i] i += 1 desc = sp.value.description col = desc.rfind('[') if col >= 0: desc = desc[:col] sp.value.description = '%s[%d,%d]' % (desc, r, c) sp.value.optional = True if index is None: index = sp.index index.description = 'Shared Plot Index' index.optional = True else: sp.index = index
class LibraryManager(HasPrivateTraits): # The list of image volumes currently being managed: volumes = List(VolumeManager) #-- Traits View Defnitions ------------------------------------------------- view = View( Item('volumes', show_label=False, editor=ThemedVerticalNotebookEditor(closed_theme=Theme( '@std:GL5', content=(0, 0, -2, 0), alignment='center'), open_theme='@std:GL5TB', multiple_open=True, scrollable=True, double_click=False, page_name='.name'), item_theme='@std:XG1')) #-- Public Methods --------------------------------------------------------- def add(self, image): """ Adds a specified *image* **ImageInfo** object to the library manager's collection. """ vm = self._find(image) if not isinstance(vm, VolumeManager): vm = VolumeManager(volume=vm) self.volumes.append(vm) vm.add(image) def remove(self, image): """ Removes a reference to a specified *image* **ImageInfo** object from the library manager's collection. """ vm = self._find(image) if isinstance(vm, VolumeManager): vm.remove(image) #-- Traits Event Handlers -------------------------------------------------- @on_trait_change('volumes:is_empty') def _volume_empty(self, volume, name, old, empty): """ Handles a VolumeManager becoming empty. """ if empty: self.volumes.remove(volume) #-- Private Methods -------------------------------------------------------- def _find(self, image): """ Attempts to return the **ImageVolume** object corresponding to a specified *image **ImageInfo** object. """ volume = ImageLibrary.find_volume(image.image_name) for vm in self.volumes: if volume is vm.volume: return vm return volume
from traitsui.api \ import Item, Theme, TitleEditor, ButtonEditor #------------------------------------------------------------------------------- # Themes: #------------------------------------------------------------------------------- # An item that displays the tool title or information: class TTitle ( Item ): show_label = Constant( False ) editor = TitleEditor() # A standard themed button: class TButton ( Item ): show_label = Constant( False ) editor = Instance( ButtonEditor, () ) image = Delegate( 'editor', modify = True ) # A label theme: LabelTheme = Theme( '@std:GL5', label = ( -3, 10 ), content = ( 0, -5 ), alignment = 'center' ) # An inset label theme: InsetTheme = Theme( '@std:inset_grey', content = -6, label = ( 6, 6, 9, 0 ), alignment = 'center', )