source: sasview/prview/perspectives/pr/inversion_panel.py @ 6ea1b87

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 6ea1b87 was 0bae207, checked in by Mathieu Doucet <doucetm@…>, 16 years ago

Fixed problem with loading additional data on a scaled graph.

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