import wx import sys from sas.sasgui.perspectives.calculator import calculator_widgets as widget from sas.sasgui.perspectives.file_converter.converter_widgets import VectorInput from wx.lib.scrolledpanel import ScrolledPanel from sas.sasgui.guiframe.panel_base import PanelBase from sas.sascalc.dataloader.data_info import Detector from sas.sasgui.guiframe.events import StatusEvent from sas.sasgui.guiframe.utils import check_float if sys.platform.count("win32") > 0: PANEL_TOP = 0 _STATICBOX_WIDTH = 350 PANEL_SIZE = 440 FONT_VARIANT = 0 else: PANEL_TOP = 60 _STATICBOX_WIDTH = 380 PANEL_SIZE = 470 FONT_VARIANT = 1 class MetadataPanel(ScrolledPanel, PanelBase): """ A common base class to be extended by panels that deal with metadata input. Handles input validation and passing inputted data back to ConverterPanel. """ def __init__(self, parent, metadata, base=None, *args, **kwargs): ScrolledPanel.__init__(self, parent, *args, **kwargs) PanelBase.__init__(self) self.SetupScrolling() self.SetWindowVariant(variant=FONT_VARIANT) self.base = base self.parent = parent self._to_validate = [] # An list of inputs that should contain floats self._vectors = [] # A list of VectorInputs to be validated self.metadata = metadata def get_property_string(self, name, is_float=False): value = getattr(self.metadata, name) if value is None or value == []: value = '' is_float = False if isinstance(value, list): value = value[0] value = str(value) if is_float and not '.' in value: value += '.0' return value def on_change(self, event): ctrl = event.GetEventObject() value = ctrl.GetValue() name = ctrl.GetName() old_value = getattr(self.metadata, name) if value == '': value = None if isinstance(old_value, list): value = [value] setattr(self.metadata, name, value) def on_close(self, event=None): for ctrl in self._to_validate: ctrl.SetBackgroundColour(wx.WHITE) if ctrl.GetValue() == '': continue if not check_float(ctrl): msg = "{} must be a valid float".format( ctrl.GetName().replace("_", " ")) wx.PostEvent(self.parent.manager.parent.manager.parent, StatusEvent(status=msg, info='error')) return False for vector_in in self._vectors: is_valid, invalid_ctrl = vector_in.Validate() if not is_valid: msg = "{} must be a valid float".format( invalid_ctrl.GetName().replace("_", " ")) wx.PostEvent(self.parent.manager.parent.manager.parent, StatusEvent(status=msg, info='error')) return False setattr(self.metadata, vector_in.GetName(), vector_in.GetValue()) return True class DetectorPanel(MetadataPanel): def __init__(self, parent, detector, base=None, *args, **kwargs): if detector.name is None: detector.name = '' MetadataPanel.__init__(self, parent, detector, base, *args, **kwargs) self._do_layout() self.SetAutoLayout(True) self.Layout() def on_close(self, event=None): if not MetadataPanel.on_close(self, event): return self.parent.manager.detector = self.metadata self.parent.on_close(event) def _do_layout(self): vbox = wx.BoxSizer(wx.VERTICAL) section = wx.StaticBox(self, -1, "Detector") section_sizer = wx.StaticBoxSizer(section, wx.VERTICAL) section_sizer.SetMinSize((_STATICBOX_WIDTH, -1)) input_grid = wx.GridBagSizer(5, 5) y = 0 name_label = wx.StaticText(self, -1, "Name: ") input_grid.Add(name_label, (y,0), (1,1), wx.ALL, 5) name_input = wx.TextCtrl(self, -1, name="name") input_grid.Add(name_input, (y,1), (1,1)) name_input.Bind(wx.EVT_TEXT, self.on_change) y += 1 distance_label = wx.StaticText(self, -1, "Distance (mm): ") input_grid.Add(distance_label, (y, 0), (1,1), wx.ALL, 5) distance_input = wx.TextCtrl(self, -1, name="distance", size=(50,-1)) input_grid.Add(distance_input, (y,1), (1,1)) distance_input.Bind(wx.EVT_TEXT, self.on_change) self._to_validate.append(distance_input) y += 1 offset_label = wx.StaticText(self, -1, "Offset (mm): ") input_grid.Add(offset_label, (y,0), (1,1), wx.ALL, 5) offset_input = VectorInput(self, "offset") input_grid.Add(offset_input.GetSizer(), (y,1), (1,1)) self._vectors.append(offset_input) y += 1 orientation_label = wx.StaticText(self, -1, "Orientation (\xb0): ") input_grid.Add(orientation_label, (y,0), (1,1), wx.ALL, 5) orientation_input = VectorInput(self, "orientation", z_enabled=True, labels=["Roll: ", "Pitch: ", "Yaw: "]) input_grid.Add(orientation_input.GetSizer(), (y,1), (1,1)) self._vectors.append(orientation_input) y += 1 pixel_label = wx.StaticText(self, -1, "Pixel Size (mm): ") input_grid.Add(pixel_label, (y,0), (1,1), wx.ALL, 5) pixel_input = VectorInput(self, "pixel_size") input_grid.Add(pixel_input.GetSizer(), (y,1), (1,1)) self._vectors.append(pixel_input) y += 1 beam_label = wx.StaticText(self, -1, "Beam Center (mm): ") input_grid.Add(beam_label, (y,0), (1,1), wx.ALL, 5) beam_input = VectorInput(self, "beam_center") input_grid.Add(beam_input.GetSizer(), (y,1), (1,1)) self._vectors.append(beam_input) y += 1 slit_label = wx.StaticText(self, -1, "Slit Length (mm): ") input_grid.Add(slit_label, (y,0), (1,1), wx.ALL, 5) slit_input = wx.TextCtrl(self, -1, name="slit_length", size=(50,-1)) input_grid.Add(slit_input, (y,1), (1,1)) slit_input.Bind(wx.EVT_TEXT, self.on_change) self._to_validate.append(slit_input) y += 1 done_btn = wx.Button(self, -1, "Done") input_grid.Add(done_btn, (y,0), (1,1), wx.ALL, 5) done_btn.Bind(wx.EVT_BUTTON, self.on_close) section_sizer.Add(input_grid) vbox.Add(section_sizer, flag=wx.ALL, border=10) name_input.SetValue(self.metadata.name) distance = self.get_property_string("distance", is_float=True) distance_input.SetValue(distance) offset_input.SetValue(self.metadata.offset) orientation_input.SetValue(self.metadata.orientation) pixel_input.SetValue(self.metadata.pixel_size) beam_input.SetValue(self.metadata.beam_center) slit_len = self.get_property_string("slit_length", is_float=True) slit_input.SetValue(slit_len) vbox.Fit(self) self.SetSizer(vbox) class SamplePanel(MetadataPanel): def __init__(self, parent, sample, base=None, *args, **kwargs): MetadataPanel.__init__(self, parent, sample, base, *args, **kwargs) if sample.name is None: sample.name = '' self._do_layout() self.SetAutoLayout(True) self.Layout() def on_close(self, event=None): if not MetadataPanel.on_close(self, event): return self.parent.manager.sample = self.metadata self.parent.on_close(event) def _do_layout(self): vbox = wx.BoxSizer(wx.VERTICAL) section = wx.StaticBox(self, -1, "Sample") section_sizer = wx.StaticBoxSizer(section, wx.VERTICAL) section_sizer.SetMinSize((_STATICBOX_WIDTH, -1)) input_grid = wx.GridBagSizer(5, 5) y = 0 name_label = wx.StaticText(self, -1, "Name: ") input_grid.Add(name_label, (y,0), (1,1), wx.ALL, 5) name_input = wx.TextCtrl(self, -1, name="name") input_grid.Add(name_input, (y,1), (1,1)) name_input.Bind(wx.EVT_TEXT, self.on_change) y += 1 thickness_label = wx.StaticText(self, -1, "Thickness (mm): ") input_grid.Add(thickness_label, (y,0), (1,1), wx.ALL, 5) thickness_input = wx.TextCtrl(self, -1, name="thickness") input_grid.Add(thickness_input, (y,1), (1,1)) thickness_input.Bind(wx.EVT_TEXT, self.on_change) self._to_validate.append(thickness_input) y += 1 transmission_label = wx.StaticText(self, -1, "Transmission: ") input_grid.Add(transmission_label, (y,0), (1,1), wx.ALL, 5) transmission_input = wx.TextCtrl(self, -1, name="transmission") input_grid.Add(transmission_input, (y,1), (1,1)) transmission_input.Bind(wx.EVT_TEXT, self.on_change) self._to_validate.append(transmission_input) y += 1 temperature_label = wx.StaticText(self, -1, "Temperature: ") input_grid.Add(temperature_label, (y,0), (1,1), wx.ALL, 5) temperature_input = wx.TextCtrl(self, -1, name="temperature") temperature_input.Bind(wx.EVT_TEXT, self.on_change) self._to_validate.append(temperature_input) input_grid.Add(temperature_input, (y,1), (1,1)) temp_unit_label = wx.StaticText(self, -1, "Unit: ") input_grid.Add(temp_unit_label, (y,2), (1,1)) temp_unit_input = wx.TextCtrl(self, -1, name="temperature_unit", size=(50,-1)) temp_unit_input.Bind(wx.EVT_TEXT, self.on_change) input_grid.Add(temp_unit_input, (y,3), (1,1)) y += 1 position_label = wx.StaticText(self, -1, "Position (mm): ") input_grid.Add(position_label, (y,0), (1,1), wx.ALL, 5) position_input = VectorInput(self, "position") self._vectors.append(position_input) input_grid.Add(position_input.GetSizer(), (y,1), (1,2)) y += 1 orientation_label = wx.StaticText(self, -1, "Orientation (\xb0): ") input_grid.Add(orientation_label, (y,0), (1,1), wx.ALL, 5) orientation_input = VectorInput(self, "orientation", labels=["Roll: ", "Pitch: ", "Yaw: "], z_enabled=True) self._vectors.append(orientation_input) input_grid.Add(orientation_input.GetSizer(), (y,1), (1,3)) y += 1 details_label = wx.StaticText(self, -1, "Details: ") input_grid.Add(details_label, (y,0), (1,1), wx.ALL, 5) details_input = wx.TextCtrl(self, -1, name="details", style=wx.TE_MULTILINE) input_grid.Add(details_input, (y,1), (3,3), wx.EXPAND) y += 3 name_input.SetValue(self.metadata.name) thickness_input.SetValue( self.get_property_string("thickness", is_float=True)) transmission_input.SetValue( self.get_property_string("transmission", is_float=True)) temperature_input.SetValue( self.get_property_string("temperature", is_float=True)) temp_unit_input.SetValue(self.get_property_string("temperature_unit")) position_input.SetValue(self.metadata.position) orientation_input.SetValue(self.metadata.orientation) details_input.SetValue(self.get_property_string("details")) details_input.Bind(wx.EVT_TEXT, self.on_change) done_btn = wx.Button(self, -1, "Done") input_grid.Add(done_btn, (y,0), (1,1), wx.ALL, 5) done_btn.Bind(wx.EVT_BUTTON, self.on_close) section_sizer.Add(input_grid) vbox.Add(section_sizer, flag=wx.ALL, border=10) vbox.Fit(self) self.SetSizer(vbox) class SourcePanel(MetadataPanel): def __init__(self, parent, source, base=None, *args, **kwargs): MetadataPanel.__init__(self, parent, source, base, *args, **kwargs) if source.name is None: source.name = '' source.wavelength_unit = 'nm' self._do_layout() self.SetAutoLayout(True) self.Layout() def on_close(self, event=None): if not MetadataPanel.on_close(self, event): return self.parent.manager.source = self.metadata self.parent.on_close(event) def _do_layout(self): vbox = wx.BoxSizer(wx.VERTICAL) section = wx.StaticBox(self, -1, "Source") section_sizer = wx.StaticBoxSizer(section, wx.VERTICAL) section_sizer.SetMinSize((_STATICBOX_WIDTH, -1)) input_grid = wx.GridBagSizer(5, 5) y = 0 name_label = wx.StaticText(self, -1, "Name: ") input_grid.Add(name_label, (y,0), (1,1), wx.ALL, 5) name_input = wx.TextCtrl(self, -1, name="name") input_grid.Add(name_input, (y,1), (1,1)) name_input.Bind(wx.EVT_TEXT, self.on_change) y += 1 size_label = wx.StaticText(self, -1, "Beam Size (mm): ") input_grid.Add(size_label, (y,0), (1,1), wx.ALL, 5) size_input = VectorInput(self, "beam_size") self._vectors.append(size_input) input_grid.Add(size_input.GetSizer(), (y,1), (1,1)) y += 1 shape_label = wx.StaticText(self, -1, "Beam Shape: ") input_grid.Add(shape_label, (y,0), (1,1), wx.ALL, 5) shape_input = wx.TextCtrl(self, -1, name="beam_shape") shape_input.Bind(wx.EVT_TEXT, self.on_change) input_grid.Add(shape_input, (y,1), (1,1)) y += 1 wavelength_label = wx.StaticText(self, -1, "Wavelength (nm): ") input_grid.Add(wavelength_label, (y,0), (1,1), wx.ALL, 5) wavelength_input = wx.TextCtrl(self, -1, name="wavelength", size=(50,-1)) wavelength_input.Bind(wx.EVT_TEXT, self.on_change) self._to_validate.append(wavelength_input) input_grid.Add(wavelength_input, (y,1), (1,1)) y += 1 min_wavelength_label = wx.StaticText(self, -1, "Min. Wavelength (nm): ") input_grid.Add(min_wavelength_label, (y,0), (1,1), wx.ALL, 5) min_wavelength_input = wx.TextCtrl(self, -1, name="wavelength_min", size=(50,-1)) min_wavelength_input.Bind(wx.EVT_TEXT, self.on_change) self._to_validate.append(min_wavelength_input) input_grid.Add(min_wavelength_input, (y,1), (1,1)) y += 1 max_wavelength_label = wx.StaticText(self, -1, "Max. Wavelength (nm): ") input_grid.Add(max_wavelength_label, (y,0), (1,1), wx.ALL, 5) max_wavelength_input = wx.TextCtrl(self, -1, name="wavelength_max", size=(50,-1)) max_wavelength_input.Bind(wx.EVT_TEXT, self.on_change) self._to_validate.append(max_wavelength_input) input_grid.Add(max_wavelength_input, (y,1), (1,1)) y += 1 wavelength_spread_label = wx.StaticText(self, -1, "Wavelength Spread (%): ") input_grid.Add(wavelength_spread_label, (y,0), (1,1), wx.ALL, 5) wavelength_spread_input = wx.TextCtrl(self, -1, name="wavelength_spread", size=(50,-1)) wavelength_spread_input.Bind(wx.EVT_TEXT, self.on_change) self._to_validate.append(wavelength_spread_input) input_grid.Add(wavelength_spread_input, (y,1), (1,1)) y += 1 name_input.SetValue(self.get_property_string("name")) size_input.SetValue(self.metadata.beam_size) shape_input.SetValue(self.get_property_string("beam_shape")) wavelength_input.SetValue( self.get_property_string("wavelength", is_float=True)) min_wavelength_input.SetValue( self.get_property_string("wavelength_min", is_float=True)) max_wavelength_input.SetValue( self.get_property_string("wavelength_max", is_float=True)) done_btn = wx.Button(self, -1, "Done") input_grid.Add(done_btn, (y,0), (1,1), wx.ALL, 5) done_btn.Bind(wx.EVT_BUTTON, self.on_close) section_sizer.Add(input_grid) vbox.Add(section_sizer, flag=wx.ALL, border=10) vbox.Fit(self) self.SetSizer(vbox) class MetadataWindow(widget.CHILD_FRAME): def __init__(self, PanelClass, parent=None, title='', base=None, manager=None, size=(PANEL_SIZE, PANEL_SIZE*0.8), metadata=None, *args, **kwargs): kwargs['title'] = title kwargs['size'] = size widget.CHILD_FRAME.__init__(self, parent, *args, **kwargs) self.manager = manager self.panel = PanelClass(self, metadata, base=None) self.Bind(wx.EVT_CLOSE, self.on_close) def on_close(self, event): if self.manager is not None: self.manager.meta_frames.remove(self) self.Destroy()