#! /usr/bin/env mpscript # import wxversion wxversion.ensureMinimal("2.8") import numpy import wx import wx.lib.filebrowsebutton import wx.lib.stattext import MpNum import MpWx import Image import time if 1: import MpCa # # Have we been requested to start a C debugger? # try: test = os.environ["MPAD_DEBUGGER"] Mp.c_wait_for_debugger() except: pass # # Create an object to hold attributes used by Mpad. # class _Mpad: pass _mpad = _Mpad() _mpad.mxdir = mxdir _mpad.callback_list = [] _mpad.gui_ready = False _mpad.fetch_image_frame = False # Do we want a Python command entry window? _mpad.debug_window = True # Do we want to display a log of the serial communication with the camera head? _mpad.debug_serial = True # # Are we running a test version of Mpad? # try: test = os.environ["MPADTEST"] test = int(test) if ( test == 0 ): _mpad.test = False else: _mpad.test = True except: _mpad.test = False if ( _mpad.test ): lib_dir = os.getcwd() etc_dir = os.getcwd() else: lib_dir = os.path.join( mxdir, "lib", "mpad" ) lib_dir = os.path.normpath( lib_dir ) # etc_dir = os.path.join( mxdir, "etc" ) # etc_dir = os.path.normpath( etc_dir ) etc_dir = lib_dir _mpad.lib_dir = lib_dir _mpad.etc_dir = etc_dir sys.path.append( lib_dir ) #--- import WxtImage #-------------------------------------------------------------------------- class MpadApp(wx.App): def OnInit( self ): # # _mpad.is_busy is used to remember whether the area detector # was busy the last time we checked, so we can compare it to # the current busy status. # _mpad.is_busy = False self.frame = MpadMainFrame() self.frame.Show() self.SetTopWindow( self.frame ) self.timer = MpadTimer( self ) _mpad.timer = self.timer self.timer.Start( 1000 ) return True #-------------------------------------------------------------------------- def main( record_list, args ): _mpad.record_list = record_list _mpad.record_list.set_program_name('mpad') # _mpad.record_list.set_network_debug(True) # # Find the area detector record. # if ( len(args) > 0 ): ad_name = args[0] _mpad.ad_record = _mpad.record_list.get_record( ad_name ) # # Verify that the record we found is an area detector record. # mx_class = _mpad.ad_record.get_field("mx_class") mx_type = _mpad.ad_record.get_field("mx_type") if ( mx_class != "area_detector" ): msg = "Record '%s' is not an 'area_detector' record." \ " Instead, it is of type '%s'." \ % ( _mpad.ad_record.name, mx_type ) raise Mp.Type_Mismatch_Error, msg else: # Find the first area detector record in the MX database. list_head = _mpad.record_list.get_record( "mx_database" ) current_record = list_head.get_next_record() while ( current_record != list_head ): mx_class = current_record.get_field("mx_class") # print current_record.name, mx_class if ( mx_class == "area_detector" ): _mpad.ad_record = current_record print "Using area detector record '%s'" \ % _mpad.ad_record.name break current_record = current_record.get_next_record() try: _mpad.ad_record except NameError: msg = \ "The MX database does not contain an area detector record." raise Mp.Not_Found_Error, msg #------------------------------------------------------------------- # # What type of area detector record is this? # _mpad.mx_type = _mpad.ad_record.get_field("mx_type") # # If this is a network area detector record, find out what type # of record is being used by the server. # if ( _mpad.mx_type != "network_area_detector" ): _mpad.server_record = None _mpad.remote_ad_name = None _mpad.remote_mx_type = None else: server_record_name = _mpad.ad_record.get_field("server_record") _mpad.server_record = \ _mpad.record_list.get_record( server_record_name ) _mpad.remote_ad_name = \ _mpad.ad_record.get_field("remote_record_name") mx_type_nf_name = "%s.mx_type" % ( _mpad.remote_ad_name ) mx_type_nf = Mp.Net( _mpad.server_record, mx_type_nf_name ) _mpad.remote_mx_type = mx_type_nf.get() print "_mpad.remote_mx_type =", _mpad.remote_mx_type # #------------------------------------------------------------------- # # Create the ImageFrame object that will be used to contain frames # read from the area detector. # maximum_framesize = _mpad.ad_record.get_maximum_framesize() bytes_per_pixel = _mpad.ad_record.get_bytes_per_pixel() _mpad.max_framesize = maximum_framesize num_pixels = int(maximum_framesize[0]) * int(maximum_framesize[1]) image_length = bytes_per_pixel * num_pixels image_length = int(image_length) image_frame = Mp.ImageFrame( maximum_framesize, \ 3, \ 1, \ bytes_per_pixel, \ 0, \ image_length ) _mpad.image_frame = image_frame _mpad.ad_record.setup_frame( _mpad.image_frame ) _mpad.file_number = 0 # # Create the WxPython GUI. # app = MpadApp(redirect=False) _mpad.gui_ready = True # # Check to see if a site-specific script must be loaded. # load_site_script = False try: mx_site = record_list.get_record( "mx_site" ) load_site_script = True except: pass if ( load_site_script ): mx_site_name = mx_site.get_field( "value" ) mx_site_script = \ os.path.join( _mpad.etc_dir, mx_site_name + ".py" ) mx_site_script = os.path.normpath( mx_site_script ) execfile( mx_site_script ) if ( os.name == "nt" ): _mpad.startup_timer = MpadStartupTimer( app.frame ) _mpad.startup_timer.Start( milliseconds=5000, oneShot=True ) # # Start the WxPython event loop. # app.MainLoop() # #---------------------------------------------------------------------------- # # FIXME: On Windows, EVT_IDLE handlers are never invoked at program startup # to load the current frame for some reason. This timer is used to make sure # that the current frame is loaded even if the application is not idle. # class MpadStartupTimer(wx.Timer): def __init__( self, owner ): wx.Timer.__init__( self, owner, id=-1 ) _mpad.fetch_image_frame = True owner.Bind( wx.EVT_TIMER, self.OnTimerEvent, self ) def OnTimerEvent( self, timer_event ): print "MpadStartupTimer invoked." if ( _mpad.fetch_image_frame ): _mpad.fetch_image_frame = False frame_number = _mpad.ad_record.get_last_frame_number() if ( frame_number < 0 ): print "+++ No frames acquired yet +++" else: print \ "+++ Getting initial frame %d from server +++" \ % frame_number get_frame_from_server( Mp.MXFT_AD_IMAGE_FRAME, \ frame_number ) #============================================================================= # # The MpadMainFrame class is used to implement the top level window of Mpad. # # #---------------------------------------------------------------------------- # class MpadMainFrame(wx.Frame): def __init__( self ): wx.Frame.__init__( self, None, \ title="MX Area Detector Control" ) _mpad.frame = self # # Create a panel to contain the notebook. # self.tab_panel = wx.Panel( self ) # # Create the tabbed notebook. # self.tab_notebook = MpadNotebook( self.tab_panel ) # # Create and add the Image tab. # self.image_tab = MpadImageTab( self.tab_notebook ) self.tab_notebook.AddPage( self.image_tab, "Image" ) # # If available, create and add a Detector Controls tab. # detector_controls_file = None if ( _mpad.remote_mx_type == "pccd_170170" ): detector_controls_file = "mpad_pccd_170170.py" elif ( _mpad.remote_mx_type == "pccd_4824" ): detector_controls_file = "mpad_pccd_4824.py" elif ( _mpad.remote_mx_type == "pccd_16080" ): detector_controls_file = "mpad_pccd_16080.py" if ( detector_controls_file != None ): detector_controls_file = os.path.join( \ _mpad.lib_dir, detector_controls_file ) detector_controls_file = os.path.normpath( \ detector_controls_file ) print "Loading detector_controls_file '%s'" \ % detector_controls_file execfile( detector_controls_file, globals(), globals() ) self.detector_controls_tab = \ MpadDetectorControlsTab( self.tab_notebook ) self.tab_notebook.AddPage( self.detector_controls_tab, \ "Detector Controls" ) self.setup_parameters_tab = \ MpadSetupParametersTab( self.tab_notebook ) self.tab_notebook.AddPage( self.setup_parameters_tab, \ "Setup Parameters" ) # # Create and populate a menu bar. # self.menubar = MpadMenuBar( self ) self.SetMenuBar( self.menubar ) # # Exit when the top level window is closed. # self.Bind( wx.EVT_CLOSE, self.OnCloseWindow ) self.Bind( wx.EVT_SIZE, self.OnSize ) # # Create a Box sizer to contain the tab panel. # self.tab_sizer = wx.BoxSizer( wx.HORIZONTAL ) self.tab_sizer.Add( self.tab_notebook, 1, wx.EXPAND ) self.tab_panel.SetSizer( self.tab_sizer ) # # Expand the size of the top level window to make sure # that all windows are visible. # self.tab_panel.Fit() self.Fit() def OnCloseWindow( self, event ): self.Destroy() def OnSize( self, event ): # print "MpadMainFrame: OnSize(): size =", self.GetSize() event.Skip() #----------------------------------------------------------------------------- class MpadNotebook(wx.Notebook): def __init__( self, parent ): wx.Notebook.__init__( self, parent ) self.parent = parent self.Bind( wx.EVT_SIZE, self.OnSize ) def OnSize( self, event ): # print "MpadNotebook: OnSize(): size = ", self.GetSize() event.Skip() #----------------------------------------------------------------------------- class MpadMenuBar(wx.MenuBar): def __init__( self, parent ): wx.MenuBar.__init__( self ) self.parent = parent # # If we are connecting to a server that is on the same # machine as the client, then we suppress the client # image file menu entries. # ad_record_type = _mpad.ad_record.get_field("mx_type") if ( ad_record_type == "network_area_detector" ): server_record_name = \ _mpad.ad_record.get_field("server_record") server_record = \ _mpad.record_list.get_record(server_record_name) server_type = server_record.get_field("mx_type") if ( server_type == "unix_server" ): show_client_items = False elif ( server_type == "tcp_server" ): hostname = server_record.get_field("hostname") if ( hostname == "localhost" ): show_client_items = False else: show_client_items = True else: show_client_items = True else: show_client_items = True # print "show_client_items =", show_client_items #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # # Add the File menu. # self.file_menu = wx.Menu() self.Append( self.file_menu, "File" ) if ( show_client_items ): load_image_item = \ self.file_menu.Append( -1, "Load Image File" ) parent.Bind( wx.EVT_MENU, \ self.OnLoadImage, load_image_item ) save_image_item = \ self.file_menu.Append( -1, "Save Image File" ) parent.Bind( wx.EVT_MENU, \ self.OnSaveImage, save_image_item ) self.file_menu.AppendSeparator() #--- load_server_item = self.file_menu.Append( -1, \ "Load Server Image" ) parent.Bind( wx.EVT_MENU, self.OnLoadServer, load_server_item ) save_server_item = self.file_menu.Append( -1, \ "Save Server Image" ) parent.Bind( wx.EVT_MENU, self.OnSaveServer, save_server_item ) self.file_menu.AppendSeparator() exit_item = self.file_menu.Append( -1, "Exit" ) parent.Bind( wx.EVT_MENU, self.OnExit, exit_item ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # # Add the Actions menu. # self.actions_menu = wx.Menu() self.Append( self.actions_menu, "Actions" ) get_server_frame_item = self.actions_menu.Append( -1, \ "Get Frame from Server" ) parent.Bind( wx.EVT_MENU, self.OnGetServerFrame, \ get_server_frame_item ) take_dark_frame_item = self.actions_menu.Append( -1, \ "Take Dark Current Image" ) parent.Bind( wx.EVT_MENU, self.OnTakeDarkFrame, \ take_dark_frame_item ) take_flood_frame_item = self.actions_menu.Append( -1, \ "Take Flood Field Image" ) parent.Bind( wx.EVT_MENU, self.OnTakeFloodFrame, \ take_flood_frame_item ) if ( _mpad.debug_window ): debug_window_item = self.actions_menu.Append( -1, \ "Debug Window" ) parent.Bind( wx.EVT_MENU, self.OnDebugWindow, \ debug_window_item ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # # Add the Help menu. # self.help_menu = wx.Menu() self.Append( self.help_menu, "Help" ) about_item = self.help_menu.Append( -1, "About Mpad" ) parent.Bind( wx.EVT_MENU, self.OnAbout, about_item ) def OnAbout( self, event ): dialog = MpadAboutBox() dialog.ShowModal() dialog.Destroy() def OnExit( self, event ): _mpad.frame.Close( True ) def OnGetServerFrame( self, event ): dialog = MpadGetServerFrameDialog() dialog.ShowModal() dialog.Destroy() def OnLoadImage( self, event ): dialog = wx.FileDialog( None, "Load Image File", style=wx.OPEN ) result = dialog.ShowModal() if ( result == wx.ID_OK ): filename = dialog.GetPath() _mpad.image_frame.read_file( Mp.MXT_IMAGE_FILE_SMV, \ filename ) wxt_panel = _mpad.frame.image_tab.wxt_panel wxt_panel.SetData( _mpad.image_frame ) wxt_panel.Display() dialog.Destroy() def OnLoadServer( self, event ): dialog = MpadLoadSaveServerDialog( 'load' ) dialog.ShowModal() dialog.Destroy() def OnSaveImage( self, event ): dialog = wx.FileDialog( None, "Save Image File", \ style=(wx.SAVE | wx.OVERWRITE_PROMPT) ) result = dialog.ShowModal() if ( result == wx.ID_OK ): filename = dialog.GetPath() _mpad.image_frame.write_file( Mp.MXT_IMAGE_FILE_SMV, \ filename ) dialog.Destroy() def OnSaveServer( self, event ): dialog = MpadLoadSaveServerDialog( 'save' ) dialog.ShowModal() dialog.Destroy() def OnTakeDarkFrame( self, event ): dialog = MpadDarkFloodDialog( 'dark' ) dialog.ShowModal() dialog.Destroy() def OnTakeFloodFrame( self, event ): dialog = MpadDarkFloodDialog( 'flood' ) dialog.ShowModal() dialog.Destroy() def OnDebugWindow( self, event ): # print "OnDebugWindow called" dialog = MpadDebugDialog() dialog.Show() #----------------------------------------------------------------------------- class MpadLoadSaveServerDialog(wx.Dialog): def __init__( self, loadsave ): self.server_frame_type = Mp.MXFT_AD_IMAGE_FRAME if ( loadsave == 'load' ): dialog_title = "Load Server Frame" elif ( loadsave == 'save' ): dialog_title = "Save Server Frame" else: self.Destroy() msg = "Bad loadsave argument '%s' supplied." % loadsave raise Mp.IllegalArgumentError, msg wx.Dialog.__init__( self, None, -1, dialog_title ) self.grid = wx.GridBagSizer( hgap=5, vgap=5 ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.frametype_label = wx.StaticText( self, -1, "Frame Type: " ) self.grid.Add( self.frametype_label, pos=(0,0), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) frametype_list = [ 'Image Frame', 'Mask Frame', 'Bias Frame', \ 'Dark Current Frame', 'Flood Field Frame' ] self.frametype_selector = wx.Choice( self, -1, \ choices=frametype_list ) self.grid.Add( self.frametype_selector, pos=(0,1) ) self.Bind( wx.EVT_CHOICE, self.OnChoice, \ self.frametype_selector ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.filename_label = wx.StaticText( self, -1, \ "Server Filename: " ) self.grid.Add( self.filename_label, pos=(1,0), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.filename_ctrl = wx.TextCtrl( self, size=(200,30) ) self.grid.Add( self.filename_ctrl, pos=(1,1) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Create a panel to put the buttons in. self.button_panel = MpadLoadSaveButtonPanel( self, loadsave ) self.grid.Add( self.button_panel, pos=(2,0), span=(1,2), \ flag=wx.ALIGN_CENTER ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.SetSizer( self.grid ) self.Fit() #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def OnChoice( self, event ): selection = self.frametype_selector.GetSelection() self.server_frame_type = get_server_frame_type( selection ) #----------------------------------------------------------------------------- class MpadLoadSaveButtonPanel(wx.Panel): def __init__( self, parent, loadsave ): wx.Panel.__init__( self, parent ) self.parent = parent self.box = wx.BoxSizer( wx.HORIZONTAL ) if ( loadsave == 'load' ): self.loadsave_button = wx.Button( self, label="Load" ) self.Bind( wx.EVT_BUTTON, self.OnLoadButton, \ self.loadsave_button ) else: self.loadsave_button = wx.Button( self, label="Save" ) self.Bind( wx.EVT_BUTTON, self.OnSaveButton, \ self.loadsave_button ) self.box.Add( self.loadsave_button ) self.cancel_button = wx.Button( self, label="Cancel" ) self.Bind( wx.EVT_BUTTON, self.OnCancelButton, \ self.cancel_button ) self.box.Add( self.cancel_button ) self.SetSizer( self.box ) def OnLoadButton( self, event ): filename = self.parent.filename_ctrl.GetValue() if ( filename == None ): return elif ( filename == "" ): return _mpad.ad_record.load_frame( \ self.parent.server_frame_type, filename ) print "File '%s' loaded." % filename self.parent.Destroy() def OnSaveButton( self, event ): filename = self.parent.filename_ctrl.GetValue() if ( filename == None ): return elif ( filename == "" ): return _mpad.ad_record.save_frame( \ self.parent.server_frame_type, filename ) print "File '%s' saved." % filename self.parent.Destroy() def OnCancelButton( self, event ): self.parent.Destroy() #----------------------------------------------------------------------------- class MpadDarkFloodDialog(wx.Dialog): def __init__( self, darkflood ): self.measurement_type = darkflood if ( self.measurement_type == 'dark' ): dialog_title = "Take Dark Current Image" elif ( self.measurement_type == 'flood' ): dialog_title = "Take Flood Field Image" else: self.Destroy() msg = "Bad darkflood argument '%s' supplied." \ % dark_flood raise Mp.IllegalArgumentError, msg wx.Dialog.__init__( self, None, -1, dialog_title ) self.grid = wx.GridBagSizer( hgap=5, vgap=5 ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.time_label = wx.StaticText( self, -1, "Measurement Time: ") self.grid.Add( self.time_label, pos=(0,0), border=5, \ flag=(wx.LEFT | wx.TOP | wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.time_ctrl = wx.TextCtrl( self ) self.grid.Add( self.time_ctrl, pos=(0,1), border=5, \ flag=(wx.TOP | wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.num_label = wx.StaticText( self, -1, \ "Number of Measurements: " ) self.grid.Add( self.num_label, pos=(1,0), border=5, \ flag=(wx.LEFT | wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.num_ctrl = wx.TextCtrl( self ) self.grid.Add( self.num_ctrl, pos=(1,1), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.button_box = wx.BoxSizer( wx.HORIZONTAL ) self.grid.Add( self.button_box, pos=(2,0), span=(1,2), \ border=10, flag=(wx.ALL | wx.ALIGN_CENTER) ) self.start_button = wx.Button( self, label="Start Measurement" ) self.button_box.Add( self.start_button ) self.Bind( wx.EVT_BUTTON, self.OnStartButton, \ self.start_button ) self.cancel_button = wx.Button( self, label="Cancel" ) self.button_box.Add( self.cancel_button ) self.Bind( wx.EVT_BUTTON, self.OnCancelButton, \ self.cancel_button ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.SetSizer( self.grid ) self.Fit() #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def OnCancelButton( self, event ): self.Destroy() def OnStartButton( self, event ): print "Start button pressed." measurement_time_string = self.time_ctrl.GetValue() if ( measurement_time_string == "" ): return num_measurements_string = self.num_ctrl.GetValue() if ( num_measurements_string == "" ): return measurement_time = float(measurement_time_string) num_measurements = int(num_measurements_string) if ( self.measurement_type == 'dark' ): print \ "Starting dark current measurement for area detector '%s'." \ % _mpad.ad_record.name print \ "Measurement time = %g seconds, number of measurements = %d" \ % ( measurement_time, num_measurements ) _mpad.ad_record.measure_dark_current_frame( \ measurement_time, num_measurements ) elif ( self.measurement_type == 'flood' ): print \ "Starting flood field measurement for area detector '%s'." \ % _mpad.ad_record.name print \ "Measurement time = %g seconds, number of measurements = %d" \ % ( measurement_time, num_measurements ) _mpad.ad_record.measure_flood_field_frame( \ measurement_time, num_measurements ) else: self.Destroy() msg = "Bad measurement type '%s' supplied." \ % self.measurement_type raise Mp.IllegalArgumentError, msg # # Wait for the measurement to complete. # # FIXME: We should have a progress meter and # an active cancel button here. # while True: _mpad.record_list.wait_for_messages(0.1) busy = _mpad.ad_record.is_busy() if ( busy == False ): break time.sleep(0.1) print "Measurement complete." self.Destroy() #----------------------------------------------------------------------------- class MpadDebugDialog(wx.Dialog): def __init__( self ): wx.Dialog.__init__( self, None, -1, "Mpad Debug Window" ) self.grid = wx.GridBagSizer( hgap=5, vgap=5 ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.prompt_label = wx.StaticText( self, -1, ">>> " ) self.grid.Add( self.prompt_label, pos=(0,0), border=5, \ flag=(wx.LEFT | wx.TOP | wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) # # style=wx.TE_PROCESS_ENTER must be specify if we want to # use events of type wx.EVT_TEXT_ENTER. # self.prompt_ctrl = wx.TextCtrl( self, size=(400,-1), \ style=wx.TE_PROCESS_ENTER ) self.prompt_ctrl.Bind( wx.EVT_TEXT_ENTER, self.OnEnter ) self.grid.Add( self.prompt_ctrl, pos=(0,1), border=5, \ flag=(wx.TOP | wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.dismiss_button = wx.Button( self, label="Dismiss" ) self.Bind( wx.EVT_BUTTON, \ self.OnDismissButton, self.dismiss_button ) self.grid.Add( self.dismiss_button, pos=(1,0), span=(1,2), \ border=5, flag=wx.ALIGN_CENTER ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.SetSizer( self.grid ) self.Fit() def OnDismissButton( self, event ): self.Destroy() def OnEnter( self, event ): command = self.prompt_ctrl.GetValue() command = str(command) print "Command: %s" % command self.prompt_ctrl.SetValue("") if ( sys.version_info[0] < 3 ): exec command in globals() else: exec( command, globals() ) print "Command complete." #----------------------------------------------------------------------------- class MpadGetServerFrameDialog(wx.Dialog): def __init__( self ): wx.Dialog.__init__( self, None, -1, "Get Server Frame" ) self.server_frame_type = Mp.MXFT_AD_IMAGE_FRAME self.grid = wx.GridBagSizer( hgap=5, vgap=5 ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.frametype_label = wx.StaticText( self, -1, "Frame Type: " ) self.grid.Add( self.frametype_label, pos=(0,0), border=10, \ flag=(wx.LEFT | wx.TOP | wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) frametype_list = [ 'Image Frame', 'Mask Frame', 'Bias Frame', \ 'Dark Current Frame', 'Flood Field Frame' ] self.frametype_selector = wx.Choice( self, -1, \ choices=frametype_list ) self.grid.Add( self.frametype_selector, pos=(0,1), border=10, \ flag=(wx.RIGHT | wx.TOP) ) self.Bind( wx.EVT_CHOICE, self.OnChoice, \ self.frametype_selector ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.button_box = wx.BoxSizer( wx.HORIZONTAL ) self.get_frame_button = wx.Button( self, label="Get Frame" ) self.button_box.Add( self.get_frame_button ) self.Bind( wx.EVT_BUTTON, self.OnGetFrameButton, \ self.get_frame_button ) self.cancel_button = wx.Button( self, label="Cancel" ) self.button_box.Add( self.cancel_button ) self.Bind( wx.EVT_BUTTON, self.OnCancelButton, \ self.cancel_button ) self.grid.Add( self.button_box, pos=(1,0), span=(1,2), \ border=10, flag=(wx.ALL | wx.ALIGN_CENTER) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.SetSizer( self.grid ) self.Fit() #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def OnChoice( self, event ): selection = self.frametype_selector.GetSelection() self.server_frame_type = get_server_frame_type( selection ) def OnCancelButton( self, event ): self.Destroy() def OnGetFrameButton( self, event ): _mpad.ad_record.transfer_frame( self.server_frame_type, \ _mpad.image_frame ) wxt_panel = _mpad.frame.image_tab.wxt_panel wxt_panel.SetData( _mpad.image_frame ) wxt_panel.Display() self.Destroy() #----------------------------------------------------------------------------- class MpadAboutBox(wx.Dialog): def __init__( self ): wx.Dialog.__init__( self, None, -1, "About Mpad" ) self.box = wx.BoxSizer( wx.VERTICAL ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.name = wx.StaticText( self, -1, "MX Area Detector Control") self.box.Add( self.name, border=20, \ flag=(wx.ALL | wx.ALIGN_CENTER) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.copyright = wx.StaticText( self, -1, \ "Copyright 2008-2009 Illinois Institute of Technology" ) self.box.Add( self.copyright, border=10, \ flag=(wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.author = wx.StaticText( self, -1, \ "Created by William M. Lavender" ) self.box.Add( self.author, border=10, \ flag=(wx.BOTTOM | wx.ALIGN_CENTER) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.description = wx.StaticText( self, -1, \ "Mpad is a joint project of Aviex LLC\n" "and Illinois Institute of Technology" ) self.box.Add( self.description, border=10, \ flag=(wx.ALL | wx.ALIGN_CENTER) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.button = wx.Button( self, label="OK" ) self.box.Add( self.button, border=10, \ flag=(wx.ALL | wx.ALIGN_CENTER) ) self.Bind( wx.EVT_BUTTON, self.OnOKButton, self.button ) self.SetSizer( self.box ) self.Fit() def OnOKButton( self, event ): self.Destroy() #============================================================================= class MpadImageTab(wx.Panel): def __init__( self, parent ): wx.Panel.__init__( self, parent ) self.parent = parent # # Create a Box sizer to contain the main image and the # side window. # self.image_tab_sizer = wx.BoxSizer( wx.HORIZONTAL ) # # Attach image_tab_sizer to the panel. # #---------------------------- # # Create the image panel. # self.wxt_panel = MpadWxtImagePanel( self ) self.image_tab_sizer.Add( self.wxt_panel, 1, \ border=10, flag=wx.EXPAND ) # # Create the right hand panel. # self.right_panel = MpadRightPanel( self ) # FIXME - Should we add wx.EXPAND for the right panel? self.image_tab_sizer.Add( self.right_panel, 0, \ border=10, flag=wx.ALL) self.SetSizer( self.image_tab_sizer ) self.Bind( wx.EVT_SIZE, self.OnSize ) def OnSize( self, event ): # print "MpadImageTab: OnSize(): size =", self.GetSize() event.Skip() #============================================================================= def mpad_monitor_display( field_name, widget, scale, offset, function, choices): nf_name = "%s.%s" % ( _mpad.ad_record.name, field_name ) nf = Mp.Net( _mpad.server_record, nf_name ) args = (nf, widget, function, choices) callback = nf.add_callback( Mp.MXCBT_VALUE_CHANGED, \ mpad_monitor_callback, args ) _mpad.callback_list.append( callback ) del callback return nf def mpad_monitor_callback( callback, args ): (nf, widget, function, choices) = args print "nf = '%s:%s', widget = %s, function = %s, choices = %s" \ % ( nf.server.name, nf.name, widget, function, choices ) if ( function != None ): function( nf, widget, choices ) else: raw_value = nf.get_local_value() if ( _mpad.debug_serial ): print "Received %s for '%s'" % \ ( str(raw_value), nf.name ) value = nf.offset + nf.scale * raw_value value = str(value) widget.SetLabel(value) widget.SetSize(widget.GetBestSize()) #============================================================================= class MpadRightPanel(wx.Panel): def __init__( self, parent ): wx.Panel.__init__( self, parent ) self.parent = parent self.box = wx.BoxSizer( wx.VERTICAL ) # # Create the status panel. # self.status_panel = MpadStatusPanel( self ) self.box.Add( self.status_panel, border=5, \ flag=(wx.TOP | wx.BOTTOM | wx.ALIGN_LEFT) ) # # Insert two separators. # self.sep1a = wx.StaticLine( self ) self.box.Add( self.sep1a, flag=(wx.ALIGN_LEFT | wx.EXPAND ) ) self.sep1b = wx.StaticLine( self ) self.box.Add( self.sep1b, flag=(wx.ALIGN_LEFT | wx.EXPAND ) ) # # Create the sequence type panel. # self.sequence_panel = MpadSequencePanel( self ) self.box.Add( self.sequence_panel, border=5, \ flag=(wx.TOP | wx.ALIGN_LEFT) ) # # Insert a separator. # self.sep2 = wx.StaticLine( self ) self.box.Add( self.sep2, border=5, \ flag=(wx.TOP | wx.ALIGN_LEFT | wx.EXPAND ) ) # # Create the Start button. # self.start_button = wx.Button( self, label="Start Sequence" ) self.Bind( wx.EVT_BUTTON, self.OnStartButton, self.start_button ) self.box.Add( self.start_button, border=5, \ flag=(wx.TOP | wx.ALIGN_CENTER)) # # Create the Stop button. # self.stop_button = wx.Button( self, label="Stop Sequence" ) self.Bind( wx.EVT_BUTTON, self.OnStopButton, self.stop_button ) self.box.Add( self.stop_button, border=5, \ flag=(wx.TOP | wx.ALIGN_CENTER)) # # Insert two separators. # self.sep3a = wx.StaticLine( self ) self.box.Add( self.sep3a, border=10, \ flag=(wx.TOP | wx.ALIGN_LEFT | wx.EXPAND ) ) self.sep3b = wx.StaticLine( self ) self.box.Add( self.sep3b, border=5, \ flag=(wx.BOTTOM | wx.ALIGN_LEFT | wx.EXPAND ) ) # # Create the shutter control panel. # self.shutter_control = MpadShutterControlPanel( self ) self.box.Add( self.shutter_control, border=5, \ flag=(wx.TOP | wx.ALIGN_CENTER) ) # # Insert two separators. # self.sep3c = wx.StaticLine( self ) self.box.Add( self.sep3c, border=10, \ flag=(wx.TOP | wx.ALIGN_LEFT | wx.EXPAND ) ) self.sep3d = wx.StaticLine( self ) self.box.Add( self.sep3d, border=5, \ flag=(wx.BOTTOM | wx.ALIGN_LEFT | wx.EXPAND ) ) # # Create the dark current panel. # self.dark_current_panel = MpadDarkCurrentPanel( self ) self.box.Add( self.dark_current_panel, flag=wx.ALIGN_CENTER ) # # Insert two separators. # self.sep5a = wx.StaticLine( self ) self.box.Add( self.sep5a, border=10, \ flag=(wx.TOP | wx.ALIGN_LEFT | wx.EXPAND ) ) self.sep5b = wx.StaticLine( self ) self.box.Add( self.sep5b, border=5, \ flag=(wx.BOTTOM | wx.ALIGN_LEFT | wx.EXPAND ) ) # # Create the datafile panel. # self.datafile_panel = MpadDatafilePanel( self ) self.box.Add( self.datafile_panel, flag=wx.ALIGN_CENTER ) self.SetSizer( self.box ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def OnStartButton( self, event ): panel = self.sequence_panel.current_sequence_panel if ( panel == None ): raise AssertionError, "current_sequence_panel is None!" # Invoke the command for this sequence panel. _mpad.is_busy = True panel.command( panel ) def OnStopButton( self, event ): _mpad.ad_record.stop() #------------------------------------------------------------------------------ class MpadStatusPanel(wx.Panel): def __init__( self, parent ): wx.Panel.__init__( self, parent ) self.parent = parent self.grid = wx.GridBagSizer() status_width = 40 #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.lfn_label = wx.StaticText( self, -1, "Frame Number: " ) self.grid.Add( self.lfn_label, pos=(0,0) ) lfn_name = "%s.last_frame_number" % ( _mpad.remote_ad_name ) self.lfn_value = MpWx.Value( self, \ _mpad.server_record, lfn_name, \ size=(status_width,-1) ) self.lfn_value.SetForegroundColour( "blue" ) self.grid.Add( self.lfn_value, pos=(0,1) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.tnf_label = wx.StaticText( self, -1, "Total # Frames: " ) self.grid.Add( self.tnf_label, pos=(1,0) ) tnf_name = "%s.total_num_frames" % ( _mpad.remote_ad_name ) self.tnf_value = MpWx.Value( self, \ _mpad.server_record, tnf_name, \ function = mpad_total_num_frames_callback_function, \ args = self.lfn_value.nf, size=(status_width,-1) ) self.tnf_value.SetForegroundColour( "blue" ) self.grid.Add( self.tnf_value, pos=(1,1) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # This widget must be created "out of order" so that # the self.status_text attribute already exists the # first time that mpad_status_callback_function() # is invoked. # self.status_text = wx.StaticText( self, -1, "Idle", \ size=(200,-1) ) self.status_text.SetForegroundColour( "limegreen" ) self.grid.Add( self.status_text, pos=(2,2), border=20, \ flag=wx.LEFT ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.status_label = wx.StaticText( self, -1, "Status:" ) self.grid.Add( self.status_label, pos=(2,0) ) status_name = "%s.status" % ( _mpad.remote_ad_name ) self.status_value = MpWx.Value( self, \ _mpad.server_record, status_name, \ function = mpad_status_callback_function, \ size=(status_width,-1) ) self.status_value.SetForegroundColour( "blue" ) self.grid.Add( self.status_value, pos=(2,1) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.Bind( wx.EVT_IDLE, self.OnIdle ) self.SetSizer( self.grid ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - initial_frame_number = self.lfn_value.nf.get_local_value() if ( initial_frame_number >= 0 ): _mpad.fetch_image_frame = True def OnIdle( self, event ): last_frame_number_nf = self.lfn_value.nf frame_number = last_frame_number_nf.get_local_value() if ( _mpad.fetch_image_frame and ( frame_number >= 0 ) ): _mpad.fetch_image_frame = False print "*** Getting frame %d from server ***" \ % frame_number get_frame_from_server( Mp.MXFT_AD_IMAGE_FRAME, \ frame_number ) #---- def mpad_total_num_frames_callback_function( nf, widget, value ): _mpad.fetch_image_frame = True MpWx._Value_update( nf, widget, value ) return #---- def mpad_status_callback_function( nf, widget, value ): MpWx._Value_update( nf, widget, value ) if ( value == 0 ): text = "Idle" color = "limegreen" elif ( value & 4 ): text = "Correction measurement" color = "orange" elif ( value & 2 ): text = "Correcting" color = "red" elif ( value & 1 ): text = "Acquiring" color = "red" else: text = "Unknown" color = "purple" status_text = widget.parent.status_text status_text.SetLabel( text ) status_text.SetForegroundColour( color ) #------------------------------------------------------------------------------ class MpadContrastPanel(wx.Panel): def __init__( self, parent ): wx.Panel.__init__( self, parent ) self.parent = parent self.grid = wx.GridBagSizer() #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.title = wx.StaticText( self, -1, "Contrast: " ) self.grid.Add( self.title, pos=(0,0), \ flag=wx.ALIGN_CENTER_VERTICAL ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.black_label = wx.StaticText( self, -1, "Black: " ) self.grid.Add( self.black_label, pos=(0,1), \ flag=wx.ALIGN_CENTER_VERTICAL ) self.black_value = wx.TextCtrl( self, \ validator = MpadFloatValidator() ) self.black_value.SetValue("0") self.grid.Add( self.black_value, pos=(0,2), \ flag=wx.ALIGN_CENTER_VERTICAL ) self.white_label = wx.StaticText( self, -1, " White: " ) self.grid.Add( self.white_label, pos=(0,3), \ flag=wx.ALIGN_CENTER_VERTICAL ) self.white_value = wx.TextCtrl( self, \ validator = MpadFloatValidator() ) self.white_value.SetValue("65535") self.grid.Add( self.white_value, pos=(0,4), \ flag=wx.ALIGN_CENTER_VERTICAL ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.change_button = wx.Button( self, label="Change Contrast" ) self.grid.Add( self.change_button, pos=(0,5), border=10, \ flag=( wx.LEFT | wx.ALIGN_CENTER_VERTICAL ) ) self.Bind( wx.EVT_BUTTON, self.OnChangeButton, \ self.change_button ) self.autoscale_button = wx.Button( self, label="Autoscale" ) self.grid.Add( self.autoscale_button, pos=(0,6), border=10, \ flag=( wx.LEFT | wx.ALIGN_CENTER_VERTICAL ) ) self.Bind( wx.EVT_BUTTON, self.OnAutoscaleButton, \ self.autoscale_button ) self.SetSizer( self.grid ) def OnChangeButton( self, event ): black_value = int( self.black_value.GetValue() ) white_value = int( self.white_value.GetValue() ) print "Changing contrast: black_value = %d, white_value = %d" \ % ( black_value, white_value ) panel = _mpad.frame.image_tab.wxt_panel.image_foo panel.SetGreyRampColormap( black_value, white_value ) panel.Display() def OnAutoscaleButton( self, event ): panel = _mpad.frame.image_tab.wxt_panel.image_foo ( mean, std_dev, min, max ) = panel.GetStatistics() black_value = round( mean - 2.0 * std_dev ) white_value = round( mean + 2.0 * std_dev ) black_value = int(black_value) white_value = int(white_value) if ( black_value < 0 ): black_value = 0 if ( white_value > 65535 ): white_value = 65535 panel.SetGreyRampColormap( black_value, white_value ) self.black_value.SetValue( str(black_value) ) self.white_value.SetValue( str(white_value) ) panel.Display() #------------------------------------------------------------------------------ class MpadDarkCurrentPanel(wx.Panel): def __init__( self, parent ): wx.Panel.__init__( self, parent ) self.parent = parent self.grid = wx.GridBagSizer() self.SetSizer( self.grid ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.title = wx.StaticText( self, -1, "Dark Current" ) self.grid.Add( self.title, pos=(0,0), span=(1,2), border=5, \ flag=(wx.BOTTOM | wx.ALIGN_CENTER) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.time_label = wx.StaticText( self, -1, "Measurement Time: ") self.grid.Add( self.time_label, pos=(1,0), border=5, \ flag=(wx.LEFT | wx.TOP | wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.time_ctrl = wx.TextCtrl( self ) self.grid.Add( self.time_ctrl, pos=(1,1), border=5, \ flag=(wx.TOP | wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.num_label = wx.StaticText( self, -1, \ "Number of Measurements: " ) self.grid.Add( self.num_label, pos=(2,0), border=5, \ flag=(wx.LEFT | wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.num_ctrl = wx.TextCtrl( self ) self.grid.Add( self.num_ctrl, pos=(2,1), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.button_panel = wx.Panel( self ) self.grid.Add( self.button_panel, pos=(3,0), span=(1,2), \ border=10, flag=(wx.ALL | wx.ALIGN_CENTER) ) self.button_box = wx.BoxSizer( wx.HORIZONTAL ) self.button_panel.SetSizer( self.button_box ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.start_button = wx.Button( self.button_panel, \ label="Start Measurement" ) self.button_box.Add( self.start_button ) self.Bind( wx.EVT_BUTTON, self.OnStartButton, \ self.start_button ) self.cancel_button = wx.Button( self.button_panel, \ label="Cancel" ) self.button_box.Add( self.cancel_button ) self.Bind( wx.EVT_BUTTON, self.OnCancelButton, \ self.cancel_button ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.Fit() def OnCancelButton( self, event ): print "Cancel button pressed." _mpad.ad_record.stop() def OnStartButton( self, event ): print "Start button pressed." measurement_time_string = self.time_ctrl.GetValue() if ( measurement_time_string == "" ): return num_measurements_string = self.num_ctrl.GetValue() if ( num_measurements_string == "" ): return measurement_time = float( measurement_time_string ) num_measurements = int( num_measurements_string ) print \ "Starting dark current measurement for area detector '%s'." \ % _mpad.ad_record.name print \ "measurement time = %g seconds, number of measurements = %d" \ % ( measurement_time, num_measurements ) _mpad.ad_record.measure_dark_current_frame( \ measurement_time, num_measurements ) _mpad.correction_timer = MpadCorrectionTimer( self ) print "BEFORE TIMER START" _mpad.correction_timer.Start(1000) print "AFTER TIMER START" #------------------------------------------------------------------------------ class MpadCorrectionTimer(wx.Timer): def __init__( self, parent ): wx.Timer.__init__( self, parent, -1 ) self.parent = parent parent.Bind( wx.EVT_TIMER, self.OnCallback, self ) def OnCallback( self, event ): print "MpadCorrectionTimer.OnCallback() invoked." ad_status = _mpad.ad_record.get_status() if ( ad_status != 0 ): return print "MpadCorrectionTimer.OnCallback(): Transferring frame." _mpad.ad_record.transfer_frame( Mp.MXFT_AD_DARK_CURRENT_FRAME, \ _mpad.image_frame ) wxt_panel = _mpad.frame.image_tab.wxt_panel wxt_panel.SetData( _mpad.image_frame ) wxt_panel.Display() self.Stop() self.Destroy() _mpad.correction_timer = None _mpad.fetch_image_frame = False print "MpadCorrectionTimer destroyed." #------------------------------------------------------------------------------ class MpadDatafilePanel(wx.Panel): def __init__( self, parent ): wx.Panel.__init__( self, parent ) self.parent = parent self.grid = wx.GridBagSizer() row = 0 #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.title = wx.StaticText( self, -1, "Image Destination" ) self.grid.Add( self.title, pos=(row,0), span=(1,3), border=5, flag=(wx.BOTTOM | wx.ALIGN_CENTER) ) row = row + 1 #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.directory_label = wx.StaticText( self, -1, "Directory:" ) self.grid.Add( self.directory_label, pos=(row,0), border=5, flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) directory_nf_name = \ "%s.datafile_directory" % _mpad.remote_ad_name self.spacer = wx.StaticText( self, -1, " " ) self.grid.Add( self.spacer, pos=(row,1) ) self.directory_value = MpadDatafileDirectory( self ) self.grid.Add( self.directory_value, pos=(row,2), flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) row = row + 1 #- - - self.pattern_label = wx.StaticText( self, -1, "Pattern:" ) self.grid.Add( self.pattern_label, pos=(row,0), flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) pattern_nf_name = "%s.datafile_pattern" % _mpad.remote_ad_name self.pattern_value = MpWx.ValueEntry( self, _mpad.server_record, pattern_nf_name, size=(200,-1) ) self.grid.Add( self.pattern_value, pos=(row,2), flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) row = row + 1 #- - - self.filename_label = \ wx.StaticText( self, -1, "Filename:" ) self.grid.Add( self.filename_label, pos=(row,0), flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) filename_nf_name = "%s.datafile_name" % _mpad.remote_ad_name self.filename_value = MpWx.Value( self, _mpad.server_record, filename_nf_name ) self.filename_value.SetForegroundColour( "blue" ) self.grid.Add( self.filename_value, pos=(row,2), flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) row = row + 1 #- - - self.next_file_number_label = \ wx.StaticText( self, -1, "Last Datafile Number:" ) self.grid.Add( self.next_file_number_label, pos=(row,0), flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL), border = 5 ) next_file_number_nf_name = \ "%s.datafile_number" % _mpad.remote_ad_name self.next_file_number_value = MpWx.ValueEntry( self, _mpad.server_record, next_file_number_nf_name, size=(200,-1) ) self.grid.Add( self.next_file_number_value, pos=(row,2), flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL), border = 5 ) row = row + 1 #- - - if 1: self.autoselect_number_label = \ wx.StaticText( self, -1, "Autoselect Number:" ) self.grid.Add( self.autoselect_number_label,pos=(row,0), flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL), border = 5 ) autoselect_number_nf_name = \ "%s.datafile_autoselect_number" % _mpad.remote_ad_name self.autoselect_number_value = MpWx.ValueEntry( self, _mpad.server_record, autoselect_number_nf_name, size=(30,-1) ) self.grid.Add( self.autoselect_number_value,pos=(row,2), flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL), border = 5 ) row = row + 1 self.allow_overwrite_label = \ wx.StaticText( self, -1, "Allow Overwrite:" ) self.grid.Add( self.allow_overwrite_label, pos=(row,0), flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL), border = 5 ) allow_overwrite_nf_name = \ "%s.datafile_allow_overwrite" % _mpad.remote_ad_name self.allow_overwrite_value = MpWx.ValueEntry( self, _mpad.server_record, allow_overwrite_nf_name, size=(30,-1) ) self.grid.Add( self.allow_overwrite_value, pos=(row,2), flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL), border = 5 ) #- - - self.SetSizer( self.grid ) #------------------------------------------------------------------------------ class MpadDatafileDirectory(wx.lib.filebrowsebutton.DirBrowseButton): def __init__( self, parent ): wx.lib.filebrowsebutton.DirBrowseButton.__init__( self, parent, labelText="", size=(300, -1) ) self.parent = parent field_name = "%s.datafile_directory" % ( _mpad.remote_ad_name ) self.nf = Mp.Net( _mpad.server_record, field_name ) # # Disable the widget if the network field is read only. # read_only = self.nf.get_attribute( Mp.MXNA_READ_ONLY ) if ( read_only ): self.Enable(False) # # See if remote and local directory variables have been # defined. These are used if the detector's data file # directory has been NFS or SMB exported to the client. # try: self.remote_dir_record = \ _mpad.record_list.get_record( "mx_remote_dir" ) self.local_dir_record = \ _mpad.record_list.get_record( "mx_local_dir" ) except: self.remote_dir_record = None self.local_dir_record = None # # Fetch the initial value of the field. # function = mpad_datafile_directory_callback self.nf.get_with_callback( function, None, self ) # Set up a value changed callback for the field. self.callback = self.nf.add_callback( Mp.MXCBT_VALUE_CHANGED, function, None, self ) # # Override the createTextControl method, so that it creates the # TextCtrl widget with style wx.TE_PROCESS_ENTER, which is necessary # for wx.EVT_TEXT_ENTER events to work. We must override this # method since it does not appear to be possible to change the # TextCtrl style after the widget has been created. # def createTextControl( self ): text_control = wx.TextCtrl( self, style=wx.TE_PROCESS_ENTER ) text_control.SetToolTipString( self.toolTip ) text_control.Bind(wx.EVT_TEXT_ENTER, self.OnEnter ) return text_control def OnEnter( self, event ): new_path = self.GetValue() if ( self.remote_dir_record != None ): new_path = mpad_transform_path( self, new_path, True ) self.nf.put( new_path ) def OnBrowse( self, ev = None ): current_path = self.GetValue() if ( current_path == "" ): current_path = "." dialog = wx.DirDialog( self, message = "", defaultPath = current_path, style = wx.TAB_TRAVERSAL ) if ( dialog.ShowModal() == wx.ID_OK ): new_path = dialog.GetPath() if ( self.remote_dir_record != None ): new_path = \ mpad_transform_path( self, new_path, True ) self.nf.put( new_path ) self.SetValue( new_path ) dialog.Destroy() #--- def mpad_datafile_directory_callback( callback, args ): nf = callback.nf value = nf.get_local_value() value = str( value ) widget = callback.object if ( widget.remote_dir_record != None ): value = mpad_transform_path( widget, value, False ) widget.SetValue( value ) widget.SetSize( widget.GetBestSize() ) #--- def mpad_transform_path( dir_widget, old_filename, local_to_remote ): if ( local_to_remote ): old_prefix = dir_widget.local_dir_record.read() new_prefix = dir_widget.remote_dir_record.read() else: old_prefix = dir_widget.remote_dir_record.read() new_prefix = dir_widget.local_dir_record.read() new_filename = \ Mp.change_filename_prefix( old_filename, old_prefix, new_prefix ) print "mpad_transform_path: old_prefix = '%s', new_prefix = '%s'" \ % ( old_prefix, new_prefix ) print "mpad_transform_path: old_filename = '%s', new_filename = '%s'" \ % ( old_filename, new_filename ) return new_filename #------------------------------------------------------------------------------ class MpadSequencePanel(wx.Panel): def __init__( self, parent ): wx.Panel.__init__( self, parent ) self.parent = parent self.box = wx.BoxSizer( wx.VERTICAL ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.sequence_type_list = [] self.sequence_panel_list = [] self.sequence_type_list.append('One-Shot') self.sequence_panel_list.append( \ MpadOneShotPanel( self, mpad_start_one_shot ) ) self.sequence_type_list.append('Continuous') self.sequence_panel_list.append( \ MpadContinuousPanel( self, mpad_start_continuous ) ) self.sequence_type_list.append('Multiframe') self.sequence_panel_list.append( \ MpadMultiframePanel( self, mpad_start_multiframe ) ) self.sequence_type_list.append('Circular Multiframe') self.sequence_panel_list.append( \ MpadCircularMultiframePanel( self, mpad_start_circular_multiframe ) ) self.sequence_type_list.append('Strobe') self.sequence_panel_list.append( \ MpadStrobePanel( self, mpad_start_strobe ) ) self.sequence_type_list.append('Duration') self.sequence_panel_list.append( \ MpadDurationPanel( self, mpad_start_duration ) ) self.sequence_type_list.append('Geometrical') self.sequence_panel_list.append( \ MpadGeometricalPanel( self, mpad_start_geometrical ) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.sequence_type_panel = MpadSequenceTypePanel( self ) self.box.Add( self.sequence_type_panel, border=10, \ flag = wx.BOTTOM ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Load the default sequence panel. self.box.Add( self.sequence_panel_list[0] ) self.current_sequence_panel = self.sequence_panel_list[0] self.SetSizer( self.box ) #------------------------------------------------------------------------------ class MpadSequenceTypePanel(wx.Panel): def __init__( self, parent ): wx.Panel.__init__( self, parent ) self.parent = parent self.box = wx.BoxSizer( wx.HORIZONTAL ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.label = wx.StaticText( self, -1, "Sequence Type: " ) self.box.Add( self.label, flag=(wx.LEFT | wx.ALIGN_CENTER) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.selector = wx.Choice( self, -1, \ choices=parent.sequence_type_list ) self.box.Add( self.selector, 1, wx.LEFT ) self.Bind( wx.EVT_CHOICE, self.OnChoice, self.selector ) self.SetSizer( self.box ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def OnChoice( self, event ): selection = self.selector.GetSelection() parent = self.parent sequence_type = parent.sequence_type_list[selection] sequence_panel = parent.sequence_panel_list[selection] if ( parent.current_sequence_panel != None ): parent.box.Detach( parent.current_sequence_panel ) parent.current_sequence_panel.Show(False) parent.current_sequence_panel = None parent.box.Add( sequence_panel ) parent.current_sequence_panel = sequence_panel parent.current_sequence_panel.Show(True) # Resize the sequence window and everything around it. parent.current_sequence_panel.Layout() parent.Layout() if True: # This way is faster. _mpad.frame.image_tab.right_panel.sequence_panel.Layout() _mpad.frame.image_tab.right_panel.Layout() _mpad.frame.image_tab.Layout() _mpad.frame.Layout() else: # The following is more general, but noticeably slower. w = self while True: w = w.GetParent() if ( w == None ): break w.Layout() _mpad.frame.Fit() #------------------------------------------------------------------------------ class MpadOneShotPanel(wx.Panel): def __init__( self, parent, command ): wx.Panel.__init__( self, parent ) self.parent = parent self.command = command self.grid = wx.GridBagSizer() #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.exposure_time_label = \ wx.StaticText( self, -1, "Exposure Time: " ) self.grid.Add( self.exposure_time_label, pos=(0,0), \ flag=wx.ALIGN_CENTER ) self.exposure_time_ctrl = wx.TextCtrl( self, \ validator = MpadFloatValidator() ) self.grid.Add( self.exposure_time_ctrl, pos=(0,1), \ border=5, flag=wx.RIGHT ) self.exposure_time_units = wx.StaticText( self, -1, "seconds" ) self.grid.Add( self.exposure_time_units, pos=(0,2), \ flag=wx.ALIGN_CENTER ) self.SetSizer( self.grid ) def mpad_start_one_shot( panel ): value = panel.exposure_time_ctrl.GetValue() seconds = float(value) print "Starting one-shot exposure for %g seconds." % seconds _mpad.ad_record.set_one_shot_mode( seconds ) _mpad.ad_record.start() _mpad.is_busy = True #------------------------------------------------------------------------------ class MpadContinuousPanel(wx.Panel): def __init__( self, parent, command ): wx.Panel.__init__( self, parent ) self.parent = parent self.command = command self.grid = wx.GridBagSizer() #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.exposure_time_label = \ wx.StaticText( self, -1, "Exposure Time Per Frame: " ) self.grid.Add( self.exposure_time_label, pos=(0,0), \ flag=wx.ALIGN_CENTER ) self.exposure_time_ctrl = wx.TextCtrl( self, \ validator = MpadFloatValidator() ) self.grid.Add( self.exposure_time_ctrl, pos=(0,1), \ border=5, flag=wx.RIGHT ) self.exposure_time_units = wx.StaticText( self, -1, "seconds" ) self.grid.Add( self.exposure_time_units, pos=(0,2), \ flag=wx.ALIGN_CENTER ) self.SetSizer( self.grid ) def mpad_start_continuous( panel ): value = panel.exposure_time_ctrl.GetValue() seconds = float(value) print "Starting continuous exposure for %g seconds per frame." % seconds _mpad.ad_record.set_continuous_mode( seconds ) _mpad.ad_record.start() _mpad.is_busy = True #------------------------------------------------------------------------------ class MpadMultiframePanel(wx.Panel): def __init__( self, parent, command ): wx.Panel.__init__( self, parent ) self.parent = parent self.command = command self.grid = wx.GridBagSizer() #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.num_frames_label = \ wx.StaticText( self, -1, "Number of Frames: " ) self.grid.Add( self.num_frames_label, pos=(0,0), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.num_frames_ctrl = wx.TextCtrl( self, \ validator = MpadFloatValidator() ) self.grid.Add( self.num_frames_ctrl, pos=(0,1), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.exposure_time_label = \ wx.StaticText( self, -1, "Exposure Time: " ) self.grid.Add( self.exposure_time_label, pos=(1,0), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.exposure_time_ctrl = wx.TextCtrl( self, \ validator = MpadFloatValidator() ) self.grid.Add( self.exposure_time_ctrl, pos=(1,1), border=5, \ flag=(wx.RIGHT | wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.exposure_time_units = wx.StaticText( self, -1, "seconds" ) self.grid.Add( self.exposure_time_units, pos=(1,2), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.frame_time_label = \ wx.StaticText( self, -1, "Frame Time: " ) self.grid.Add( self.frame_time_label, pos=(2,0), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.frame_time_ctrl = wx.TextCtrl( self, \ validator = MpadFloatValidator() ) self.grid.Add( self.frame_time_ctrl, pos=(2,1), border=5, \ flag=(wx.RIGHT | wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.frame_time_units = wx.StaticText( self, -1, "seconds" ) self.grid.Add( self.frame_time_units, pos=(2,2), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.SetSizer( self.grid ) def mpad_start_multiframe( panel ): num_frames = int( panel.num_frames_ctrl.GetValue() ) exposure_seconds = float( panel.exposure_time_ctrl.GetValue() ) frame_seconds = float( panel.frame_time_ctrl.GetValue() ) print \ "Starting multiframe exposure for %d frames, exposure time %g, frame time %g" \ % ( num_frames, exposure_seconds, frame_seconds ) _mpad.ad_record.set_multiframe_mode( num_frames, \ exposure_seconds, frame_seconds ) _mpad.ad_record.start() _mpad.is_busy = True #------------------------------------------------------------------------------ class MpadCircularMultiframePanel(wx.Panel): def __init__( self, parent, command ): wx.Panel.__init__( self, parent ) self.parent = parent self.command = command self.grid = wx.GridBagSizer() #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.num_frames_label = \ wx.StaticText( self, -1, "Number of Frames: " ) self.grid.Add( self.num_frames_label, pos=(0,0), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.num_frames_ctrl = wx.TextCtrl( self, \ validator = MpadFloatValidator() ) self.grid.Add( self.num_frames_ctrl, pos=(0,1), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.exposure_time_label = \ wx.StaticText( self, -1, "Exposure Time: " ) self.grid.Add( self.exposure_time_label, pos=(1,0), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.exposure_time_ctrl = wx.TextCtrl( self, \ validator = MpadFloatValidator() ) self.grid.Add( self.exposure_time_ctrl, pos=(1,1), border=5, \ flag=(wx.RIGHT | wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.exposure_time_units = wx.StaticText( self, -1, "seconds" ) self.grid.Add( self.exposure_time_units, pos=(1,2), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.frame_time_label = \ wx.StaticText( self, -1, "Frame Time: " ) self.grid.Add( self.frame_time_label, pos=(2,0), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.frame_time_ctrl = wx.TextCtrl( self, \ validator = MpadFloatValidator() ) self.grid.Add( self.frame_time_ctrl, pos=(2,1), border=5, \ flag=(wx.RIGHT | wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.frame_time_units = wx.StaticText( self, -1, "seconds" ) self.grid.Add( self.frame_time_units, pos=(2,2), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.SetSizer( self.grid ) def mpad_start_circular_multiframe( panel ): num_frames = int( panel.num_frames_ctrl.GetValue() ) exposure_seconds = float( panel.exposure_time_ctrl.GetValue() ) frame_seconds = float( panel.frame_time_ctrl.GetValue() ) print \ "Starting circular multiframe exposure for %d frames, exposure time %g, frame time %g" \ % ( num_frames, exposure_seconds, frame_seconds ) _mpad.ad_record.set_circular_multiframe_mode( num_frames, \ exposure_seconds, frame_seconds ) _mpad.ad_record.start() _mpad.is_busy = True #------------------------------------------------------------------------------ class MpadStrobePanel(wx.Panel): def __init__( self, parent, command ): wx.Panel.__init__( self, parent ) self.parent = parent self.command = command self.grid = wx.GridBagSizer() #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.num_frames_label = \ wx.StaticText( self, -1, "Number of Frames: " ) self.grid.Add( self.num_frames_label, pos=(0,0), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.num_frames_ctrl = wx.TextCtrl( self, \ validator = MpadFloatValidator() ) self.grid.Add( self.num_frames_ctrl, pos=(0,1), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.exposure_time_label = \ wx.StaticText( self, -1, "Exposure Time: " ) self.grid.Add( self.exposure_time_label, pos=(1,0), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.exposure_time_ctrl = wx.TextCtrl( self, \ validator = MpadFloatValidator() ) self.grid.Add( self.exposure_time_ctrl, pos=(1,1), border=5, \ flag=(wx.RIGHT | wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.exposure_time_units = wx.StaticText( self, -1, "seconds" ) self.grid.Add( self.exposure_time_units, pos=(1,2), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.SetSizer( self.grid ) def mpad_start_strobe( panel ): num_frames = int( panel.num_frames_ctrl.GetValue() ) exposure_seconds = float( panel.exposure_time_ctrl.GetValue() ) print "Starting strobe exposure for %d frames, exposure time %g second"\ % ( num_frames, exposure_seconds ) _mpad.ad_record.set_strobe_mode( num_frames, exposure_seconds ) _mpad.ad_record.start() _mpad.is_busy = True #------------------------------------------------------------------------------ class MpadDurationPanel(wx.Panel): def __init__( self, parent, command ): wx.Panel.__init__( self, parent ) self.parent = parent self.command = command self.grid = wx.GridBagSizer() #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.num_frames_label = \ wx.StaticText( self, -1, "Number of Frames: " ) self.grid.Add( self.num_frames_label, pos=(0,0), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.num_frames_ctrl = wx.TextCtrl( self, \ validator = MpadFloatValidator() ) self.grid.Add( self.num_frames_ctrl, pos=(0,1), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.SetSizer( self.grid ) def mpad_start_duration( panel ): num_frames = int( panel.num_frames_ctrl.GetValue() ) print "Starting duration exposure for %d frames" % num_frames _mpad.ad_record.set_duration_mode( num_frames ) _mpad.ad_record.start() _mpad.is_busy = True #------------------------------------------------------------------------------ class MpadGeometricalPanel(wx.Panel): def __init__( self, parent, command ): wx.Panel.__init__( self, parent ) self.parent = parent self.command = command self.grid = wx.GridBagSizer() #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.num_frames_label = \ wx.StaticText( self, -1, "Number of Frames: " ) self.grid.Add( self.num_frames_label, pos=(0,0), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.num_frames_ctrl = wx.TextCtrl( self, \ validator = MpadFloatValidator() ) self.grid.Add( self.num_frames_ctrl, pos=(0,1), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.exposure_time_label = \ wx.StaticText( self, -1, "Exposure Time: " ) self.grid.Add( self.exposure_time_label, pos=(1,0), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.exposure_time_ctrl = wx.TextCtrl( self, \ validator = MpadFloatValidator() ) self.grid.Add( self.exposure_time_ctrl, pos=(1,1), border=5, \ flag=(wx.RIGHT | wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.exposure_time_units = wx.StaticText( self, -1, "seconds" ) self.grid.Add( self.exposure_time_units, pos=(1,2), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.gap_time_label = \ wx.StaticText( self, -1, "Gap Time: " ) self.grid.Add( self.gap_time_label, pos=(2,0), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.gap_time_ctrl = wx.TextCtrl( self, \ validator = MpadFloatValidator() ) self.grid.Add( self.gap_time_ctrl, pos=(2,1), border=5, \ flag=(wx.RIGHT | wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.gap_time_units = wx.StaticText( self, -1, "seconds" ) self.grid.Add( self.gap_time_units, pos=(2,2), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.exposure_multiplier_label = \ wx.StaticText( self, -1, "Exposure Multiplier: " ) self.grid.Add( self.exposure_multiplier_label, pos=(3,0), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.exposure_multiplier_ctrl = wx.TextCtrl( self, \ validator = MpadFloatValidator() ) self.grid.Add( self.exposure_multiplier_ctrl, \ pos=(3,1), border=5, \ flag=(wx.RIGHT | wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.gap_multiplier_label = \ wx.StaticText( self, -1, "Gap Multiplier: " ) self.grid.Add( self.gap_multiplier_label, pos=(4,0), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.gap_multiplier_ctrl = wx.TextCtrl( self, \ validator = MpadFloatValidator() ) self.grid.Add( self.gap_multiplier_ctrl, pos=(4,1), border=5, \ flag=(wx.RIGHT | wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.gap_multiplier_units = wx.StaticText( self, -1, "seconds" ) self.grid.Add( self.gap_multiplier_units, pos=(4,2), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.SetSizer( self.grid ) def mpad_start_geometrical( panel ): num_frames = int( panel.num_frames_ctrl.GetValue() ) exposure_seconds = float( panel.exposure_time_ctrl.GetValue() ) gap_seconds = float( panel.gap_time_ctrl.GetValue() ) exposure_multiplier = float( panel.exposure_multiplier_ctrl.GetValue() ) gap_multiplier = float( panel.gap_multiplier_ctrl.GetValue() ) print \ "Starting geometrical exposure for %d frames, exposure time %g, gap time %g, " \ "exposure multiplier %g, gap multiplier %g" \ % ( num_frames, exposure_seconds, gap_seconds, \ exposure_multiplier, gap_multiplier ) _mpad.ad_record.set_geometrical_mode( num_frames, \ exposure_seconds, gap_seconds, \ exposure_multiplier, gap_multiplier ) _mpad.ad_record.start() _mpad.is_busy = True #============================================================================= class MpadShutterControlPanel(wx.Panel): def __init__( self, parent ): wx.Panel.__init__( self, parent ) self.parent = parent self.grid = wx.GridBagSizer( hgap=5, vgap=5 ) self.SetSizer( self.grid ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # # FIXME - We should get this shutter dictionary from # some beamline specific file. # self.shutter_dict = { 'Script Shutter':'script_shutter', \ 'X-Ray Shutter':'xray_shutter' } #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.label = wx.StaticText( self, -1, "Shutter: " ) self.grid.Add( self.label, pos=(0,0), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.shutter_selector = wx.Choice( self, -1, \ choices=self.shutter_dict.keys() ); self.Bind( wx.EVT_CHOICE, self.OnSelect, self.shutter_selector ) self.grid.Add( self.shutter_selector, pos=(0,1), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) #----- # Start out by selecting the first record in the dictionary. selection = self.shutter_dict.keys()[0] self.register_selection( selection ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - self.shutter_button = wx.Button( self, \ label="________________" ) self.grid.Add( self.shutter_button, pos=(1,1), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) self.Bind( wx.EVT_BUTTON, self.OnShutterButton, \ self.shutter_button ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # FIXME - It doesn't look like a real LED. self.shutter_led = wx.lib.stattext.GenStaticText( self, \ -1, "", size=(20,20) ) self.shutter_led.SetBackgroundColour( "white" ) self.grid.Add( self.shutter_led, pos=(1,2), \ flag=(wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ) #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - wx.FutureCall( 500, self.shutter_monitor ); #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def OnShutterButton( self, event ): if ( self.shutter_status == 0 ): _mpad.shutter_record.relay_command( 1 ) elif ( self.shutter_status == 1 ): _mpad.shutter_record.relay_command( 0 ) else: print "Nothing happened." def shutter_monitor( self ): try: # Get the status of the currently selected shutter. self.shutter_status = \ _mpad.shutter_record.get_relay_status() if ( self.shutter_status == 0 ): self.shutter_led.SetBackgroundColour("red") self.shutter_button.SetLabel("Close Shutter") elif ( self.shutter_status == 1 ): self.shutter_led.SetBackgroundColour("black") self.shutter_button.SetLabel("Open Shutter") else: self.shutter_led.SetBackgroundColour("yellow") self.shutter_button.SetLabel("Xyzzy") self.shutter_button.Enable(True) except: pass wx.FutureCall( 500, self.shutter_monitor ); #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def OnSelect( self, event ): selection = event.GetString() # Disable the button until the next call to shutter_monitor(). self.shutter_button.Enable(False) # Look for the selected shutter record. self.register_selection( selection ) def register_selection( self, selection ): record_name = self.shutter_dict[selection] try: _mpad.shutter_record = \ _mpad.record_list.get_record(record_name) except Mp.Not_Found_Error: _mpad.shutter_record = None print "Error: The shutter record '%s' was not found." \ % ( record_name ) #============================================================================= # # The MpadTimer class is used to implement periodic checks of the hardware. # class MpadTimer(wx.Timer): def __init__( self, owner ): wx.Timer.__init__( self, owner, id=-1 ) owner.Bind( wx.EVT_TIMER, self.OnTimerEvent, self ) def OnTimerEvent( self, timer_event ): ### print "vvv======= OnTimerEvent() invoked =======vvv" try: _mpad.record_list.wait_for_messages( 0.1 ) except Mp.Timed_Out_Error: pass ### print "^^^======= OnTimerEvent() complete ======^^^" #============================================================================= class MpadValueText(wx.TextCtrl): def __init__( self, parent, window_id, initial_text ): wx.TextCtrl.__init__( self, parent, \ id=window_id, value=initial_text, \ style=wx.TE_READONLY|wx.NO_BORDER ) self.parent = parent self.SetBackgroundColour( self.parent.GetBackgroundColour() ) def SetValue( self, value ): string_value = str(value) wx.TextCtrl.SetValue( self, string_value ) # wx.TextCtrl.SetForegroundColour( self, wx.Colour(255,0,0) ) #------------------------------------------------------------------------ class MpadFloatValidator(wx.PyValidator): ''' MpadFloatValidator() checks for valid numerical characters in a text entry field. It also permits editing characters like backspace, delete, and so forth. ''' def __init__( self ): wx.PyValidator.__init__(self) self.valid_keycodes = [ wx.WXK_DELETE, wx.WXK_BACK, \ wx.WXK_HOME, wx.WXK_END, \ wx.WXK_LEFT, wx.WXK_RIGHT, \ wx.WXK_INSERT ] self.valid_chars = '0123456789-.eE' self.Bind( wx.EVT_CHAR, self.OnChar ) def Clone( self ): return MpadFloatValidator() def Validate( self, window ): return True def TransferToWindow( self ): return True def TransferFromWindow( self ): return True def OnChar( self, event ): keycode = event.GetKeyCode() # Is this a valid keycode? if ( keycode in self.valid_keycodes ): # This keycode is valid so let it through. event.Skip() return # Is this a valid character for a number? try: key = chr( keycode ) if ( key in self.valid_chars ): # This key is valid, so let it through. event.Skip() return # This key is not valid. pass except: # The keycode was not in the valid range for chr(). pass # # If we get here, the key the user typed was not valid # for editing a floating point number, so we discard # the keycode event without passing it on. # # # FIXME: We should beep here to tell the user that # the key is invalid. # return #------------------------------------------------------------------------ def rebin( a, newshape ): ''' Rebin an array to a new shape. newshape must be a factor of shape. This came from http://scipy.org/Cookbook/Rebinning ''' assert len(a.shape) == len(newshape) slices = [ slice(None,None, old/new) \ for old,new in zip(a.shape,newshape) ] return a[slices] #----------------------------------------------------------------------------- def get_server_frame_type( selection ): if ( selection == 0 ): server_frame_type = Mp.MXFT_AD_IMAGE_FRAME elif ( selection == 1 ): server_frame_type = Mp.MXFT_AD_MASK_FRAME elif ( selection == 2 ): server_frame_type = Mp.MXFT_AD_BIAS_FRAME elif ( selection == 3 ): server_frame_type = Mp.MXFT_AD_DARK_CURRENT_FRAME elif ( selection == 4 ): server_frame_type = Mp.MXFT_AD_FLOOD_FIELD_FRAME else: msg = "Illegal server frame type %d requested." % selection raise Mp.CorruptDataStructureError, msg return server_frame_type #------------------------------------------------------------------------ def get_frame_from_server( frame_type, frame_number ): start_time = time.clock() # print "get_frame_from_server() invoked." # print "frame_type =", frame_type, " frame_number =", frame_number if ( frame_type == Mp.MXFT_AD_IMAGE_FRAME ): frame_name = 'image' elif ( frame_type == Mp.MXFT_AD_MASK_FRAME ): frame_name = 'mask' elif ( frame_type == Mp.MXFT_AD_BIAS_FRAME ): frame_name = 'bias' elif ( frame_type == Mp.MXFT_AD_DARK_CURRENT_FRAME ): frame_name = 'dark current' elif ( frame_type == Mp.MXFT_AD_FLOOD_FIELD_FRAME ): frame_name = 'flood field' else: msg = "Unsupported frame type %x requested." % frame_type raise Mp.IllegalArgumentError, msg print "Reading %s frame, frame number %d" \ % ( frame_name, frame_number ) ad = _mpad.ad_record if ( frame_type == Mp.MXFT_AD_IMAGE_FRAME ): ad.setup_frame( _mpad.image_frame ) ad.readout_frame( frame_number ) ad.correct_frame() ad.transfer_frame( frame_type, _mpad.image_frame ) else: ad.transfer_frame( frame_type, _mpad.image_frame ) print "Frame read." wxt_panel = _mpad.frame.image_tab.wxt_panel frame_read_end_time = time.clock() wxt_panel.SetData( _mpad.image_frame ) convert_end_time = time.clock() wxt_panel.Display() display_end_time = time.clock() # print "frame read time = %f sec" % (frame_read_end_time - start_time) # print "convert time = %f sec" % (convert_end_time - frame_read_end_time) # print "display time = %f sec" % (display_end_time - convert_end_time) #============================================================================= class MpadWxtImagePanel(wx.Panel): def __init__( self, parent ): wx.Panel.__init__( self, parent ) self.parent = parent self.box = wx.BoxSizer( wx.VERTICAL ) self.image_foo = WxtImage.ImagePanel( self, size=(1024,1024) ) self.box.Add( self.image_foo, 20, wx.EXPAND, border=10 ) self.image_position = wx.StaticText( self, -1, label="XYZZY" ) self.box.Add( self.image_position, 1, wx.ALIGN_LEFT, border=10 ) self.SetSizer( self.box ) self.Bind( wx.EVT_SIZE, self.OnSize ) self.image_foo.SetPositionWindow( self.image_position ) self.contrast_panel = MpadContrastPanel( self ) self.box.Add( self.contrast_panel, 1, wx.ALIGN_LEFT, border=0 ) def SetData( self, mp_image_frame ): binary_string = mp_image_frame.get_image_data() # print "SetData: len(binary_string) =", len(binary_string) # print "SetData: mp_image_frame.framesize =", \ # mp_image_frame.framesize # print "SetData: ad.binsize =", _mpad.ad_record.get_binsize() # print "SetData: ad.framesize =", _mpad.ad_record.get_framesize() raw_pil_image = Image.fromstring( "F", \ mp_image_frame.framesize, \ binary_string, \ "raw", "F;16N" ) # print "MpadWxtImagePanel: SetData(): raw_size =", \ # raw_pil_image.size self.image_foo.SetData( raw_pil_image ) def Display( self ): # print "MpadWxtImagePanel: Display() invoked." self.image_foo.Display() def OnSize( self, event ): # print "MpadWxtImagePanel: OnSize(): size =", self.GetSize() event.Skip()