source: sasview/src/sas/perspectives/pr/inversion_panel.py @ 1805b87

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 1805b87 was 8b21fa7, checked in by Doucet, Mathieu <doucetm@…>, 10 years ago

pylint fixes

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