source: sasview/src/sas/sasgui/perspectives/pr/inversion_panel.py @ cd31251

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since cd31251 was 5a58656, checked in by butler, 9 years ago

linked new help to pr panel

  • Property mode set to 100644
File size: 38.8 KB
RevLine 
[f3d51f6]1#!/usr/bin/env python
2
3# version
4__id__ = "$Id: aboutdialog.py 1193 2007-05-03 17:29:59Z dmitriy $"
5__revision__ = "$Revision: 1193 $"
6
7import wx
[5d98370]8import os
[ceaf16e]9import sys
10import logging
[9ff861b]11from wx.lib.scrolledpanel import ScrolledPanel
[d85c194]12from sas.sasgui.guiframe.events import StatusEvent
13from sas.sasgui.guiframe.panel_base import PanelBase
[5d98370]14from inversion_state import InversionState
[3e41f43]15from pr_widgets import PrTextCtrl
16from pr_widgets import DataFileTextCtrl
17from pr_widgets import OutputTextCtrl
[d85c194]18from sas.sasgui.guiframe.documentation_window import DocumentationWindow
[f3d51f6]19
[b8ff610]20if sys.platform.count("win32") > 0:
[7d9e7a9]21    FONT_VARIANT = 0
22else:
23    FONT_VARIANT = 1
[f3d51f6]24
[75df58b]25class InversionControl(ScrolledPanel, PanelBase):
[7116b6e0]26    """
27    """
[f3d51f6]28    window_name = 'pr_control'
29    window_caption = "P(r) control panel"
30    CENTER_PANE = True
[8b21fa7]31
[f3d51f6]32    # Figure of merit parameters [default]
[8b21fa7]33
[dfb58f8]34    ## Oscillation parameters (sin function = 1.1)
[f3d51f6]35    oscillation_max = 1.5
[8b21fa7]36
[f21d496]37    def __init__(self, parent, id=-1, plots=None, **kwargs):
[7116b6e0]38        """
39        """
[3e41f43]40        ScrolledPanel.__init__(self, parent, id=id, **kwargs)
[3f0351c6]41        PanelBase.__init__(self, parent)
[9ff861b]42        self.SetupScrolling()
[8b21fa7]43        #Set window's font size
[7d9e7a9]44        self.SetWindowVariant(variant=FONT_VARIANT)
[8b21fa7]45
[f3d51f6]46        self.plots = plots
47        self.radio_buttons = {}
[ae84427]48        self.parent = parent.parent
[8b21fa7]49
[f3d51f6]50        ## Data file TextCtrl
[8b21fa7]51        self.data_file = None
52        self.plot_data = None
53        self.nfunc_ctl = None
54        self.alpha_ctl = None
55        self.dmax_ctl = None
56        self.time_ctl = None
57        self.chi2_ctl = None
58        self.osc_ctl = None
[f3d51f6]59        self.file_radio = None
60        self.plot_radio = None
[634f1cf]61        self.label_sugg = None
[8b21fa7]62        self.qmin_ctl = None
63        self.qmax_ctl = None
[5d98370]64        self.swidth_ctl = None
65        self.sheight_ctl = None
[8b21fa7]66
67        self.rg_ctl = None
68        self.iq0_ctl = None
69        self.bck_chk = None
70        self.bck_ctl = None
71
[dfb58f8]72        # TextCtrl for fraction of positive P(r)
73        self.pos_ctl = None
[8b21fa7]74
[dfb58f8]75        # TextCtrl for fraction of 1 sigma positive P(r)
[8b21fa7]76        self.pos_err_ctl = None
77
[f3d51f6]78        ## Estimates
79        self.alpha_estimate_ctl = None
[35adaf6]80        self.nterms_estimate_ctl = None
[a00ee4c]81        ## D_max distance explorator
82        self.distance_explorator_ctl = None
[f3d51f6]83        ## Data manager
[8b21fa7]84        self._manager = None
[5d98370]85        ## Default file location for save
86        self._default_save_location = os.getcwd()
[c4ae1c2]87        if self.parent is not None:
[8b21fa7]88            self._default_save_location = \
[c4ae1c2]89                        self.parent._default_save_location
[8b21fa7]90
[0ccd214]91        # Default width
92        self._default_width = 350
[f3d51f6]93        self._do_layout()
[8b21fa7]94
[f3d51f6]95    def __setattr__(self, name, value):
96        """
[7116b6e0]97        Allow direct hooks to text boxes
[f3d51f6]98        """
[3e41f43]99        if name == 'nfunc':
[5d98370]100            self.nfunc_ctl.SetValue(str(int(value)))
[3e41f43]101        elif name == 'd_max':
[f3d51f6]102            self.dmax_ctl.SetValue(str(value))
[3e41f43]103        elif name == 'alpha':
[f3d51f6]104            self.alpha_ctl.SetValue(str(value))
[3e41f43]105        elif name == 'chi2':
[a4bd2ac]106            self.chi2_ctl.SetValue("%-5.2g" % value)
[3e41f43]107        elif name == 'bck':
[a4bd2ac]108            self.bck_ctl.SetValue("%-5.2g" % value)
[3e41f43]109        elif name == 'q_min':
[a4bd2ac]110            self.qmin_ctl.SetValue("%-5.2g" % value)
[3e41f43]111        elif name == 'q_max':
[a4bd2ac]112            self.qmax_ctl.SetValue("%-5.2g" % value)
[3e41f43]113        elif name == 'elapsed':
[f3d51f6]114            self.time_ctl.SetValue("%-5.2g" % value)
[8b21fa7]115        elif name == 'rg':
[a4bd2ac]116            self.rg_ctl.SetValue("%-5.2g" % value)
[3e41f43]117        elif name == 'iq0':
[a4bd2ac]118            self.iq0_ctl.SetValue("%-5.2g" % value)
[3e41f43]119        elif name == 'oscillation':
[f3d51f6]120            self.osc_ctl.SetValue("%-5.2g" % value)
[3e41f43]121        elif name == 'slit_width':
[5d98370]122            self.swidth_ctl.SetValue("%-5.2g" % value)
[3e41f43]123        elif name == 'slit_height':
[5d98370]124            self.sheight_ctl.SetValue("%-5.2g" % value)
[3e41f43]125        elif name == 'positive':
[dfb58f8]126            self.pos_ctl.SetValue("%-5.2g" % value)
[3e41f43]127        elif name == 'pos_err':
[dfb58f8]128            self.pos_err_ctl.SetValue("%-5.2g" % value)
[3e41f43]129        elif name == 'alpha_estimate':
[634f1cf]130            self.alpha_estimate_ctl.SetToolTipString("Click to accept value.")
131            self.alpha_estimate_ctl.Enable(True)
132            self.alpha_estimate_ctl.SetLabel("%-3.1g" % value)
133            #self.alpha_estimate_ctl.Show()
134            #self.label_sugg.Show()
[3e41f43]135        elif name == 'nterms_estimate':
[35adaf6]136            self.nterms_estimate_ctl.SetToolTipString("Click to accept value.")
137            self.nterms_estimate_ctl.Enable(True)
138            self.nterms_estimate_ctl.SetLabel("%-g" % value)
[3e41f43]139        elif name == 'plotname':
[0d88a09]140            self.plot_data.SetValue(str(value))
141            self._on_pars_changed(None)
[3e41f43]142        elif name == 'datafile':
[0d88a09]143            self.plot_data.SetValue(str(value))
144            self._on_pars_changed(None)
[f3d51f6]145        else:
146            wx.Panel.__setattr__(self, name, value)
[8b21fa7]147
[f3d51f6]148    def __getattr__(self, name):
149        """
[7116b6e0]150        Allow direct hooks to text boxes
[f3d51f6]151        """
[3e41f43]152        if name == 'nfunc':
[3fd1ebc]153            try:
154                return int(self.nfunc_ctl.GetValue())
155            except:
156                return -1
[3e41f43]157        elif name == 'd_max':
[3fd1ebc]158            try:
159                return self.dmax_ctl.GetValue()
160            except:
161                return -1.0
[3e41f43]162        elif name == 'alpha':
[3fd1ebc]163            try:
164                return self.alpha_ctl.GetValue()
165            except:
166                return -1.0
[3e41f43]167        elif name == 'chi2':
[3fd1ebc]168            try:
169                return float(self.chi2_ctl.GetValue())
170            except:
[5d98370]171                return None
[3e41f43]172        elif name == 'bck':
[a4bd2ac]173            try:
174                return float(self.bck_ctl.GetValue())
175            except:
[5d98370]176                return None
[3e41f43]177        elif name == 'q_min':
[3fd1ebc]178            try:
179                return float(self.qmin_ctl.GetValue())
180            except:
181                return 0.0
[8b21fa7]182        elif name == 'q_max':
[3fd1ebc]183            try:
184                return float(self.qmax_ctl.GetValue())
185            except:
186                return 0.0
[3e41f43]187        elif name == 'elapsed':
[3fd1ebc]188            try:
189                return float(self.time_ctl.GetValue())
190            except:
[5d98370]191                return None
[3e41f43]192        elif name == 'rg':
[a4bd2ac]193            try:
194                return float(self.rg_ctl.GetValue())
195            except:
[5d98370]196                return None
[8b21fa7]197        elif name == 'iq0':
[a4bd2ac]198            try:
199                return float(self.iq0_ctl.GetValue())
200            except:
[5d98370]201                return None
[3e41f43]202        elif name == 'oscillation':
[3fd1ebc]203            try:
204                return float(self.osc_ctl.GetValue())
205            except:
[5d98370]206                return None
[3e41f43]207        elif name == 'slit_width':
[5d98370]208            try:
209                return float(self.swidth_ctl.GetValue())
210            except:
211                return None
[8b21fa7]212        elif name == 'slit_height':
[5d98370]213            try:
214                return float(self.sheight_ctl.GetValue())
215            except:
216                return None
[3e41f43]217        elif name == 'pos':
[3fd1ebc]218            try:
219                return float(self.pos_ctl.GetValue())
220            except:
[5d98370]221                return None
[3e41f43]222        elif name == 'pos_err':
[5d98370]223            try:
224                return float(self.pos_err_ctl.GetValue())
225            except:
226                return None
[3e41f43]227        elif name == 'alpha_estimate':
[5d98370]228            try:
229                return float(self.alpha_estimate_ctl.GetLabel())
230            except:
231                return None
[3e41f43]232        elif name == 'nterms_estimate':
[5d98370]233            try:
234                return int(self.nterms_estimate_ctl.GetLabel())
235            except:
236                return None
[3e41f43]237        elif name == 'plotname':
[0d88a09]238            return self.plot_data.GetValue()
[3e41f43]239        elif name == 'datafile':
[0d88a09]240            return self.plot_data.GetValue()
[f3d51f6]241        else:
[a00ee4c]242            return wx.Panel.__getattribute__(self, name)
[8b21fa7]243
[d85ee8c]244    def save_project(self, doc=None):
245        """
246        return an xml node containing state of the panel
247         that guiframe can write to file
248        """
249        data = self.get_data()
250        state = self.get_state()
251        if data is not None:
252            new_doc = self._manager.state_reader.write_toXML(data, state)
253            if new_doc is not None:
254                if doc is not None and hasattr(doc, "firstChild"):
[92a2ecd]255                    child = new_doc.getElementsByTagName("SASentry")
256                    for item in child:
257                        doc.firstChild.appendChild(item)
[d85ee8c]258                else:
259                    doc = new_doc
[8b21fa7]260        return doc
261
[3f0351c6]262    def on_save(self, evt=None):
[5d98370]263        """
[7116b6e0]264        Method used to create a memento of the current state
[8b21fa7]265
266        :return: state object
[5d98370]267        """
268        # Ask the user the location of the file to write to.
269        path = None
[c4ae1c2]270        if self.parent != None:
[8b21fa7]271            self._default_save_location = self.parent._default_save_location
[3e41f43]272        dlg = wx.FileDialog(self, "Choose a file",
[8b21fa7]273                            self._default_save_location,
[c4ae1c2]274                            self.window_caption, "*.prv", wx.SAVE)
[5d98370]275        if dlg.ShowModal() == wx.ID_OK:
276            path = dlg.GetPath()
277            self._default_save_location = os.path.dirname(path)
[c4ae1c2]278            if self.parent != None:
[8b21fa7]279                self.parent._default_save_location = self._default_save_location
[0d88a09]280        else:
281            return None
[8b21fa7]282
[5d98370]283        dlg.Destroy()
[8b21fa7]284
[b35d3d1]285        state = self.get_state()
[8b21fa7]286
[23cdeab]287        # MAC always needs the extension for saving
288        extens = ".prv"
289        # Make sure the ext included in the file name
290        fName = os.path.splitext(path)[0] + extens
291        self._manager.save_data(filepath=fName, prstate=state)
[8b21fa7]292
[b35d3d1]293        return state
[8b21fa7]294
[6d3d5ff]295    def get_data(self):
296        """
297        """
298        return self._manager.get_data()
[8b21fa7]299
[b35d3d1]300    def get_state(self):
301        """
302        Get the current state
[8b21fa7]303
[b35d3d1]304        : return: state object
305        """
[8b21fa7]306        # Construct the state object
[5d98370]307        state = InversionState()
[8b21fa7]308
[5d98370]309        # Read the panel's parameters
310        flag, alpha, dmax, nfunc, qmin, \
311        qmax, height, width = self._read_pars()
[8b21fa7]312
[5d98370]313        state.nfunc = nfunc
314        state.d_max = dmax
315        state.alpha = alpha
[8b21fa7]316        state.qmin = qmin
317        state.qmax = qmax
[5d98370]318        state.width = width
319        state.height = height
[8b21fa7]320
[5d98370]321        # Data file
[0d88a09]322        state.file = self.plot_data.GetValue()
[8b21fa7]323
[5d98370]324        # Background evaluation checkbox
325        state.estimate_bck = self.bck_chk.IsChecked()
[8b21fa7]326
[5d98370]327        # Estimates
328        state.nterms_estimate = self.nterms_estimate
329        state.alpha_estimate = self.alpha_estimate
[8b21fa7]330
[5d98370]331        # Read the output values
[8b21fa7]332        state.chi2 = self.chi2
[5d98370]333        state.elapsed = self.elapsed
[8b21fa7]334        state.osc = self.oscillation
335        state.pos = self.pos
[5d98370]336        state.pos_err = self.pos_err
[8b21fa7]337        state.rg = self.rg
338        state.iq0 = self.iq0
339        state.bck = self.bck
340
[5d98370]341        return state
[8b21fa7]342
[5d98370]343    def set_state(self, state):
344        """
[7116b6e0]345        Set the state of the panel and inversion problem to
346        the state passed as a parameter.
[8b21fa7]347        Execute the inversion immediately after filling the
[7116b6e0]348        controls.
[8b21fa7]349
[7116b6e0]350        :param state: InversionState object
[5d98370]351        """
[fde249c]352        if state.nfunc is not None:
353            self.nfunc = state.nfunc
354        if state.d_max is not None:
355            self.d_max = state.d_max
356        if state.alpha is not None:
357            self.alpha = state.alpha
358        if state.qmin is not None:
[8b21fa7]359            self.q_min = state.qmin
[fde249c]360        if state.qmax is not None:
[8b21fa7]361            self.q_max = state.qmax
[fde249c]362        if state.width is not None:
363            self.slit_width = state.width
364        if state.height is not None:
365            self.slit_height = state.height
[8b21fa7]366
[5d98370]367        # Data file
[0d88a09]368        self.plot_data.SetValue(str(state.file))
[8b21fa7]369
[5d98370]370        # Background evaluation checkbox
371        self.bck_chk.SetValue(state.estimate_bck)
[8b21fa7]372
[5d98370]373        # Estimates
[fde249c]374        if state.nterms_estimate is not None:
375            self.nterms_estimate = state.nterms_estimate
[8b21fa7]376        if state.alpha_estimate is not None:
377            self.alpha_estimate = state.alpha_estimate
378
379
[5d98370]380        # Read the output values
[fde249c]381        if state.chi2 is not None:
[8b21fa7]382            self.chi2 = state.chi2
[fde249c]383        if state.elapsed is not None:
384            self.elapsed = state.elapsed
385        if state.osc is not None:
386            self.oscillation = state.osc
387        if state.pos is not None:
388            self.positive = state.pos
389        if state.pos_err is not None:
390            self.pos_err = state.pos_err
391        if state.rg is not None:
[8b21fa7]392            self.rg = state.rg
[fde249c]393        if state.iq0 is not None:
[8b21fa7]394            self.iq0 = state.iq0
[fde249c]395        if state.bck is not None:
[8b21fa7]396            self.bck = state.bck
[5d98370]397
[0d88a09]398        # Perform inversion
[8b21fa7]399        self._on_invert(None)
400
[f3d51f6]401    def set_manager(self, manager):
[6d3d5ff]402        self._manager = manager
[8b21fa7]403
[f3d51f6]404    def _do_layout(self):
[8b21fa7]405        vbox = wx.GridBagSizer(0, 0)
[4318af7f]406        iy_vb = 0
[f3d51f6]407
408        # ----- I(q) data -----
[aa4b8379]409        databox = wx.StaticBox(self, -1, "I(q) data source")
[8b21fa7]410
[f3d51f6]411        boxsizer1 = wx.StaticBoxSizer(databox, wx.VERTICAL)
[3e41f43]412        boxsizer1.SetMinSize((self._default_width, 50))
413        pars_sizer = wx.GridBagSizer(5, 5)
[0d21ac1]414
[f3d51f6]415        iy = 0
[57b551e]416        self.file_radio = wx.StaticText(self, -1, "Name:")
[3e41f43]417        pars_sizer.Add(self.file_radio, (iy, 0), (1, 1),
[8b21fa7]418                       wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
419
420        self.plot_data = DataFileTextCtrl(self, -1, size=(260, 20))
421
[3e41f43]422        pars_sizer.Add(self.plot_data, (iy, 1), (1, 1),
[8b21fa7]423                       wx.EXPAND | wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 15)
424
[a4bd2ac]425        self.bck_chk = wx.CheckBox(self, -1, "Estimate background level")
[3e41f43]426        hint_msg = "Check box to let the fit estimate "
427        hint_msg += "the constant background level."
428        self.bck_chk.SetToolTipString(hint_msg)
[a4bd2ac]429        self.bck_chk.Bind(wx.EVT_CHECKBOX, self._on_pars_changed)
430        iy += 1
[3e41f43]431        pars_sizer.Add(self.bck_chk, (iy, 0), (1, 2),
[8b21fa7]432                       wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
433        boxsizer1.Add(pars_sizer, 0, wx.EXPAND)
[3e41f43]434        vbox.Add(boxsizer1, (iy_vb, 0), (1, 1),
[8b21fa7]435                 wx.LEFT | wx.RIGHT | wx.EXPAND | wx.ADJUST_MINSIZE | wx.TOP, 5)
436
[a4bd2ac]437        # ----- Add slit parameters -----
[2a92852]438        if True:
[a4bd2ac]439            sbox = wx.StaticBox(self, -1, "Slit parameters")
440            sboxsizer = wx.StaticBoxSizer(sbox, wx.VERTICAL)
[3e41f43]441            sboxsizer.SetMinSize((self._default_width, 20))
[8b21fa7]442
[3e41f43]443            sizer_slit = wx.GridBagSizer(5, 5)
[8b21fa7]444
[3e41f43]445            label_sheight = wx.StaticText(self, -1, "Height", size=(40, 20))
446            label_swidth = wx.StaticText(self, -1, "Width", size=(40, 20))
[8b21fa7]447            label_sunits2 = wx.StaticText(self, -1, "[A^(-1)]", size=(55, 20))
448            self.sheight_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, size=(60, 20))
449            self.swidth_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, size=(60, 20))
[3e41f43]450            hint_msg = "Enter slit height in units of Q or leave blank."
451            self.sheight_ctl.SetToolTipString(hint_msg)
452            hint_msg = "Enter slit width in units of Q or leave blank."
453            self.swidth_ctl.SetToolTipString(hint_msg)
[8b21fa7]454
[a4bd2ac]455            iy = 0
[8b21fa7]456            sizer_slit.Add(label_sheight, (iy, 0), (1, 1), wx.LEFT | wx.EXPAND, 5)
457            sizer_slit.Add(self.sheight_ctl, (iy, 1), (1, 1), wx.LEFT | wx.EXPAND, 5)
458            sizer_slit.Add(label_swidth, (iy, 2), (1, 1), wx.LEFT | wx.EXPAND, 5)
459            sizer_slit.Add(self.swidth_ctl, (iy, 3), (1, 1), wx.LEFT | wx.EXPAND, 5)
460            sizer_slit.Add(label_sunits2, (iy, 4), (1, 1), wx.LEFT | wx.EXPAND, 5)
461
[a4bd2ac]462            sboxsizer.Add(sizer_slit, wx.TOP, 15)
[4318af7f]463            iy_vb += 1
[3e41f43]464            vbox.Add(sboxsizer, (iy_vb, 0), (1, 1),
[8b21fa7]465                     wx.LEFT | wx.RIGHT | wx.EXPAND | wx.ADJUST_MINSIZE, 5)
466
[357b79b]467        # ----- Q range -----
468        qbox = wx.StaticBox(self, -1, "Q range")
469        qboxsizer = wx.StaticBoxSizer(qbox, wx.VERTICAL)
[3e41f43]470        qboxsizer.SetMinSize((self._default_width, 20))
[8b21fa7]471
[3e41f43]472        sizer_q = wx.GridBagSizer(5, 5)
[357b79b]473
[3e41f43]474        label_qmin = wx.StaticText(self, -1, "Q min", size=(40, 20))
475        label_qmax = wx.StaticText(self, -1, "Q max", size=(40, 20))
476        label_qunits2 = wx.StaticText(self, -1, "[A^(-1)]", size=(55, 20))
[8b21fa7]477        self.qmin_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, size=(60, 20))
478        self.qmax_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, size=(60, 20))
[3e41f43]479        hint_msg = "Select a lower bound for Q or leave blank."
480        self.qmin_ctl.SetToolTipString(hint_msg)
481        hint_msg = "Select an upper bound for Q or leave blank."
482        self.qmax_ctl.SetToolTipString(hint_msg)
[357b79b]483        self.qmin_ctl.Bind(wx.EVT_TEXT, self._on_pars_changed)
484        self.qmax_ctl.Bind(wx.EVT_TEXT, self._on_pars_changed)
[8b21fa7]485
[357b79b]486        iy = 0
[8b21fa7]487        sizer_q.Add(label_qmin, (iy, 0), (1, 1), wx.LEFT | wx.EXPAND, 5)
488        sizer_q.Add(self.qmin_ctl, (iy, 1), (1, 1), wx.LEFT | wx.EXPAND, 5)
489        sizer_q.Add(label_qmax, (iy, 2), (1, 1), wx.LEFT | wx.EXPAND, 5)
490        sizer_q.Add(self.qmax_ctl, (iy, 3), (1, 1), wx.LEFT | wx.EXPAND, 5)
491        sizer_q.Add(label_qunits2, (iy, 4), (1, 1), wx.LEFT | wx.EXPAND, 5)
[357b79b]492        qboxsizer.Add(sizer_q, wx.TOP, 15)
[4318af7f]493
494        iy_vb += 1
[8b21fa7]495        vbox.Add(qboxsizer, (iy_vb, 0), (1, 1),
496                 wx.LEFT | wx.RIGHT | wx.EXPAND | wx.ADJUST_MINSIZE, 5)
497
[f3d51f6]498        # ----- Parameters -----
499        parsbox = wx.StaticBox(self, -1, "Parameters")
500        boxsizer2 = wx.StaticBoxSizer(parsbox, wx.VERTICAL)
[8b21fa7]501        boxsizer2.SetMinSize((self._default_width, 50))
502
503        explanation = "P(r) is found by fitting a set of base functions"
[3e41f43]504        explanation += " to I(Q). The minimization involves"
505        explanation += " a regularization term to ensure a smooth P(r)."
[8b21fa7]506        explanation += " The regularization constant gives the size of that "
[3e41f43]507        explanation += "term. The suggested value is the value above which the"
508        explanation += " output P(r) will have only one peak."
[8b21fa7]509        label_explain = wx.StaticText(self, -1, explanation, size=(280, 90))
510        boxsizer2.Add(label_explain, wx.LEFT | wx.BOTTOM, 5)
511
[f3d51f6]512        label_nfunc = wx.StaticText(self, -1, "Number of terms")
[3e41f43]513        label_nfunc.SetMinSize((120, 20))
[f3d51f6]514        label_alpha = wx.StaticText(self, -1, "Regularization constant")
[8b21fa7]515        label_dmax = wx.StaticText(self, -1, "Max distance [A]")
516        self.label_sugg = wx.StaticText(self, -1, "Suggested value")
517
518        self.nfunc_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, size=(60, 20))
[32dffae4]519        self.nfunc_ctl.SetToolTipString("Number of terms in the expansion.")
[8b21fa7]520        self.alpha_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, size=(60, 20))
[3e41f43]521        hint_msg = "Control parameter for the size of the regularization term."
522        self.alpha_ctl.SetToolTipString(hint_msg)
[8b21fa7]523        self.dmax_ctl = PrTextCtrl(self, -1, style=wx.TE_PROCESS_ENTER, size=(60, 20))
[3e41f43]524        hint_msg = "Maximum distance between any two points in the system."
525        self.dmax_ctl.SetToolTipString(hint_msg)
[8b21fa7]526        wx_id = wx.NewId()
527        self.alpha_estimate_ctl = wx.Button(self, wx_id, "")
528        self.Bind(wx.EVT_BUTTON, self._on_accept_alpha, id=wx_id)
[f3d51f6]529        self.alpha_estimate_ctl.Enable(False)
[634f1cf]530        self.alpha_estimate_ctl.SetToolTipString("Waiting for estimate...")
[8b21fa7]531
532        wx_id = wx.NewId()
533        self.nterms_estimate_ctl = wx.Button(self, wx_id, "")
[35adaf6]534        #self.nterms_estimate_ctl.Hide()
[8b21fa7]535        self.Bind(wx.EVT_BUTTON, self._on_accept_nterms, id=wx_id)
[35adaf6]536        self.nterms_estimate_ctl.Enable(False)
[8b21fa7]537
[35adaf6]538        self.nterms_estimate_ctl.SetToolTipString("Waiting for estimate...")
[8b21fa7]539
[d6113849]540        self.nfunc_ctl.Bind(wx.EVT_TEXT, self._read_pars)
[a4bd2ac]541        self.alpha_ctl.Bind(wx.EVT_TEXT, self._read_pars)
542        self.dmax_ctl.Bind(wx.EVT_TEXT, self._on_pars_changed)
[8b21fa7]543
[a00ee4c]544        # Distance explorator
[8b21fa7]545        wx_id = wx.NewId()
546        self.distance_explorator_ctl = wx.Button(self, wx_id, "Explore")
547        self.Bind(wx.EVT_BUTTON, self._on_explore, id=wx_id)
548
549
550        sizer_params = wx.GridBagSizer(5, 5)
[f3d51f6]551
552        iy = 0
[3e41f43]553        sizer_params.Add(self.label_sugg, (iy, 2), (1, 1), wx.LEFT, 15)
[f3d51f6]554        iy += 1
[8b21fa7]555        sizer_params.Add(label_nfunc, (iy, 0), (1, 1), wx.LEFT, 15)
556        sizer_params.Add(self.nfunc_ctl, (iy, 1), (1, 1), wx.RIGHT, 0)
[3e41f43]557        sizer_params.Add(self.nterms_estimate_ctl, (iy, 2), (1, 1), wx.LEFT, 15)
[f3d51f6]558        iy += 1
[8b21fa7]559        sizer_params.Add(label_alpha, (iy, 0), (1, 1), wx.LEFT, 15)
560        sizer_params.Add(self.alpha_ctl, (iy, 1), (1, 1), wx.RIGHT, 0)
[3e41f43]561        sizer_params.Add(self.alpha_estimate_ctl, (iy, 2), (1, 1), wx.LEFT, 15)
[f3d51f6]562        iy += 1
[3e41f43]563        sizer_params.Add(label_dmax, (iy, 0), (1, 1), wx.LEFT, 15)
[8b21fa7]564        sizer_params.Add(self.dmax_ctl, (iy, 1), (1, 1), wx.RIGHT, 0)
[3e41f43]565        sizer_params.Add(self.distance_explorator_ctl, (iy, 2),
566                         (1, 1), wx.LEFT, 15)
[f3d51f6]567
568        boxsizer2.Add(sizer_params, 0)
[8b21fa7]569
[4318af7f]570        iy_vb += 1
[3e41f43]571        vbox.Add(boxsizer2, (iy_vb, 0), (1, 1),
[8b21fa7]572                 wx.LEFT | wx.RIGHT | wx.EXPAND | wx.ADJUST_MINSIZE, 5)
[f3d51f6]573
[634f1cf]574
[f3d51f6]575        # ----- Results -----
576        resbox = wx.StaticBox(self, -1, "Outputs")
577        ressizer = wx.StaticBoxSizer(resbox, wx.VERTICAL)
[3e41f43]578        ressizer.SetMinSize((self._default_width, 50))
[8b21fa7]579
580        label_rg = wx.StaticText(self, -1, "Rg")
581        label_rg_unit = wx.StaticText(self, -1, "[A]")
582        label_iq0 = wx.StaticText(self, -1, "I(Q=0)")
[a4bd2ac]583        label_iq0_unit = wx.StaticText(self, -1, "[A^(-1)]")
[8b21fa7]584        label_bck = wx.StaticText(self, -1, "Background")
[a4bd2ac]585        label_bck_unit = wx.StaticText(self, -1, "[A^(-1)]")
[8b21fa7]586        self.rg_ctl = OutputTextCtrl(self, -1, size=(60, 20))
[3e41f43]587        hint_msg = "Radius of gyration for the computed P(r)."
588        self.rg_ctl.SetToolTipString(hint_msg)
[8b21fa7]589        self.iq0_ctl = OutputTextCtrl(self, -1, size=(60, 20))
[3e41f43]590        hint_msg = "Scattering intensity at Q=0 for the computed P(r)."
591        self.iq0_ctl.SetToolTipString(hint_msg)
[8b21fa7]592        self.bck_ctl = OutputTextCtrl(self, -1, size=(60, 20))
[a4bd2ac]593        self.bck_ctl.SetToolTipString("Value of estimated constant background.")
[8b21fa7]594
[f3d51f6]595        label_time = wx.StaticText(self, -1, "Computation time")
596        label_time_unit = wx.StaticText(self, -1, "secs")
[8b21fa7]597        label_time.SetMinSize((120, 20))
[f3d51f6]598        label_chi2 = wx.StaticText(self, -1, "Chi2/dof")
599        label_osc = wx.StaticText(self, -1, "Oscillations")
[dfb58f8]600        label_pos = wx.StaticText(self, -1, "Positive fraction")
601        label_pos_err = wx.StaticText(self, -1, "1-sigma positive fraction")
[8b21fa7]602
[75df58b]603        self.time_ctl = OutputTextCtrl(self, -1, size=(60, 20))
[3e41f43]604        hint_msg = "Computation time for the last inversion, in seconds."
605        self.time_ctl.SetToolTipString(hint_msg)
[8b21fa7]606
[75df58b]607        self.chi2_ctl = OutputTextCtrl(self, -1, size=(60, 20))
[32dffae4]608        self.chi2_ctl.SetToolTipString("Chi^2 over degrees of freedom.")
[8b21fa7]609
[dfb58f8]610        # Oscillation parameter
[75df58b]611        self.osc_ctl = OutputTextCtrl(self, -1, size=(60, 20))
[3e41f43]612        hint_msg = "Oscillation parameter. P(r) for a sphere has an "
613        hint_msg += " oscillation parameter of 1.1."
614        self.osc_ctl.SetToolTipString(hint_msg)
[8b21fa7]615
[dfb58f8]616        # Positive fraction figure of merit
[75df58b]617        self.pos_ctl = OutputTextCtrl(self, -1, size=(60, 20))
[3e41f43]618        hint_msg = "Fraction of P(r) that is positive. "
619        hint_msg += "Theoretically, P(r) is defined positive."
620        self.pos_ctl.SetToolTipString(hint_msg)
[8b21fa7]621
[dfb58f8]622        # 1-simga positive fraction figure of merit
[75df58b]623        self.pos_err_ctl = OutputTextCtrl(self, -1, size=(60, 20))
[8b21fa7]624        message = "Fraction of P(r) that is at least 1 standard deviation"
[3e41f43]625        message += " greater than zero.\n"
626        message += "This figure of merit tells you about the size of the "
627        message += "P(r) errors.\n"
628        message += "If it is close to 1 and the other figures of merit are bad,"
629        message += " consider changing the maximum distance."
[dfb58f8]630        self.pos_err_ctl.SetToolTipString(message)
[8b21fa7]631
[3e41f43]632        sizer_res = wx.GridBagSizer(5, 5)
[f3d51f6]633
634        iy = 0
[8b21fa7]635        sizer_res.Add(label_rg, (iy, 0), (1, 1), wx.LEFT | wx.EXPAND, 15)
636        sizer_res.Add(self.rg_ctl, (iy, 1), (1, 1), wx.RIGHT | wx.EXPAND, 15)
637        sizer_res.Add(label_rg_unit, (iy, 2), (1, 1), wx.RIGHT | wx.EXPAND, 15)
[a4bd2ac]638        iy += 1
[8b21fa7]639        sizer_res.Add(label_iq0, (iy, 0), (1, 1), wx.LEFT | wx.EXPAND, 15)
640        sizer_res.Add(self.iq0_ctl, (iy, 1), (1, 1), wx.RIGHT | wx.EXPAND, 15)
641        sizer_res.Add(label_iq0_unit, (iy, 2), (1, 1), wx.RIGHT | wx.EXPAND, 15)
[a4bd2ac]642        iy += 1
[8b21fa7]643        sizer_res.Add(label_bck, (iy, 0), (1, 1), wx.LEFT | wx.EXPAND, 15)
644        sizer_res.Add(self.bck_ctl, (iy, 1), (1, 1), wx.RIGHT | wx.EXPAND, 15)
645        sizer_res.Add(label_bck_unit, (iy, 2), (1, 1), wx.RIGHT | wx.EXPAND, 15)
[a4bd2ac]646        iy += 1
[8b21fa7]647        sizer_res.Add(label_time, (iy, 0), (1, 1), wx.LEFT | wx.EXPAND, 15)
648        sizer_res.Add(self.time_ctl, (iy, 1), (1, 1), wx.RIGHT | wx.EXPAND, 15)
649        sizer_res.Add(label_time_unit, (iy, 2), (1, 1), wx.RIGHT | wx.EXPAND, 15)
[f3d51f6]650        iy += 1
[8b21fa7]651        sizer_res.Add(label_chi2, (iy, 0), (1, 1), wx.LEFT | wx.EXPAND, 15)
652        sizer_res.Add(self.chi2_ctl, (iy, 1), (1, 1), wx.RIGHT | wx.EXPAND, 15)
[f3d51f6]653        iy += 1
[8b21fa7]654        sizer_res.Add(label_osc, (iy, 0), (1, 1), wx.LEFT | wx.EXPAND, 15)
655        sizer_res.Add(self.osc_ctl, (iy, 1), (1, 1), wx.RIGHT | wx.EXPAND, 15)
[f3d51f6]656
[dfb58f8]657        iy += 1
[8b21fa7]658        sizer_res.Add(label_pos, (iy, 0), (1, 1), wx.LEFT | wx.EXPAND, 15)
659        sizer_res.Add(self.pos_ctl, (iy, 1), (1, 1), wx.RIGHT | wx.EXPAND, 15)
[dfb58f8]660
661        iy += 1
[8b21fa7]662        sizer_res.Add(label_pos_err, (iy, 0), (1, 1), wx.LEFT | wx.EXPAND, 15)
663        sizer_res.Add(self.pos_err_ctl, (iy, 1), (1, 1), wx.RIGHT | wx.EXPAND, 15)
[dfb58f8]664
[f3d51f6]665        ressizer.Add(sizer_res, 0)
[4318af7f]666        iy_vb += 1
[3e41f43]667        vbox.Add(ressizer, (iy_vb, 0), (1, 1),
[8b21fa7]668                 wx.LEFT | wx.RIGHT | wx.EXPAND | wx.ADJUST_MINSIZE, 5)
[f3d51f6]669
670        # ----- Buttons -----
[8b21fa7]671        wx_id = wx.NewId()
672        button_ok = wx.Button(self, wx_id, "Compute")
673        button_ok.SetToolTipString("Perform P(r) inversion.")
674        self.Bind(wx.EVT_BUTTON, self._on_invert, id=wx_id)
675
[f71700b]676        self.button_help = wx.Button(self, -1, "HELP")
677        self.button_help.SetToolTipString("Get help on P(r) inversion.")
678        self.button_help.Bind(wx.EVT_BUTTON, self.on_help)
[dea2f6e]679
[5771ea3]680        self._set_reset_flag(True)
[3f0351c6]681        self._set_save_flag(True)
[f3d51f6]682        sizer_button = wx.BoxSizer(wx.HORIZONTAL)
[8b21fa7]683        sizer_button.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
684        sizer_button.Add(button_ok, 0, wx.LEFT | wx.ADJUST_MINSIZE, 10)
[f71700b]685        sizer_button.Add(self.button_help, 0, wx.LEFT | wx.ADJUST_MINSIZE, 10)
[8b21fa7]686
[4318af7f]687        iy_vb += 1
[3e41f43]688        vbox.Add(sizer_button, (iy_vb, 0), (1, 1),
[8b21fa7]689                 wx.EXPAND | wx.BOTTOM | wx.TOP | wx.RIGHT, 10)
[f3d51f6]690
[a00ee4c]691        self.Bind(wx.EVT_TEXT_ENTER, self._on_invert)
[f3d51f6]692
693        self.SetSizer(vbox)
[8b21fa7]694
[634f1cf]695    def _on_accept_alpha(self, evt):
696        """
[8b21fa7]697        User has accepted the estimated alpha,
[7116b6e0]698        set it as part of the input parameters
[634f1cf]699        """
700        try:
701            alpha = self.alpha_estimate_ctl.GetLabel()
[c1bffa5]702            # Check that we have a number
703            float(alpha)
704            self.alpha_ctl.SetValue(alpha)
705        except ValueError:
706            logging.error("InversionControl._on_accept_alpha got a value that was not a number: %s" % alpha )
[634f1cf]707        except:
708            # No estimate or bad estimate, either do nothing
[8b21fa7]709            logging.error("InversionControl._on_accept_alpha: %s" % sys.exc_value)
710
[35adaf6]711    def _on_accept_nterms(self, evt):
712        """
[8b21fa7]713        User has accepted the estimated number of terms,
[7116b6e0]714        set it as part of the input parameters
[35adaf6]715        """
716        try:
717            nterms = self.nterms_estimate_ctl.GetLabel()
[c1bffa5]718            # Check that we have a number
719            float(nterms)
720            self.nfunc_ctl.SetValue(nterms)
721        except ValueError:
722            logging.error("InversionControl._on_accept_nterms got a value that was not a number: %s" % nterms )
[35adaf6]723        except:
724            # No estimate or bad estimate, either do nothing
[8b21fa7]725            logging.error("InversionControl._on_accept_nterms: %s" % sys.exc_value)
726
[91d910d]727    def clear_panel(self):
728        """
729        """
730        self.plot_data.SetValue("")
731        self.on_reset(event=None)
[8b21fa7]732
[91d910d]733    def on_reset(self, event=None):
[b659551]734        """
[7116b6e0]735        Resets inversion parameters
[b659551]736        """
[6d3d5ff]737        self.nfunc = self._manager.DEFAULT_NFUNC
738        self.d_max = self._manager.DEFAULT_DMAX
739        self.alpha = self._manager.DEFAULT_ALPHA
[b659551]740        self.qmin_ctl.SetValue("")
741        self.qmax_ctl.SetValue("")
742        self.time_ctl.SetValue("")
[a4bd2ac]743        self.rg_ctl.SetValue("")
744        self.iq0_ctl.SetValue("")
745        self.bck_ctl.SetValue("")
[b659551]746        self.chi2_ctl.SetValue("")
747        self.osc_ctl.SetValue("")
748        self.pos_ctl.SetValue("")
749        self.pos_err_ctl.SetValue("")
750        self.alpha_estimate_ctl.Enable(False)
751        self.alpha_estimate_ctl.SetLabel("")
[35adaf6]752        self.nterms_estimate_ctl.Enable(False)
753        self.nterms_estimate_ctl.SetLabel("")
[b659551]754        self._on_pars_changed()
[8b21fa7]755
[b659551]756    def _on_pars_changed(self, evt=None):
[f3d51f6]757        """
[7116b6e0]758        Called when an input parameter has changed
759        We will estimate the alpha parameter behind the
[8b21fa7]760        scenes.
[f3d51f6]761        """
[2a92852]762        flag, alpha, dmax, nfunc, qmin, qmax, height, width = self._read_pars()
[a4bd2ac]763        has_bck = self.bck_chk.IsChecked()
[8b21fa7]764
[f3d51f6]765        # If the pars are valid, estimate alpha
766        if flag:
[2a92852]767            self.nterms_estimate_ctl.Enable(False)
768            self.alpha_estimate_ctl.Enable(False)
[8b21fa7]769
[0d88a09]770            dataset = self.plot_data.GetValue()
[6ce7201]771            if dataset is not None and dataset.strip() != "":
[8b21fa7]772                self._manager.estimate_plot_inversion(alpha=alpha, nfunc=nfunc,
773                                                      d_max=dmax,
774                                                      q_min=qmin, q_max=qmax,
775                                                      bck=has_bck,
776                                                      height=height,
777                                                      width=width)
778
[7116b6e0]779    def _read_pars(self, evt=None):
780        """
[8b21fa7]781        """
[f3d51f6]782        alpha = 0
783        nfunc = 5
[8b21fa7]784        dmax = 120
785        qmin = 0
786        qmax = 0
[2a92852]787        height = 0
[8b21fa7]788        width = 0
[f3d51f6]789        flag = True
[2a92852]790        # Read slit height
791        try:
792            height_str = self.sheight_ctl.GetValue()
[3e41f43]793            if len(height_str.lstrip().rstrip()) == 0:
[2a92852]794                height = 0
795            else:
796                height = float(height_str)
797                self.sheight_ctl.SetBackgroundColour(wx.WHITE)
798                self.sheight_ctl.Refresh()
799        except:
800            flag = False
801            self.sheight_ctl.SetBackgroundColour("pink")
802            self.sheight_ctl.Refresh()
[8b21fa7]803
[2a92852]804        # Read slit width
805        try:
806            width_str = self.swidth_ctl.GetValue()
[8b21fa7]807            if len(width_str.lstrip().rstrip()) == 0:
[2a92852]808                width = 0
809            else:
810                width = float(width_str)
811                self.swidth_ctl.SetBackgroundColour(wx.WHITE)
812                self.swidth_ctl.Refresh()
813        except:
814            flag = False
815            self.swidth_ctl.SetBackgroundColour("pink")
816            self.swidth_ctl.Refresh()
[8b21fa7]817
[f3d51f6]818        # Read alpha
819        try:
820            alpha = float(self.alpha_ctl.GetValue())
821            self.alpha_ctl.SetBackgroundColour(wx.WHITE)
822            self.alpha_ctl.Refresh()
823        except:
824            flag = False
825            self.alpha_ctl.SetBackgroundColour("pink")
826            self.alpha_ctl.Refresh()
[8b21fa7]827
828        # Read d_max
[f3d51f6]829        try:
830            dmax = float(self.dmax_ctl.GetValue())
831            self.dmax_ctl.SetBackgroundColour(wx.WHITE)
832            self.dmax_ctl.Refresh()
833        except:
834            flag = False
835            self.dmax_ctl.SetBackgroundColour("pink")
836            self.dmax_ctl.Refresh()
[8b21fa7]837
[f3d51f6]838        # Read nfunc
839        try:
840            nfunc = int(self.nfunc_ctl.GetValue())
[6d3d5ff]841            npts = self._manager.get_npts()
[3e41f43]842            if npts > 0 and nfunc > npts:
843                message = "Number of function terms should be smaller "
844                message += "than the number of points"
[6d3d5ff]845                wx.PostEvent(self._manager.parent, StatusEvent(status=message))
[b659551]846                raise ValueError, message
[f3d51f6]847            self.nfunc_ctl.SetBackgroundColour(wx.WHITE)
848            self.nfunc_ctl.Refresh()
849        except:
850            flag = False
851            self.nfunc_ctl.SetBackgroundColour("pink")
852            self.nfunc_ctl.Refresh()
[8b21fa7]853
[634f1cf]854        # Read qmin
855        try:
856            qmin_str = self.qmin_ctl.GetValue()
[3e41f43]857            if len(qmin_str.lstrip().rstrip()) == 0:
[634f1cf]858                qmin = None
859            else:
860                qmin = float(qmin_str)
861                self.qmin_ctl.SetBackgroundColour(wx.WHITE)
862                self.qmin_ctl.Refresh()
863        except:
864            flag = False
865            self.qmin_ctl.SetBackgroundColour("pink")
866            self.qmin_ctl.Refresh()
[8b21fa7]867
[634f1cf]868        # Read qmax
869        try:
870            qmax_str = self.qmax_ctl.GetValue()
[3e41f43]871            if len(qmax_str.lstrip().rstrip()) == 0:
[634f1cf]872                qmax = None
873            else:
874                qmax = float(qmax_str)
875                self.qmax_ctl.SetBackgroundColour(wx.WHITE)
876                self.qmax_ctl.Refresh()
877        except:
878            flag = False
879            self.qmax_ctl.SetBackgroundColour("pink")
880            self.qmax_ctl.Refresh()
[8b21fa7]881
[2a92852]882        return flag, alpha, dmax, nfunc, qmin, qmax, height, width
[8b21fa7]883
[a00ee4c]884    def _on_explore(self, evt):
885        """
[7116b6e0]886        Invoke the d_max exploration dialog
[a00ee4c]887        """
888        from explore_dialog import ExploreDialog
[6d3d5ff]889        if self._manager._last_pr is not None:
890            pr = self._manager._create_plot_pr()
[a00ee4c]891            dialog = ExploreDialog(pr, 10, None, -1, "")
[3d250da3]892            dialog.Show()
[a00ee4c]893        else:
894            message = "No data to analyze. Please load a data set to proceed."
[6d3d5ff]895            wx.PostEvent(self._manager.parent, StatusEvent(status=message))
[8b21fa7]896
[f3d51f6]897    def _on_invert(self, evt):
898        """
[7116b6e0]899        Perform inversion
[8b21fa7]900
901        :param silent: when True, there will be no output for the user
902
[f3d51f6]903        """
904        # Get the data from the form
905        # Push it to the manager
[8b21fa7]906
[2a92852]907        flag, alpha, dmax, nfunc, qmin, qmax, height, width = self._read_pars()
[a4bd2ac]908        has_bck = self.bck_chk.IsChecked()
[8b21fa7]909
[f3d51f6]910        if flag:
[0d88a09]911            dataset = self.plot_data.GetValue()
[8b21fa7]912            if dataset == None or len(dataset.strip()) == 0:
[3e41f43]913                message = "No data to invert. Select a data set before"
914                message += " proceeding with P(r) inversion."
[6d3d5ff]915                wx.PostEvent(self._manager.parent, StatusEvent(status=message))
[f3d51f6]916            else:
[8b21fa7]917                self._manager.setup_plot_inversion(alpha=alpha, nfunc=nfunc,
918                                                   d_max=dmax,
919                                                   q_min=qmin, q_max=qmax,
920                                                   bck=has_bck,
921                                                   height=height,
922                                                   width=width)
[f3d51f6]923        else:
[3e41f43]924            message = "The P(r) form contains invalid values: "
925            message += "please submit it again."
[f3d51f6]926            wx.PostEvent(self.parent, StatusEvent(status=message))
[8b21fa7]927
[75df58b]928    def _change_file(self, evt=None, filepath=None, data=None):
[f3d51f6]929        """
[7116b6e0]930        Choose a new input file for I(q)
[f3d51f6]931        """
[6d3d5ff]932        if not self._manager is None:
[75df58b]933            self.plot_data.SetValue(str(data.name))
934            try:
[6d3d5ff]935                self._manager.show_data(data=data, reset=True)
[75df58b]936                self._on_pars_changed(None)
937                self._on_invert(None)
938            except:
939                msg = "InversionControl._change_file: %s" % sys.exc_value
[8b21fa7]940                logging.error(msg)
[119a11d]941
[dea2f6e]942    def on_help(self, event):
[7116b6e0]943        """
[dea2f6e]944        Bring up the P(r) Documentation whenever
945        the HELP button is clicked.
[8b21fa7]946
[dea2f6e]947        Calls DocumentationWindow with the path of the location within the
948        documentation tree (after /doc/ ....".  Note that when using old
949        versions of Wx (before 2.9) and thus not the release version of
950        installers, the help comes up at the top level of the file as
951        webbrowser does not pass anything past the # to the browser when it is
952        running "file:///...."
[8b21fa7]953
[dea2f6e]954    :param evt: Triggers on clicking the help button
955    """
[8b21fa7]956
[5a58656]957        _TreeLocation = "user/sasgui/perspectives/pr/pr_help.html"
[3db44fb]958        _doc_viewer = DocumentationWindow(self, -1, _TreeLocation, "",
959                                          "P(r) Help")
[dea2f6e]960
961
[b659551]962class PrDistDialog(wx.Dialog):
963    """
[7116b6e0]964    Property dialog to let the user change the number
965    of points on the P(r) plot.
[b659551]966    """
967    def __init__(self, parent, id):
[b699768]968        from sas.sascalc.pr.invertor import help
[b659551]969        wx.Dialog.__init__(self, parent, id, size=(250, 120))
[8b21fa7]970        self.SetTitle("P(r) distribution")
971
[b659551]972
973        vbox = wx.BoxSizer(wx.VERTICAL)
[8b21fa7]974
[b659551]975        label_npts = wx.StaticText(self, -1, "Number of points")
[75df58b]976        self.npts_ctl = PrTextCtrl(self, -1, size=(100, 20))
[8b21fa7]977
[75df58b]978        pars_sizer = wx.GridBagSizer(5, 5)
[b659551]979        iy = 0
[75df58b]980        pars_sizer.Add(label_npts, (iy, 0), (1, 1), wx.LEFT, 15)
981        pars_sizer.Add(self.npts_ctl, (iy, 1), (1, 1), wx.RIGHT, 0)
[8b21fa7]982
983        vbox.Add(pars_sizer, 0, wx.ALL | wx.EXPAND, 15)
[b659551]984
985        static_line = wx.StaticLine(self, -1)
986        vbox.Add(static_line, 0, wx.EXPAND, 0)
[8b21fa7]987
988        button_ok = wx.Button(self, wx.ID_OK, "OK")
989        self.Bind(wx.EVT_BUTTON, self._checkValues, button_ok)
990        button_cancel = wx.Button(self, wx.ID_CANCEL, "Cancel")
991
[b659551]992        sizer_button = wx.BoxSizer(wx.HORIZONTAL)
[8b21fa7]993        sizer_button.Add((20, 20), 1, wx.EXPAND | wx.ADJUST_MINSIZE, 0)
994        sizer_button.Add(button_ok, 0, wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
995        sizer_button.Add(button_cancel, 0,
996                         wx.LEFT | wx.RIGHT | wx.ADJUST_MINSIZE, 10)
997        vbox.Add(sizer_button, 0, wx.EXPAND | wx.BOTTOM | wx.TOP, 10)
[b659551]998
999        self.SetSizer(vbox)
1000        self.SetAutoLayout(True)
[8b21fa7]1001
[b659551]1002        self.Layout()
1003        self.Centre()
1004
1005    def _checkValues(self, event):
1006        """
[7116b6e0]1007        Check the dialog content.
[b659551]1008        """
1009        flag = True
1010        try:
1011            int(self.npts_ctl.GetValue())
1012            self.npts_ctl.SetBackgroundColour(wx.WHITE)
1013            self.npts_ctl.Refresh()
1014        except:
1015            flag = False
1016            self.npts_ctl.SetBackgroundColour("pink")
1017            self.npts_ctl.Refresh()
1018        if flag:
1019            event.Skip(True)
1020
1021    def get_content(self):
1022        """
[7116b6e0]1023        Return the content of the dialog.
1024        At this point the values have already been
1025        checked.
[b659551]1026        """
1027        value = int(self.npts_ctl.GetValue())
1028        return value
[8b21fa7]1029
[b659551]1030    def set_content(self, npts):
1031        """
[7116b6e0]1032        Initialize the content of the dialog.
[b659551]1033        """
1034        self.npts_ctl.SetValue("%i" % npts)
Note: See TracBrowser for help on using the repository browser.