class PanelContainer(wx.Panel): """This contains a preference panel. This container has the ability to hold several panels, and to be able to switch between them. For some modes, however, the container will only hold a single panel. Each page has a title area, and an area for a preferences panel """ def __init__(self, *args, **kwargs): super(PanelContainer, self).__init__(*args, **kwargs) self._current_panel = None self.title = wx.StaticText(self, label="Your message here") # self.panels_container = wx.Panel(self) self.panels_container = ScrolledPanel(self, wx.ID_ANY, style=wx.TAB_TRAVERSAL) self.panels_container.SetupScrolling() sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.title, 0, wx.TOP | wx.LEFT | wx.EXPAND, 4) sizer.Add(wx.StaticLine(self), 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 4) sizer.Add(self.panels_container, 1, wx.EXPAND) # sizer.Add(self._create_body(), 1, flag=wx.EXPAND | wx.ALL, border=16) self.SetSizer(sizer) self.panels_container.SetSizer(wx.BoxSizer(wx.VERTICAL)) font = self.title.GetFont() font.SetPointSize(font.GetPointSize() + 2) self.title.SetFont(font) self.title.SetForegroundColour("#000000") def AddPanel(self, panel_class, settings): """Add a panel to the dialog""" panel = panel_class(parent=self.panels_container, settings=settings) self.panels_container.GetSizer().Add(panel, 1, wx.EXPAND) return panel def ShowPanel(self, panel): """Arrange for the given panel to be shown""" if self._current_panel is not None: self._current_panel.Hide() self._current_panel = panel panel.Show() sizer = self.panels_container.GetSizer() item = sizer.GetItem(panel) title = getattr(panel, "title", panel.location[-1]) self.title.SetLabel(title) if item is None: sizer.Add(panel, 1, wx.EXPAND) sizer.Layout() def SetTitle(self, title): """Set the title of the panel""" self.title.SetLabel(title)
class InjectionInputsPanel(pdsim_panels.PDPanel): """ The container panel for all the injection ports and injection data """ def __init__(self, parent, **kwargs): pdsim_panels.PDPanel.__init__(self, parent, **kwargs) #Now we are going to put everything into a scrolled window main_sizer = wx.BoxSizer(wx.VERTICAL) self.scrolled_panel = ScrolledPanel(self, size=(-1, -1), style=wx.TAB_TRAVERSAL, name="panel1") self.scrolled_panel.SetScrollbars(1, 1, 1, 1) self.scrolled_panel.SetupScrolling() #Add the header row of buttons self.View = wx.Button(self.scrolled_panel, label='View') self.View.Bind(wx.EVT_BUTTON, self.OnView) self.AddInjection = wx.Button(self.scrolled_panel, label='Add Injection Line') self.AddInjection.Bind(wx.EVT_BUTTON, self.OnAddInjection) self.PlotExistence = wx.Button(self.scrolled_panel, label='Plot Existence') self.PlotExistence.Bind(wx.EVT_BUTTON, self.OnPlotExistence) buttons_sizer = wx.BoxSizer(wx.HORIZONTAL) buttons_sizer.Add(self.AddInjection) buttons_sizer.Add(self.View) buttons_sizer.Add(self.PlotExistence) sizer = wx.FlexGridSizer(cols=1) sizer.Add(buttons_sizer) sizer.AddSpacer(10) sizer.Layout() self.scrolled_panel.SetAutoLayout(1) #Do the layout of all the panels self.scrolled_panel.SetSizer(sizer) main_sizer.Add(self.scrolled_panel, 1, wx.EXPAND) self.SetSizer(main_sizer) main_sizer.Layout() #Set some local variables self.Nterms = 0 self.Lines = [] def OnAddInjection(self, event=None): """ Add an injection line to the injection panel """ IE = InjectionElementPanel(self.scrolled_panel, self.Nterms + 1) #Put the panel within the scrolled panel and refresh self.scrolled_panel.GetSizer().Add(IE, 0) self.scrolled_panel.FitInside() self.GetSizer().Layout() #Update the local variables self.Lines.append(IE) self.Nterms += 1 self.Refresh() def remove_all(self): while self.Lines: self.RemoveInjection(self.Lines[0]) def RemoveInjection(self, injection): """ Remove the given injection term """ self.Lines.remove(injection) injection.Destroy() self.Nterms -= 1 #Renumber the injection panels that are contained in scrolled_panel I = 1 for child in self.scrolled_panel.Children: if isinstance(child, InjectionElementPanel): child.SizerBox.SetLabel("Injection line #" + str(I)) I += 1 self.GetSizer().Layout() self.scrolled_panel.FitInside() self.Refresh() def OnView(self, event): geo = self.GetTopLevelParent().MTB.InputsTB.panels[0].Scroll.geo SAF = ScrollAnimForm(geo, start=False) #IEPs are children that are instances of InjectionElementPanel class IEPs = [ child for child in self.scrolled_panel.Children if isinstance(child, InjectionElementPanel) ] for IEP in IEPs: for child in IEP.Children: if isinstance(child, InjectionPortPanel): # Get the values from the panel vals = child.get_values() # Overlay the port on the scroll wrap plot scroll_geo.overlay_injection_port(0, geo, vals['phi'], SAF.ax, vals['involute'], rport=vals['D'] / 2, offset=vals['offset']) SAF.start() SAF.Show() def OnPlotExistence(self, event=None): """ Plot a 2D line plot showing which control volume is connected to each injection port as a function of the crank angle """ import pylab import numpy as np _Scroll = self.GetTopLevelParent().MTB.InputsTB.panels[0].Scroll Iport = 1 #IEPs are children that are instances of InjectionElementPanel class IEPs = [ child for child in self.scrolled_panel.Children if isinstance(child, InjectionElementPanel) ] for IEP in IEPs: for child in IEP.Children: if isinstance(child, InjectionPortPanel): #Get the values from the port panel v = child.get_values() partner_list = [] theta = np.linspace(0, 2 * pi, 1000) for th in theta: partner_list.append( _Scroll._get_injection_CVkey( v['phi'], th, v['involute'])) #Find the break points in each segment dividers = [ i for i in range(len(theta) - 1) if not partner_list[i] == partner_list[i + 1] ] #Add end and beginning indices dividers = [0] + dividers + [len(theta) - 1] for i in range(len(dividers) - 1): L = dividers[i] R = dividers[i + 1] M = int((L + R) / 2) pylab.plot(np.r_[theta[L], theta[R]], np.r_[Iport, Iport]) pylab.plot(np.r_[theta[L], theta[L]], np.r_[Iport - 0.02, Iport + 0.02], 'k') pylab.plot(np.r_[theta[R], theta[R]], np.r_[Iport - 0.02, Iport + 0.02], 'k') pylab.text(theta[M], Iport + .02, partner_list[M], ha='center', va='bottom') #Increase the counter Iport += 1 pylab.xticks([0, pi / 2, pi, 3 * pi / 2, 2 * pi], [0, r'$\pi/2$', r'$\pi$', r'$3\pi/2$', r'$2\pi$']) pylab.xlim(0, 2 * pi) pylab.ylim(0.5, Iport - 1 + 0.5) pylab.yticks(range(1, Iport + 1)) pylab.show() def build_from_configfile(self, config): """ Get parameters from the configfile section for this plugin Parameters ---------- config : yaml configuration section for the plugin """ if config: self.remove_all() for line in config: # Add an injection line panel self.OnAddInjection() #Get a pointer to the last IEP (the one just added) IEP = self.Lines[-1] #Set the line length in the GUI [m] IEP.Lval.SetValue(str(line['Length'])) #Set the line ID in the GUI IEP.IDval.SetValue(str(line['ID'])) #Set the State in the GUI State = line['inletState'] IEP.state.set_state(State['Fluid'], T=State['T'], D=State['rho']) if 'ports' in line and line['ports']: for i, port in enumerate(line['ports']): if i > 0: IEP.OnAddPort() # Get a pointer to the port panel portpanel = IEP.ports_list[-1] # Set the values in the panel portpanel.set_values(port) def get_additional_parametric_terms(self): #: the list of terms _T = [] #IEPs are children of injection_panel that are instances of InjectionElementPanel class IEPs = [ child for child in self.scrolled_panel.Children if isinstance(child, InjectionElementPanel) ] for i, IEP in enumerate(IEPs): I = str(i + 1) _T += [ dict(attr='injection_state_pressure_' + I, text='Injection pressure #' + I + ' [kPa]', parent=self), dict(attr='injection_state_sat_temp_' + I, text='Injection saturated temperature (dew) #' + I + ' [K]', parent=self), dict(attr='injection_state_temp_' + I, text='Injection temperature #' + I + ' [K]', parent=self), dict(attr='injection_state_superheat_' + I, text='Injection superheat #' + I + ' [K]', parent=self), ] Ports = [ c for c in IEP.Children if isinstance(c, InjectionPortPanel) ] for j, child in enumerate(Ports): J = str(j + 1) _T += [ dict(attr='injection_phi_' + I + '_' + J, text='Injection port angle #' + I + ':' + J + ' [rad]', parent=self) ] return _T def apply_additional_parametric_terms(self, attrs, vals, panel_items): """ Set the terms in the injection panel based on the additional parametric terms provided by the get_additional_parametric_terms() function """ def apply_line_terms(attrs, vals): def is_int(i): """ Returns True if it is an integer """ try: i = int(i) return True except ValueError: return False def is_line_term(attr): """ Check if it is a line type term of the form injection_xxxxx_1' and is not a port term of the form injection_xxxxx_1_1 """ if not attr.startswith('injection'): return False #If there are no underscores, return false if len(attr.rsplit('_', 1)) == 1: return False #Try to split twice attr, i, j = attr.rsplit('_', 2) # If the far right one is an integer and the left part isn't you are # ok, its an injection line if not is_int(i) and is_int(j): return True else: return False # First check about the injection state; if two state related terms are # provided, use them to fix the injection state inj_state_params = [(par, val) for par, val in zip(attrs, vals) if is_line_term(par)] num_inj_state_params = len(inj_state_params) for i in range(len(self.Lines)): #Find the injection state terms that apply for this line state_params = [ (par, val) for par, val in zip(attrs, vals) if par.find('state') > -1 and par.endswith(str(i + 1)) ] num_state_params = len(state_params) #Get a copy of the state from the StatePanel inletState = self.Lines[i].state.GetState() if num_state_params > 0: #Unzip the parameters (List of tuples -> tuple of lists) state_attrs, state_vals = zip(*state_params) if num_state_params == 2: # Remove all the entries that correspond to the injection state - # we need them and don't want to set them in the conventional way for a in state_attrs: vals.pop(attrs.index(a)) attrs.pop(attrs.index(a)) #: The string representation of the index (1-based) I = str(i + 1) #Temperature and pressure provided if 'injection_state_temp_' + I in state_attrs and 'injection_state_pressure_' + I in state_attrs: injection_temp = state_vals[state_attrs.index( 'injection_state_temp_' + I)] injection_pressure = state_vals[state_attrs.index( 'injection_state_pressure_' + I)] self.Lines[i].state.set_state(inletState.Fluid, T=injection_temp, P=injection_pressure) #Dew temperature and superheat provided elif 'injection_state_sat_temp_' + I in state_attrs and 'injection_state_superheat_' + I in state_attrs: injection_sat_temp = state_vals[state_attrs.index( 'injection_state_sat_temp_' + I)] injection_superheat = state_vals[state_attrs.index( 'injection_state_superheat_' + I)] injection_temp = injection_sat_temp + injection_superheat import CoolProp.CoolProp as CP injection_pressure = CP.PropsSI( 'P', 'T', injection_sat_temp, 'Q', 1.0, inletState.Fluid) / 1000.0 self.Lines[i].state.set_state(inletState.Fluid, T=injection_temp, P=injection_pressure) else: raise ValueError( 'Invalid combination of injection states: ' + str(state_attrs)) elif num_inj_state_params == 1: import textwrap string = textwrap.dedent(""" Sorry but you need to provide two variables for the injection state in parametric table to fix the state. If you want to just modify the saturated temperature, add the superheat as a variable and give it one element in the parametric table """) dlg = wx.MessageDialog(None, string) dlg.ShowModal() dlg.Destroy() raise ValueError( 'Must provide two state variables in the parametric table for injection line' ) elif num_inj_state_params > 2: raise ValueError( 'Only two inlet state parameters can be provided in parametric table' ) return attrs, vals def apply_port_terms(attrs, vals): phi_params = [(par, val) for par, val in zip(attrs, vals) if par.startswith('injection_phi')] num_phi_params = len(phi_params) if num_phi_params > 0: #Unzip the parameters (List of tuples -> tuple of lists) phi_attrs, phi_vals = zip(*phi_params) # Remove all the entries that correspond to the angles # we need them and don't want to set them in the conventional way for a in phi_attrs: i = attrs.index(a) vals.pop(i) attrs.pop(i) for attr, val in zip(phi_attrs, phi_vals): # Term might look like something like 'injection_phi_1_2' # i would be 0, j would be 1 #indices are zero-based j = int(attr.rsplit('_', 1)[1]) - 1 i = int(attr.rsplit('_', 2)[1]) - 1 self.Lines[i].ports_list[j].phi_inj_port.SetValue(str(val)) return attrs, vals #Apply all the line terms and get back the lists attrs, vals = apply_line_terms(attrs, vals) #Apply all the line terms and get back the lists attrs, vals = apply_port_terms(attrs, vals) return attrs, vals
def init_page(self, title, options, location): m_options = collections.OrderedDict() def watch_option(option_name, new_value): options_shm, options_lock = self.options_shared_memory[title] options_list = [(opt.__class__.__name__, opt.args) for opt in self.options_dict[title].values()] for option in options_list: if option[1][0] == option_name: option[1][1] = new_value else: option[1][1] = self.options_dict[title][option[1][0]].value serialized = vision_common.serialize_options(options_list) options_lock.acquire_write() options_shm.seek(0) options_shm.write(serialized) options_lock.release_write() for option in options: m_options[option[1][0]] = getattr(gui_options, option[0])(*option[1]) m_options[option[1][0]].add_watcher(functools.partial(watch_option, option[1][0])) self.options_dict[title] = m_options options = m_options.values() page = wx.Panel(self.notebook) location = min(location, len(self.notebook.GetChildren()) - 1) self.notebook.InsertPage(location, page, title) for page_, title_ in ((self.pages[title_], title_) for title_ in self.pages if self.pages[title_][3] >= location): page_[3] += 1 image_panel = wxtended.WrapScroll(page) settings_panel = ScrolledPanel(page) settings_panel.SetSizer(wx.BoxSizer(wx.VERTICAL)) settings_panel.SetupScrolling(scroll_x=False) sizer = wx.BoxSizer() sizer.Add(image_panel, 1, wx.EXPAND) sizer.Add(settings_panel, 0, wx.EXPAND) sizer.AddSpacer((20, 0)) page.SetSizer(sizer) self.pages[title] = [page, image_panel, {}, location, settings_panel] save_button = wx.Button(settings_panel, -1, 'Save settings to file') load_button = wx.Button(settings_panel, -1, 'Load settings from file') defaults_button = wx.Button(settings_panel, -1, 'Restore defaults') def save_to_file(evt): dlg = wx.FileDialog(self.frame, 'Save config to location', '', "", "*", wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) if dlg.ShowModal() == wx.ID_OK: filename = dlg.GetFilename() dirname = dlg.GetDirectory() with open(os.path.join(dirname, filename), 'w') as f: for option in options: f.write('{} {}\n'.format(option.tag, option.value)) dlg.Destroy() def load_from_file(evt): dlg = wx.FileDialog(self.frame, 'Load config from location', '', "", "*", wx.FD_OPEN) if dlg.ShowModal() == wx.ID_OK: filename = dlg.GetFilename() dirname = dlg.GetDirectory() with open(os.path.join(dirname, filename)) as f: for line in f.readlines(): line_split = line.split() key = line_split[0] value = line[len(key):] self.options_dict[title][key].set_value(value) dlg.Destroy() def load_defaults(evt): module = imp.reload(__import__(title.split('.')[0])) for option_element in module.vision_options: self.options_dict[title][option_element.args[0]].set_value(option_element.args[1]) save_button.Bind(wx.EVT_BUTTON, save_to_file) load_button.Bind(wx.EVT_BUTTON, load_from_file) defaults_button.Bind(wx.EVT_BUTTON, load_defaults) settings_panel.GetSizer().AddSpacer((1, 5)) settings_panel.GetSizer().Add(save_button, 0, wx.CENTER) settings_panel.GetSizer().AddSpacer((1, 5)) settings_panel.GetSizer().Add(load_button, 0, wx.CENTER) settings_panel.GetSizer().AddSpacer((1, 5)) settings_panel.GetSizer().Add(defaults_button, 0, wx.CENTER) settings_panel.GetSizer().AddSpacer((1, 10)) for option in options: settings_panel.GetSizer().Add(option.draw_gui(settings_panel), 0) settings_panel.GetSizer().Add( wx.StaticLine(settings_panel, style=wx.LI_HORIZONTAL | wx.CENTER, size=(200, 20)))