def test_fit_components(self): container = VPlotContainer(bounds=[200,300], resizable="v", fit_components="v") comp1 = StaticPlotComponent([50,100], padding=5) comp2 = StaticPlotComponent([50,120], padding=5) container.add(comp1) container.add(comp2) self.assert_tuple(container.get_preferred_size(), (200,240)) # The container should not change its size as a result of its fit_components # being set. self.assert_tuple(container.bounds, (200,300)) container.bounds = container.get_preferred_size() container.do_layout() container.padding = 8 self.assert_tuple(container.get_preferred_size(), (216,256)) container.do_layout() self.assert_tuple(comp1.outer_position, (0,0)) self.assert_tuple(comp2.outer_position, (0,110))
def test_fit_components(self): container = VPlotContainer(bounds=[200, 300], resizable="v", fit_components="v") comp1 = StaticPlotComponent([50, 100], padding=5) comp2 = StaticPlotComponent([50, 120], padding=5) container.add(comp1) container.add(comp2) self.assert_tuple(container.get_preferred_size(), (200, 240)) # The container should not change its size as a result of its fit_components # being set. self.assert_tuple(container.bounds, (200, 300)) container.bounds = container.get_preferred_size() container.do_layout() container.padding = 8 self.assert_tuple(container.get_preferred_size(), (216, 256)) container.do_layout() self.assert_tuple(comp1.outer_position, (0, 0)) self.assert_tuple(comp2.outer_position, (0, 110))
def test_stack_nonresize(self): container = VPlotContainer(bounds=[100,300]) comp1 = StaticPlotComponent([70,100]) comp2 = StaticPlotComponent([80,90]) comp3 = StaticPlotComponent([90,80]) container.add(comp1, comp2, comp3) container.do_layout() self.assert_tuple(container.get_preferred_size(), (90, 270)) self.assert_tuple(container.bounds, (100,300)) self.assert_tuple(comp1.position, (0,0)) self.assert_tuple(comp2.position, (0,100)) self.assert_tuple(comp3.position, (0,190)) return
def test_stack_nonresize(self): container = VPlotContainer(bounds=[100, 300]) comp1 = StaticPlotComponent([70, 100]) comp2 = StaticPlotComponent([80, 90]) comp3 = StaticPlotComponent([90, 80]) container.add(comp1, comp2, comp3) container.do_layout() self.assert_tuple(container.get_preferred_size(), (90, 270)) self.assert_tuple(container.bounds, (100, 300)) self.assert_tuple(comp1.position, (0, 0)) self.assert_tuple(comp2.position, (0, 100)) self.assert_tuple(comp3.position, (0, 190)) return
def test_stack_one_resize(self): "Checks stacking with 1 resizable component thrown in" container = VPlotContainer(bounds=[100,300]) comp1 = StaticPlotComponent([70,100]) comp2 = StaticPlotComponent([80,90]) comp3 = StaticPlotComponent([90,80], resizable='hv') comp4 = StaticPlotComponent([50,40]) container.add(comp1, comp2, comp3, comp4) container.do_layout() self.assert_tuple(container.get_preferred_size(), (80,230)) self.assert_tuple(container.bounds, (100,300)) self.assert_tuple(comp1.position, (0,0)) self.assert_tuple(comp2.position, (0,100)) self.assert_tuple(comp3.position, (0,190)) self.assert_tuple(comp4.position, (0,260)) return
def test_stack_one_resize(self): "Checks stacking with 1 resizable component thrown in" container = VPlotContainer(bounds=[100, 300]) comp1 = StaticPlotComponent([70, 100]) comp2 = StaticPlotComponent([80, 90]) comp3 = StaticPlotComponent([90, 80], resizable='hv') comp4 = StaticPlotComponent([50, 40]) container.add(comp1, comp2, comp3, comp4) container.do_layout() self.assert_tuple(container.get_preferred_size(), (80, 230)) self.assert_tuple(container.bounds, (100, 300)) self.assert_tuple(comp1.position, (0, 0)) self.assert_tuple(comp2.position, (0, 100)) self.assert_tuple(comp3.position, (0, 190)) self.assert_tuple(comp4.position, (0, 260)) return
class UserInterface(HasTraits): '''UserInterface Class GUI for SrXes. Uses traits to watch for user interaction and then adds jobs to a queue for processing. ''' def __init__(self, **kwargs): '''Constructor for UserInterface object Adds panels and plots to a userinterface window. ''' super(UserInterface, self).__init__() self.add_trait('rawviewer', RawViewer()) self.add_trait('cpanel', ControlPanel()) self.add_trait('mdpanel', MetadataPanel()) self.add_trait('messagelog', MessageLog()) self.rawviewer.startProcessJob() self.cpanel.sync_trait('datalistlength', self.rawviewer) self.imagepanel = Instance(Component) self.createImagePanel() self.rrpanel = Instance(Component) self.rrpanel = VPlotContainer(stack_order = 'top_to_bottom', resizeable='', use_backbuffer=True, bgcolor='transparent') self.rrpanel.get_preferred_size() # TODO: Adjust view view = View( HSplit( VSplit( UItem('imagepanel', editor=ComponentEditor(), padding=0), UItem('mdpanel', style="custom", padding=5, height=85, width=700) ), VGroup( UItem('cpanel', style="custom", width=-430, padding=10), UItem('messagelog', style ="custom", width=-430, padding =10), UItem('rrpanel', editor=ComponentEditor(), style='custom') ), show_labels=False, ), resizable = True, height = 0.96, width = 1.0, handler = PyXDAHandler(), buttons = NoButtons, title = 'SrXes', icon = LOGO) ############################# # UI Action Handling ############################# @on_trait_change('cpanel.left_arrow', post_init=True) def _left_arrow_fired(self): '''Left arrow has been pushed Changes the image display to the left one over if it exists. ''' self.rawviewer.jobqueue.put(['updatecache', ['left']]) return @on_trait_change('cpanel.right_arrow', post_init=True) def _right_arrow_fired(self): '''Right arrow has been pushed Changes the image display to the right one over if it exists. ''' self.rawviewer.jobqueue.put(['updatecache', ['right']]) return @on_trait_change('cpanel.generate', post_init=True) def _generate_fired(self): '''Generate Intensity button has been pushed Creates a reduced representation plot in the GUI. ''' self.rawviewer.jobqueue.put(['plotrr', [self.cpanel.rrchoice]]) time.sleep(0.5) self.updateRRPanel(self.cpanel.rrchoice) return @on_trait_change('cpanel.dirpath', post_init=True) def _dirpath_changed(self): '''Directory path has changed If there are tiff images in the folder path, they will be loaded and the first image will be plotted to the screen. If there are no tiff images or the path is invalid, rawviewer.message will be changed to a string explaining the error. ''' self.rawviewer.jobqueue.put(['startload', [self.cpanel.dirpath]]) @on_trait_change('rawviewer.pic', post_init=True) def _pic_changed(self): '''The displayed 2D image has been changed Changes the control panel index, and the metadata associated with it. ''' pic = self.rawviewer.pic self.cpanel.index = pic.n + 1 self.mdpanel.name = pic.name if pic.metadata: for key in pic.metadata.keys(): setattr(self.mdpanel, key, pic.metadata[key]) return @on_trait_change('rawviewer.display.filename', post_init=True) def _filename_changed(self): '''The filename of the 2D image has changed Changes the displayed filename to the updated one. ''' print 'filename changed' if self.rawviewer.display.filename == -1: self.cpanel.filename = '' else: self.cpanel.filename = self.rawviewer.datalist[self.rawviewer.display.filename].name @on_trait_change('rawviewer.loadimage.message', post_init=True) def handleMessage(self): '''Rawviewer.message has changed Displays the new message in messagelog. If there is already a message inside messagelog, the new one is plotted below it. ''' if self.rawviewer.loadimage.message != '': if self.messagelog.line_pos == 0: self.messagelog.line1 = 'Out: ' + self.rawviewer.loadimage.message self.messagelog.line_pos = self.messagelog.line_pos +1 return if self.messagelog.line_pos == 1: self.messagelog.line2 = 'Out: ' + self.rawviewer.loadimage.message self.messagelog.line_pos = self.messagelog.line_pos + 1 return if self.messagelog.line_pos == 2: self.messagelog.line3 = 'Out: ' + self.rawviewer.loadimage.message self.messagelog.line_pos = 0 return return # TODO: Update def createImagePanel(self): '''Creates the Image Panel Creates the image panel that contains the 2D image, colorbarm histogram, and 1D slice. ''' cont = VPlotContainer(stack_order = 'top_to_bottom', bgcolor = 'transparent', use_backbuffer=True) imageplot = getattr(self.rawviewer, 'imageplot') colorbar = getattr(self.rawviewer.display, 'colorbar') histogram = getattr(self.rawviewer, 'histogram') plot1d = getattr(self.rawviewer, 'plot1d') imgcont = HPlotContainer(imageplot, colorbar, bgcolor = 'transparent', spacing = 20.0) cont.add(imgcont) cont.add(histogram) cont.add(plot1d) self.imagepanel = cont self.imagepanel.get_preferred_size() self.imagepanel.invalidate_draw() return def updateRRPanel(self, choice): '''Updates the Reduced Representation Panel Args: choice: the new variable for the RR. eg: mean, total intensity... ''' rrplots = getattr(self.rawviewer, 'rrplots') if rrplots[choice] not in self.rrpanel._components: self.rrpanel.add(rrplots[choice]) self.rrpanel.invalidate_and_redraw() return
class UserInterface(HasTraits): '''A user interface that handles interactions with the images/data. | control -- JobControl object that handles the internal functionality | cpanel -- contains tools to interact with the data, shown in upper right | mdpanel -- contains the metadata for the image, shown in lower left | imagepanel -- contains all of the image related plots, shown on left | rrpanel -- contains the RR plots that have been created, shown on right ''' def __init__(self, **kwargs): super(UserInterface, self).__init__() self.add_trait('process', ProcessCenter()) self.add_trait('cpanel', ControlPanel()) self.add_trait('mdpanel', MetadataPanel()) self.process.startProcessJob() self.cpanel.sync_trait('datalistlength', self.process) self.cpanel.sync_trait('message', self.process) self.imagepanel = Instance(Component) self.createImagePanel() self.rrpanel = Instance(Component) self.rrpanel = VPlotContainer(stack_order = 'top_to_bottom', resizeable='', use_backbuffer=True, bgcolor='transparent') self.rrpanel.get_preferred_size() return view = View( HSplit( VSplit( UItem('imagepanel', editor=ComponentEditor(), padding=0, height=0.825), UItem('mdpanel', style="custom", height=127, width=700, resizable=True), ), VGroup( UItem('cpanel', style="custom", width=-430, padding=10), UItem('rrpanel', editor=ComponentEditor(), style='custom') ), show_labels=False, ), resizable = True, height = 0.95*800, width = 1.0*1280, title = 'SrXes', icon = ICON ) ############################# # UI Action Handling ############################# @on_trait_change('cpanel.left_arrow', post_init=True) def _left_arrow_fired(self): '''Left arrow/key pressed. Sends request to load previous image.''' self.process.jobqueue.put(['updatecache', ['left']]) return @on_trait_change('cpanel.right_arrow', post_init=True) def _right_arrow_fired(self): '''Right arrow/key pressed. Sends request to load next image.''' self.process.jobqueue.put(['updatecache', ['right']]) return @on_trait_change('cpanel.generate', post_init=True) def _generate_fired(self): '''Generate pressed. Sends request to create specified RR plot.''' self.process.jobqueue.put(['plotrr', [self.cpanel.rrchoice]]) time.sleep(0.5) self.updateRRPanel(self.cpanel.rrchoice) return @on_trait_change('cpanel.dirpath', post_init=True) def _dirpath_changed(self): '''A directory has been chosen. Sends request to start load thread.''' self.process.jobqueue.put(['startload', [self.cpanel.dirpath]]) return @on_trait_change('process.pic', post_init=True) def _pic_changed(self): '''Updates the index and metadata when the current image changes.''' pic = self.process.pic self.cpanel.index = pic.n + 1 self.mdpanel.name = pic.name if pic.metadata: for key in pic.metadata.keys(): setattr(self.mdpanel, key, pic.metadata[key]) else: for key in self.mdpanel.editable_traits(): if key != 'name': setattr(self.mdpanel, key, '') self.imagepanel.invalidate_and_redraw() return @on_trait_change('process.display.filenum', post_init=True) def _filenum_changed(self): '''Handles interactions with the RR plots. When a point is hovered over, its filename is displayed in the control panel. ''' #print 'filenum changed' n = self.process.display.filenum if n == -1: self.cpanel.message = '' else: name = self.process.datalist[n].name self.cpanel.message = '%d: %s' % (n+1, name) return @on_trait_change('cpanel.colormap', post_init=True) def _colormap_changed(self): '''A new colormap has been selected. Sends request to update cmap.''' self.process.jobqueue.put(['updatecmap', [self.cpanel.colormap]]) return def createImagePanel(self): '''Creates the image panel and fills it with the associated plots. The plots included are the image plot, histogram, and 1D plot. Data can be set for these plots without changing the Plot objects. ''' cont = VPlotContainer(stack_order = 'top_to_bottom', bgcolor = 'transparent', use_backbuffer=True) imageplot = getattr(self.process, 'imageplot') colorbar = getattr(self.process.display, 'colorbar') histogram = getattr(self.process, 'histogram') plot1d = getattr(self.process, 'plot1d') imgcont = HPlotContainer(imageplot, colorbar, bgcolor = 'transparent', spacing = 20.0) cont.add(imgcont) cont.add(histogram) cont.add(plot1d) self.imagepanel = cont self.imagepanel.get_preferred_size() self.imagepanel.invalidate_draw() return def updateRRPanel(self, choice): '''Fills the rrpanel with new RR plots. choice -- the name of the RR to check for ''' rrplots = getattr(self.process, 'rrplots') try: if rrplots[choice] not in self.rrpanel._components: self.rrpanel.add(rrplots[choice]) except KeyError: return if len(self.rrpanel._components) > 3: self.rrpanel.remove(self.rrpanel._components[0]) self.rrpanel.invalidate_and_redraw() return