source: sasview/prview/perspectives/pr/inversion_panel.py @ 9fb814a

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 9fb814a was 55f5a77, checked in by Gervaise Alina <gervyh@…>, 14 years ago

working on guiframe load data

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