source: sasview/prview/perspectives/pr/inversion_panel.py @ 675e0ab

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 675e0ab was fde249c, checked in by Mathieu Doucet <doucetm@…>, 15 years ago

prview: completed first cut of functionality to save a P(r) inversion. Need to iron out the file format.

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