source: sasview/fittingview/src/sans/perspectives/fitting/fitpage.py @ 6c4130a

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 6c4130a was 83b81b8, checked in by Jae Cho <jhjcho@…>, 12 years ago

a little better data error control

  • Property mode set to 100644
File size: 128.4 KB
Line 
1"""
2    FitPanel class contains fields allowing to display results when
3    fitting  a model and one data
4"""
5import sys
6import wx
7import wx.lib.newevent
8import numpy
9import copy
10import math
11import time
12from sans.guiframe.events import StatusEvent
13from sans.guiframe.events import NewPlotEvent
14from sans.guiframe.dataFitting import check_data_validity
15from sans.guiframe.utils import format_number
16from sans.guiframe.utils import check_float
17
18(Chi2UpdateEvent, EVT_CHI2_UPDATE) = wx.lib.newevent.NewEvent()
19_BOX_WIDTH = 76
20_DATA_BOX_WIDTH = 300
21SMEAR_SIZE_L = 0.00
22SMEAR_SIZE_H = 0.00
23
24from sans.perspectives.fitting.basepage import BasicPage as BasicPage
25from sans.perspectives.fitting.basepage import PageInfoEvent as PageInfoEvent
26from sans.models.qsmearing import smear_selection
27
28
29class FitPage(BasicPage):
30    """
31    FitPanel class contains fields allowing to display results when
32    fitting  a model and one data
33   
34    :note: For Fit to be performed the user should check at least one parameter
35        on fit Panel window.
36    """
37
38    def __init__(self, parent, color='rand'):
39        """
40        Initialization of the Panel
41        """
42        BasicPage.__init__(self, parent, color=color)
43       
44        ## draw sizer
45        self._fill_data_sizer()
46        self.is_2D = None
47        self.fit_started = False
48        self.weightbt_string = None
49        self.m_name = None
50        # get smear info from data
51        self._get_smear_info()
52        self._fill_model_sizer(self.sizer1)
53        self._get_defult_custom_smear()
54        self._fill_range_sizer()
55        self._set_smear(self.data)
56        self.Bind(EVT_CHI2_UPDATE, self.on_complete_chisqr)
57        # bind key event
58        self.Bind(wx.EVT_RIGHT_DOWN, self.on_right_down)
59        self._set_bookmark_flag(False)
60        self._set_save_flag(False)
61        self._set_preview_flag(False)
62        self._set_copy_flag(False)
63        self._set_paste_flag(False)
64        self.btFit.SetFocus()
65        self.enable_fit_button()
66        self.fill_data_combobox(data_list=self.data_list)
67        #create a default data for an empty panel
68        self.create_default_data()
69   
70    def enable_fit_button(self):
71        """
72        Enable fit button if data is valid and model is valid
73        """
74        flag = check_data_validity(self.data) & (self.model is not None)
75        self.btFit.Enable(flag)
76       
77    def _fill_data_sizer(self):
78        """
79        fill sizer 0 with data info
80        """
81        self.data_box_description = wx.StaticBox(self, -1, 'I(q) Data Source')
82        if check_data_validity(self.data):
83            dname_color = wx.BLUE
84        else:
85            dname_color = wx.RED
86        self.data_box_description.SetForegroundColour(dname_color)
87        boxsizer1 = wx.StaticBoxSizer(self.data_box_description, wx.VERTICAL)
88        #----------------------------------------------------------
89        sizer_data = wx.BoxSizer(wx.HORIZONTAL)
90        self.dataSource = wx.ComboBox(self, -1, style=wx.CB_READONLY)
91        wx.EVT_COMBOBOX(self.dataSource, -1, self.on_select_data)
92        self.dataSource.SetMinSize((_DATA_BOX_WIDTH, -1))
93        sizer_data.Add(wx.StaticText(self, -1, 'Name : '))
94        sizer_data.Add(self.dataSource)
95        sizer_data.Add((0, 5))
96        boxsizer1.Add(sizer_data, 0, wx.ALL, 10)
97        self.sizer0.Add(boxsizer1, 0, wx.EXPAND | wx.ALL, 10)
98        self.sizer0.Layout()
99       
100    def enable_datasource(self):
101        """
102        Enable or disable data source control depending on existing data
103        """
104        if not self.data_list:
105            self.dataSource.Disable()
106        else:
107            self.dataSource.Enable()
108           
109    def fill_data_combobox(self, data_list):
110        """
111        Get a list of data and fill the corresponding combobox
112        """
113        self.dataSource.Clear()
114        self.data_list = data_list
115        self.enable_datasource()
116        if len(data_list) > 0:
117            #find the maximum range covering all data
118            qmin, qmax, npts = self.compute_data_set_range(data_list)
119            self.qmin_data_set = qmin
120            self.qmax_data_set = qmax
121            self.npts_data_set = npts
122
123            self.qmin.SetValue(str(self.qmin_data_set))
124            self.qmax.SetValue(str(self.qmax_data_set))
125            self.qmin.SetBackgroundColour("white")
126            self.qmax.SetBackgroundColour("white")
127            self.qmin_x = self.qmin_data_set
128            self.qmax_x = self.qmax_data_set
129            self.state.qmin = self.qmin_x
130            self.state.qmax = self.qmax_x
131        is_data = False
132        for data in self.data_list:
133            if data is not None:
134                self.dataSource.Append(str(data.name), clientData=data)
135                if not is_data:
136                    is_data = check_data_validity(data)
137        self.dataSource.SetSelection(0)
138        self.on_select_data(event=None)
139               
140    def on_select_data(self, event=None):
141        """
142        On_select_data
143        """
144        if event is None and self.dataSource.GetCount() > 0:
145            data = self.dataSource.GetClientData(0)
146            self.set_data(data)
147        elif self.dataSource.GetCount() > 0:
148            pos = self.dataSource.GetSelection()
149            data = self.dataSource.GetClientData(pos)
150            self.set_data(data)
151   
152    def _on_fit_complete(self):
153        """
154        When fit is complete ,reset the fit button label.
155        """
156        self.fit_started = False
157        self.set_fitbutton()
158       
159    def _is_2D(self):
160        """
161        Check if data_name is Data2D
162       
163        :return: True or False
164       
165        """
166        if self.data.__class__.__name__ == "Data2D" or \
167                        self.enable2D:
168            return True
169        return False
170           
171    def _on_engine_change(self, name):
172        """
173        get the current name of the fit engine type
174         and update the panel accordingly
175        """
176       
177        self.engine_type = str(name)
178        self.state.engine_type = self.engine_type
179        if not self.is_mac:
180            if len(self.parameters) == 0:
181                self.Layout()
182                return
183            self.Layout()
184            self.Refresh()
185       
186    def _fill_range_sizer(self):
187        """
188        Fill the sizer containing the plotting range
189        add  access to npts
190        """
191        is_2Ddata = False
192       
193        # Check if data is 2D
194        if self.data.__class__.__name__ == "Data2D" or \
195                        self.enable2D:
196            is_2Ddata = True
197           
198        title = "Fitting"
199        #smear messages & titles
200        smear_message_none = "No smearing is selected..."
201        smear_message_dqdata = "The dQ data is being used for smearing..."
202        smear_message_2d = \
203              "Higher accuracy is very time-expensive. Use it with care..."
204        smear_message_new_ssmear = \
205              "Please enter only the value of interest to customize smearing..."
206        smear_message_new_psmear = \
207              "Please enter both; the dQ will be generated by interpolation..."
208        smear_message_2d_x_title = "<dQp>[1/A]:"
209        smear_message_2d_y_title = "<dQs>[1/A]:"
210        smear_message_pinhole_min_title = "dQ_low[1/A]:"
211        smear_message_pinhole_max_title = "dQ_high[1/A]:"
212        smear_message_slit_height_title = "Slit height[1/A]:"
213        smear_message_slit_width_title = "Slit width[1/A]:"
214       
215        self._get_smear_info()
216       
217        #Sizers
218        box_description_range = wx.StaticBox(self, -1, str(title))
219        box_description_range.SetForegroundColour(wx.BLUE)
220        boxsizer_range = wx.StaticBoxSizer(box_description_range, wx.VERTICAL)
221        self.sizer_set_smearer = wx.BoxSizer(wx.VERTICAL)
222        sizer_smearer = wx.BoxSizer(wx.HORIZONTAL)
223        self.sizer_new_smear = wx.BoxSizer(wx.HORIZONTAL)
224        self.sizer_set_masking = wx.BoxSizer(wx.HORIZONTAL)
225        sizer_chi2 = wx.BoxSizer(wx.VERTICAL)
226        smear_set_box = wx.StaticBox(self, -1, 'Set Instrumental Smearing')
227        sizer_smearer_box = wx.StaticBoxSizer(smear_set_box, wx.HORIZONTAL)
228        sizer_smearer_box.SetMinSize((_DATA_BOX_WIDTH, 60))
229       
230        weighting_set_box = wx.StaticBox(self, -1, \
231                                'Set Weighting by Selecting dI Source')
232        weighting_box = wx.StaticBoxSizer(weighting_set_box, wx.HORIZONTAL)
233        sizer_weighting = wx.BoxSizer(wx.HORIZONTAL)
234        weighting_box.SetMinSize((_DATA_BOX_WIDTH, 40))
235        #Filling the sizer containing weighting info.
236        self.dI_noweight = wx.RadioButton(self, -1, 'No Weighting',
237                                          style=wx.RB_GROUP)
238        self.dI_didata = wx.RadioButton(self, -1, 'Use dI Data')
239        self.dI_sqrdata = wx.RadioButton(self, -1, 'Use |sqrt(I Data)|')
240        self.dI_idata = wx.RadioButton(self, -1, 'Use |I Data|')
241        self.Bind(wx.EVT_RADIOBUTTON, self.onWeighting,
242                  id=self.dI_noweight.GetId())
243        self.Bind(wx.EVT_RADIOBUTTON, self.onWeighting,
244                  id=self.dI_didata.GetId())
245        self.Bind(wx.EVT_RADIOBUTTON, self.onWeighting,
246                  id=self.dI_sqrdata.GetId())
247        self.Bind(wx.EVT_RADIOBUTTON, self.onWeighting,
248                  id=self.dI_idata.GetId())
249        self.dI_didata.SetValue(True)
250        # add 4 types of weighting to the sizer
251        sizer_weighting.Add(self.dI_noweight, 0, wx.LEFT, 10)
252        sizer_weighting.Add((14, 10))
253        sizer_weighting.Add(self.dI_didata)
254        sizer_weighting.Add((14, 10))
255        sizer_weighting.Add(self.dI_sqrdata)
256        sizer_weighting.Add((14, 10))
257        sizer_weighting.Add(self.dI_idata)
258        sizer_weighting.Add((10, 10))
259        self.dI_noweight.Enable(False)
260        self.dI_didata.Enable(False)
261        self.dI_sqrdata.Enable(False)
262        self.dI_idata.Enable(False)
263        weighting_box.Add(sizer_weighting)
264       
265        sizer_fit = wx.GridSizer(2, 4, 2, 6)
266       
267        # combobox for smear2d accuracy selection
268        self.smear_accuracy = wx.ComboBox(self, -1, size=(50, -1),
269                                          style=wx.CB_READONLY)
270        self._set_accuracy_list()
271        self.smear_accuracy.SetValue(self.smear2d_accuracy)
272        self.smear_accuracy.SetSelection(0)
273        self.smear_accuracy.SetToolTipString(\
274            "'Higher' uses more Gaussian points for smearing computation.")
275                   
276        wx.EVT_COMBOBOX(self.smear_accuracy, -1, self._on_select_accuracy)
277
278        #Fit button
279        self.btFit = wx.Button(self, wx.NewId(), 'Fit', size=(88, 25))
280        self.default_bt_colour = self.btFit.GetDefaultAttributes()
281        self.btFit.Bind(wx.EVT_BUTTON, self._onFit, id=self.btFit.GetId())
282        self.btFit.SetToolTipString("Start fitting.")
283       
284        #textcntrl for custom resolution
285        self.smear_pinhole_max = self.ModelTextCtrl(self, -1,
286                            size=(_BOX_WIDTH - 25, 20),
287                            style=wx.TE_PROCESS_ENTER,
288                            text_enter_callback=self.onPinholeSmear)
289        self.smear_pinhole_min = self.ModelTextCtrl(self, -1,
290                            size=(_BOX_WIDTH - 25, 20),
291                            style=wx.TE_PROCESS_ENTER,
292                            text_enter_callback=self.onPinholeSmear)
293        self.smear_slit_height = self.ModelTextCtrl(self, -1,
294                            size=(_BOX_WIDTH - 25, 20),
295                            style=wx.TE_PROCESS_ENTER,
296                            text_enter_callback=self.onSlitSmear)
297        self.smear_slit_width = self.ModelTextCtrl(self, -1,
298                            size=(_BOX_WIDTH - 25, 20),
299                            style=wx.TE_PROCESS_ENTER,
300                            text_enter_callback=self.onSlitSmear)
301
302        ## smear
303        self.smear_data_left = BGTextCtrl(self, -1,
304                                         size=(_BOX_WIDTH - 25, 20), style=0)
305        self.smear_data_left.SetValue(str(self.dq_l))
306        self.smear_data_right = BGTextCtrl(self, -1,
307                                        size=(_BOX_WIDTH - 25, 20), style=0)
308        self.smear_data_right.SetValue(str(self.dq_r))
309
310        #set default values for smear
311        self.smear_pinhole_max.SetValue(str(self.dx_max))
312        self.smear_pinhole_min.SetValue(str(self.dx_min))
313        self.smear_slit_height.SetValue(str(self.dxl))
314        self.smear_slit_width.SetValue(str(self.dxw))
315
316        #Filling the sizer containing instruments smearing info.
317        self.disable_smearer = wx.RadioButton(self, -1,
318                                              'None', style=wx.RB_GROUP)
319        self.enable_smearer = wx.RadioButton(self, -1,
320                                             'Use dQ Data')
321        #self.enable_smearer.SetToolTipString(
322        #"Click to use the loaded dQ data for smearing.")
323        self.pinhole_smearer = wx.RadioButton(self, -1,
324                                              'Custom Pinhole Smear')
325        #self.pinhole_smearer.SetToolTipString
326        #("Click to input custom resolution for pinhole smearing.")
327        self.slit_smearer = wx.RadioButton(self, -1, 'Custom Slit Smear')
328        #self.slit_smearer.SetToolTipString
329        #("Click to input custom resolution for slit smearing.")
330        self.Bind(wx.EVT_RADIOBUTTON, self.onSmear,
331                  id=self.disable_smearer.GetId())
332        self.Bind(wx.EVT_RADIOBUTTON, self.onSmear,
333                  id=self.enable_smearer.GetId())
334        self.Bind(wx.EVT_RADIOBUTTON, self.onPinholeSmear,
335                  id=self.pinhole_smearer.GetId())
336        self.Bind(wx.EVT_RADIOBUTTON, self.onSlitSmear,
337                  id=self.slit_smearer.GetId())
338        self.disable_smearer.SetValue(True)
339       
340        # add 4 types of smearing to the sizer
341        sizer_smearer.Add(self.disable_smearer, 0, wx.LEFT, 10)
342        sizer_smearer.Add((10, 10))
343        sizer_smearer.Add(self.enable_smearer)
344        sizer_smearer.Add((10, 10))
345        sizer_smearer.Add(self.pinhole_smearer)
346        sizer_smearer.Add((10, 10))
347        sizer_smearer.Add(self.slit_smearer)
348        sizer_smearer.Add((10, 10))
349       
350        # StaticText for chi2, N(for fitting), Npts
351        self.tcChi = BGTextCtrl(self, -1, "-", size=(75, 20), style=0)
352        self.tcChi.SetToolTipString("Chi2/Npts(Fit)")
353        self.Npts_fit = BGTextCtrl(self, -1, "-", size=(75, 20), style=0)
354        self.Npts_fit.SetToolTipString(\
355                            " Npts : number of points selected for fitting")
356        self.Npts_total = self.ModelTextCtrl(self, -1,
357                        size=(_BOX_WIDTH, 20),
358                        style=wx.TE_PROCESS_ENTER,
359                        text_enter_callback=self._onQrangeEnter)
360        self.Npts_total.SetValue(format_number(self.npts_x))
361        self.Npts_total.SetToolTipString(\
362                                " Total Npts : total number of data points")
363       
364        # Update and Draw button
365        self.draw_button = wx.Button(self, wx.NewId(),
366                                     'Compute', size=(88, 24))
367        self.draw_button.Bind(wx.EVT_BUTTON, \
368                              self._onDraw, id=self.draw_button.GetId())
369        self.draw_button.SetToolTipString("Compute and Draw.")
370       
371        box_description_1 = wx.StaticText(self, -1, '   Chi2/Npts')
372        box_description_2 = wx.StaticText(self, -1, 'Npts(Fit)')
373        box_description_3 = wx.StaticText(self, -1, 'Total Npts')
374        box_description_3.SetToolTipString( \
375                                " Total Npts : total number of data points")
376       
377        sizer_fit.Add(box_description_1, 0, 0)
378        sizer_fit.Add(box_description_2, 0, 0)
379        sizer_fit.Add(box_description_3, 0, 0)
380        sizer_fit.Add(self.draw_button, 0, 0)
381        sizer_fit.Add(self.tcChi, 0, 0)
382        sizer_fit.Add(self.Npts_fit, 0, 0)
383        sizer_fit.Add(self.Npts_total, 0, 0)
384        sizer_fit.Add(self.btFit, 0, 0)
385
386        # StaticText for smear
387        self.smear_description_none = wx.StaticText(self, -1,
388                                    smear_message_none, style=wx.ALIGN_LEFT)
389        self.smear_description_dqdata = wx.StaticText(self,
390                                -1, smear_message_dqdata, style=wx.ALIGN_LEFT)
391        self.smear_description_type = wx.StaticText(self,
392                                     -1, "Type:", style=wx.ALIGN_LEFT)
393        self.smear_description_accuracy_type = wx.StaticText(self, -1,
394                                        "Accuracy:", style=wx.ALIGN_LEFT)
395        self.smear_description_smear_type = BGTextCtrl(self, -1,
396                                                       size=(57, 20), style=0)
397        self.smear_description_smear_type.SetValue(str(self.dq_l))
398        self.SetBackgroundColour(self.GetParent().GetBackgroundColour())
399        self.smear_description_2d = wx.StaticText(self, -1,
400                                    smear_message_2d, style=wx.ALIGN_LEFT)
401        self.smear_message_new_s = wx.StaticText(self, -1,
402                         smear_message_new_ssmear, style=wx.ALIGN_LEFT)
403        self.smear_message_new_p = wx.StaticText(self, -1,
404                            smear_message_new_psmear, style=wx.ALIGN_LEFT)
405        self.smear_description_2d_x = wx.StaticText(self, -1,
406                            smear_message_2d_x_title, style=wx.ALIGN_LEFT)
407        self.smear_description_2d_x.SetToolTipString(\
408                                        "  dQp(parallel) in q_r direction.")
409        self.smear_description_2d_y = wx.StaticText(self, -1,
410                            smear_message_2d_y_title, style=wx.ALIGN_LEFT)
411        self.smear_description_2d_y.SetToolTipString(\
412                                    " dQs(perpendicular) in q_phi direction.")
413        self.smear_description_pin_min = wx.StaticText(self, -1,
414                        smear_message_pinhole_min_title, style=wx.ALIGN_LEFT)
415        self.smear_description_pin_max = wx.StaticText(self, -1,
416                        smear_message_pinhole_max_title, style=wx.ALIGN_LEFT)
417        self.smear_description_slit_height = wx.StaticText(self, -1,
418                        smear_message_slit_height_title, style=wx.ALIGN_LEFT)
419        self.smear_description_slit_width = wx.StaticText(self, -1,
420                        smear_message_slit_width_title, style=wx.ALIGN_LEFT)
421       
422        #arrange sizers
423        self.sizer_set_smearer.Add(sizer_smearer)
424        self.sizer_set_smearer.Add((10, 10))
425        self.sizer_set_smearer.Add(self.smear_description_none,
426                                    0, wx.CENTER, 10)
427        self.sizer_set_smearer.Add(self.smear_description_dqdata,
428                                    0, wx.CENTER, 10)
429        self.sizer_set_smearer.Add(self.smear_description_2d,
430                                    0, wx.CENTER, 10)
431        self.sizer_new_smear.Add(self.smear_description_type,
432                                  0, wx.CENTER, 10)
433        self.sizer_new_smear.Add(self.smear_description_accuracy_type,
434                                  0, wx.CENTER, 10)
435        self.sizer_new_smear.Add(self.smear_accuracy)
436        self.sizer_new_smear.Add(self.smear_description_smear_type,
437                                  0, wx.CENTER, 10)
438        self.sizer_new_smear.Add((15, -1))
439        self.sizer_new_smear.Add(self.smear_description_2d_x,
440                                  0, wx.CENTER, 10)
441        self.sizer_new_smear.Add(self.smear_description_pin_min,
442                                  0, wx.CENTER, 10)
443        self.sizer_new_smear.Add(self.smear_description_slit_height,
444                                  0, wx.CENTER, 10)
445
446        self.sizer_new_smear.Add(self.smear_pinhole_min,
447                                  0, wx.CENTER, 10)
448        self.sizer_new_smear.Add(self.smear_slit_height,
449                                  0, wx.CENTER, 10)
450        self.sizer_new_smear.Add(self.smear_data_left,
451                                  0, wx.CENTER, 10)
452        self.sizer_new_smear.Add((20, -1))
453        self.sizer_new_smear.Add(self.smear_description_2d_y,
454                                  0, wx.CENTER, 10 )
455        self.sizer_new_smear.Add(self.smear_description_pin_max,
456                                  0, wx.CENTER, 10 )
457        self.sizer_new_smear.Add(self.smear_description_slit_width,
458                                  0, wx.CENTER, 10 )
459
460        self.sizer_new_smear.Add(self.smear_pinhole_max, 0, wx.CENTER, 10)
461        self.sizer_new_smear.Add(self.smear_slit_width, 0, wx.CENTER, 10)
462        self.sizer_new_smear.Add(self.smear_data_right, 0, wx.CENTER, 10)
463           
464        self.sizer_set_smearer.Add(self.smear_message_new_s, 0, wx.CENTER, 10)
465        self.sizer_set_smearer.Add(self.smear_message_new_p, 0, wx.CENTER, 10)
466        self.sizer_set_smearer.Add((5, 2))
467        self.sizer_set_smearer.Add(self.sizer_new_smear, 0, wx.CENTER, 10)
468       
469        # add all to chi2 sizer
470        sizer_smearer_box.Add(self.sizer_set_smearer)
471        sizer_chi2.Add(sizer_smearer_box)
472        sizer_chi2.Add((-1, 5))
473        sizer_chi2.Add(weighting_box)
474        sizer_chi2.Add((-1, 5))
475       
476        # hide all smear messages and textctrl
477        self._hide_all_smear_info()
478       
479        # get smear_selection
480        self.current_smearer = smear_selection(self.data, self.model)
481
482        # Show only the relevant smear messages, etc
483        if self.current_smearer == None:
484            if not is_2Ddata:
485                self.smear_description_none.Show(True)
486                self.enable_smearer.Disable()
487            else:
488                self.smear_description_none.Show(True)
489                self.slit_smearer.Disable()
490            if self.data == None:
491                self.slit_smearer.Disable()
492                self.pinhole_smearer.Disable()
493                self.enable_smearer.Disable()
494        else:
495            self._show_smear_sizer()
496        boxsizer_range.Add(self.sizer_set_masking)
497        #2D data? default
498        is_2Ddata = False
499       
500        #check if it is 2D data
501        if self.data.__class__.__name__ == "Data2D" or self.enable2D:
502            is_2Ddata = True
503           
504        self.sizer5.Clear(True)
505     
506        self.qmin = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
507                                    style=wx.TE_PROCESS_ENTER,
508                                    text_enter_callback=self._onQrangeEnter)
509        self.qmin.SetValue(str(self.qmin_x))
510        self.qmin.SetToolTipString("Minimun value of Q in linear scale.")
511     
512        self.qmax = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
513                                       style=wx.TE_PROCESS_ENTER,
514                                       text_enter_callback=self._onQrangeEnter)
515        self.qmax.SetValue(str(self.qmax_x))
516        self.qmax.SetToolTipString("Maximum value of Q in linear scale.")
517        id = wx.NewId()
518        self.reset_qrange = wx.Button(self, id, 'Reset', size=(77, 20))
519     
520        self.reset_qrange.Bind(wx.EVT_BUTTON, self.on_reset_clicked, id=id)
521        self.reset_qrange.SetToolTipString("Reset Q range to the default")
522     
523        sizer = wx.GridSizer(2, 4, 2, 6)
524
525        self.btEditMask = wx.Button(self, wx.NewId(), 'Editor', size=(88, 23))
526        self.btEditMask.Bind(wx.EVT_BUTTON, self._onMask,
527                             id=self.btEditMask.GetId())
528        self.btEditMask.SetToolTipString("Edit Mask.")
529        self.EditMask_title = wx.StaticText(self, -1, ' Masking(2D)')
530
531        sizer.Add(wx.StaticText(self, -1, '   Q range'))
532        sizer.Add(wx.StaticText(self, -1, ' Min[1/A]'))
533        sizer.Add(wx.StaticText(self, -1, ' Max[1/A]'))
534        sizer.Add(self.EditMask_title)
535        sizer.Add(self.reset_qrange)
536        sizer.Add(self.qmin)
537        sizer.Add(self.qmax)
538        #sizer.Add(self.theory_npts_tcrtl)
539        sizer.Add(self.btEditMask)
540        boxsizer_range.Add(sizer_chi2)
541        boxsizer_range.Add((10, 10))
542        boxsizer_range.Add(sizer)
543       
544        boxsizer_range.Add((10, 15))
545        boxsizer_range.Add(sizer_fit)
546        if is_2Ddata:
547            self.btEditMask.Enable()
548            self.EditMask_title.Enable()
549        else:
550            self.btEditMask.Disable()
551            self.EditMask_title.Disable()
552        ## save state
553        self.save_current_state()
554        self.sizer5.Add(boxsizer_range, 0, wx.EXPAND | wx.ALL, 10)
555        self.sizer5.Layout()
556
557       
558    def _set_sizer_dispersion(self):
559        """
560        draw sizer with gaussian dispersity parameters
561        """
562        self.fittable_param = []
563        self.fixed_param = []
564        self.orientation_params_disp = []
565
566        self.sizer4_4.Clear(True)
567        if self.model == None:
568            ##no model is selected
569            return
570        if not self.enable_disp.GetValue():
571            ## the user didn't select dispersity display
572            return
573           
574        self._reset_dispersity()
575       
576        ## fill a sizer with the combobox to select dispersion type
577        model_disp = wx.StaticText(self, -1, 'Function')
578        CHECK_STATE = self.cb1.GetValue()
579        import sans.models.dispersion_models
580        self.polydisp = sans.models.dispersion_models.models
581
582        ix = 0
583        iy = 0
584        disp = wx.StaticText(self, -1, ' ')
585        self.sizer4_4.Add(disp, (iy, ix), (1, 1),
586                          wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
587        ix += 1
588        values = wx.StaticText(self, -1, 'PD[ratio]')
589        polytext = "Polydispersity (= STD/mean); "
590        polytext += "the standard deviation over the mean value."
591        values.SetToolTipString(polytext)
592
593        self.sizer4_4.Add(values, (iy, ix), (1, 1),
594                          wx.EXPAND | wx.ADJUST_MINSIZE, 0)
595        ix += 2
596        if self.is_mac:
597            err_text = 'Error'
598        else:
599            err_text = ''
600        self.text_disp_1 = wx.StaticText(self, -1, err_text)
601        self.sizer4_4.Add(self.text_disp_1, (iy, ix), (1, 1), \
602                          wx.EXPAND | wx.ADJUST_MINSIZE, 0)
603       
604        ix += 1
605        self.text_disp_min = wx.StaticText(self, -1, 'Min')
606        self.sizer4_4.Add(self.text_disp_min, (iy, ix), (1, 1), \
607                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
608
609        ix += 1
610        self.text_disp_max = wx.StaticText(self, -1, 'Max')
611        self.sizer4_4.Add(self.text_disp_max, (iy, ix), (1, 1),
612                          wx.EXPAND | wx.ADJUST_MINSIZE, 0)
613       
614        ix += 1
615        npts = wx.StaticText(self, -1, 'Npts')
616        npts.SetToolTipString("Number of sampling points for the numerical\n\
617        integration over the distribution function.")
618        self.sizer4_4.Add(npts, (iy, ix), (1, 1),
619                          wx.EXPAND | wx.ADJUST_MINSIZE, 0)
620        ix += 1
621        nsigmas = wx.StaticText(self, -1, 'Nsigs')
622        nsigmas.SetToolTipString("Number of sigmas between which the range\n\
623         of the distribution function will be used for weighting. \n\
624        The value '3' covers 99.5% for Gaussian distribution \n\
625        function. Note: Not recommended to change this value.")
626        self.sizer4_4.Add(nsigmas, (iy, ix), (1, 1),
627                          wx.EXPAND | wx.ADJUST_MINSIZE, 0)
628        ix += 1
629        self.sizer4_4.Add(model_disp, (iy, ix), (1, 1),
630                          wx.EXPAND | wx.ADJUST_MINSIZE, 0)
631       
632        if self.engine_type == "park":
633            self.text_disp_max.Show(True)
634            self.text_disp_min.Show(True)
635
636        for item in self.model.dispersion.keys():
637            if not item in self.model.orientation_params:
638                if not item in self.disp_cb_dict:
639                    self.disp_cb_dict[item] = None
640                name0 = "Distribution of " + item
641                name1 = item + ".width"
642                name2 = item + ".npts"
643                name3 = item + ".nsigmas"
644                if not name1 in self.model.details:
645                    self.model.details[name1] = ["", None, None]
646
647                iy += 1
648                for p in self.model.dispersion[item].keys():
649       
650                    if p == "width":
651                        ix = 0
652                        cb = wx.CheckBox(self, -1, name0, (10, 10))
653                        cb.SetValue(CHECK_STATE)
654                        cb.SetToolTipString("Check mark to fit")
655                        wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
656                        self.sizer4_4.Add(cb, (iy, ix), (1, 1),
657                                wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 5)
658                        ix = 1
659                        value = self.model.getParam(name1)
660                        ctl1 = self.ModelTextCtrl(self, -1,
661                                                  size=(_BOX_WIDTH / 1.3, 20),
662                                                  style=wx.TE_PROCESS_ENTER)
663                        ctl1.SetLabel('PD[ratio]')
664                        poly_text = "Polydispersity (STD/mean) of %s\n" % item
665                        poly_text += "STD: the standard deviation"
666                        poly_text += " from the mean value."
667                        ctl1.SetToolTipString(poly_text)
668                        ctl1.SetValue(str(format_number(value, True)))
669                        self.sizer4_4.Add(ctl1, (iy, ix), (1, 1), wx.EXPAND)
670                        ## text to show error sign
671                        ix = 2
672                        text2 = wx.StaticText(self, -1, '+/-')
673                        self.sizer4_4.Add(text2, (iy, ix), (1, 1),
674                                          wx.EXPAND | wx.ADJUST_MINSIZE, 0)
675                        if not self.is_mac:
676                            text2.Hide()
677
678                        ix = 3
679                        ctl2 = wx.TextCtrl(self, -1,
680                                           size=(_BOX_WIDTH / 1.3, 20),
681                                           style=0)
682                 
683                        self.sizer4_4.Add(ctl2, (iy, ix), (1, 1),
684                                          wx.EXPAND | wx.ADJUST_MINSIZE, 0)
685                        if not self.is_mac:
686                            ctl2.Hide()
687
688                        ix = 4
689                        ctl3 = self.ModelTextCtrl(self, -1,
690                                                  size=(_BOX_WIDTH / 2, 20),
691                                                  style=wx.TE_PROCESS_ENTER,
692                                text_enter_callback=self._onparamRangeEnter)
693                       
694                        self.sizer4_4.Add(ctl3, (iy, ix), (1, 1),
695                                          wx.EXPAND | wx.ADJUST_MINSIZE, 0)
696                       
697                        ix = 5
698                        ctl4 = self.ModelTextCtrl(self, -1,
699                                                  size=(_BOX_WIDTH / 2, 20),
700                                                  style=wx.TE_PROCESS_ENTER,
701                            text_enter_callback=self._onparamRangeEnter)
702                       
703                        self.sizer4_4.Add(ctl4, (iy, ix), (1, 1),
704                                          wx.EXPAND | wx.ADJUST_MINSIZE, 0)
705
706                        if self.engine_type == "park":
707                            ctl3.Show(True)
708                            ctl4.Show(True)
709                                                             
710                    elif p == "npts":
711                        ix = 6
712                        value = self.model.getParam(name2)
713                        Tctl = self.ModelTextCtrl(self, -1,
714                                                  size=(_BOX_WIDTH / 2.2, 20),
715                                                  style=wx.TE_PROCESS_ENTER)
716                       
717                        Tctl.SetValue(str(format_number(value)))
718                        self.sizer4_4.Add(Tctl, (iy, ix), (1, 1),
719                                           wx.EXPAND | wx.ADJUST_MINSIZE, 0)
720                        self.fixed_param.append([None, name2, Tctl, None, None,
721                                                 None, None, None])
722                    elif p == "nsigmas":
723                        ix = 7
724                        value = self.model.getParam(name3)
725                        Tct2 = self.ModelTextCtrl(self, -1,
726                                                  size=(_BOX_WIDTH / 2.2, 20),
727                                                  style=wx.TE_PROCESS_ENTER)
728                       
729                        Tct2.SetValue(str(format_number(value)))
730                        self.sizer4_4.Add(Tct2, (iy, ix), (1, 1),
731                                           wx.EXPAND | wx.ADJUST_MINSIZE, 0)
732                        self.fixed_param.append([None, name3, Tct2,
733                                                 None, None, None,
734                                                 None, None])
735
736                ix = 8
737                disp_box = wx.ComboBox(self, -1, size=(65, -1),
738                                       style=wx.CB_READONLY, name='%s' % name1)
739                for key, value in self.polydisp.iteritems():
740                    name_disp = str(key)
741                    disp_box.Append(name_disp, value)
742                    disp_box.SetStringSelection("gaussian")
743                wx.EVT_COMBOBOX(disp_box, -1, self._on_disp_func)
744                self.sizer4_4.Add(disp_box, (iy, ix), (1, 1), wx.EXPAND)
745                self.fittable_param.append([cb, name1, ctl1, text2,
746                                            ctl2, ctl3, ctl4, disp_box])
747                           
748        ix = 0
749        iy += 1
750        self.sizer4_4.Add((20, 20), (iy, ix), (1, 1),
751                          wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
752        first_orient = True
753        for item in self.model.dispersion.keys():
754            if  item in self.model.orientation_params:
755                if not item in self.disp_cb_dict:
756                    self.disp_cb_dict[item] = None
757                name0 = "Distribution of " + item
758                name1 = item + ".width"
759                name2 = item + ".npts"
760                name3 = item + ".nsigmas"
761               
762                if not name1 in self.model.details:
763                    self.model.details[name1] = ["", None, None]
764 
765                iy += 1
766                for p in self.model.dispersion[item].keys():
767       
768                    if p == "width":
769                        ix = 0
770                        cb = wx.CheckBox(self, -1, name0, (10, 10))
771                        cb.SetValue(CHECK_STATE)
772                        cb.SetToolTipString("Check mark to fit")
773                        wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
774                        self.sizer4_4.Add(cb, (iy, ix), (1, 1),
775                                wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 5)
776                        if self.data.__class__.__name__ == "Data2D" or \
777                                    self.enable2D:
778                            cb.Show(True)
779                        elif cb.IsShown():
780                            cb.Hide()
781                        ix = 1
782                        value = self.model.getParam(name1)
783                        ctl1 = self.ModelTextCtrl(self, -1,
784                                                  size=(_BOX_WIDTH / 1.3, 20),
785                                                  style=wx.TE_PROCESS_ENTER)
786                        poly_tip = "Absolute Sigma for %s." % item
787                        ctl1.SetToolTipString(poly_tip)
788                        ctl1.SetValue(str(format_number(value, True)))
789                        if self.data.__class__.__name__ == "Data2D" or \
790                                    self.enable2D:
791                            if first_orient:
792                                values.SetLabel('PD[ratio], Sig[deg]')
793                                poly_text = "PD(polydispersity for lengths):\n"
794                                poly_text += "It should be a value between"
795                                poly_text += "0 and 1\n"
796                                poly_text += "Sigma for angles: \n"
797                                poly_text += "It is the STD (ratio*mean)"
798                                poly_text += " of the distribution.\n "
799                           
800                                values.SetToolTipString(poly_text)
801                                first_orient = False
802                            ctl1.Show(True)
803                        elif ctl1.IsShown():
804                            ctl1.Hide()
805                       
806                        self.sizer4_4.Add(ctl1, (iy, ix), (1, 1), wx.EXPAND)
807                        ## text to show error sign
808                        ix = 2
809                        text2 = wx.StaticText(self, -1, '+/-')
810                        self.sizer4_4.Add(text2, (iy, ix), (1, 1),
811                                          wx.EXPAND | wx.ADJUST_MINSIZE, 0)
812
813                        text2.Hide()
814
815                        ix = 3
816                        ctl2 = wx.TextCtrl(self, -1,
817                                           size=(_BOX_WIDTH / 1.3, 20),
818                                           style=0)
819                   
820                        self.sizer4_4.Add(ctl2, (iy, ix), (1, 1),
821                                          wx.EXPAND | wx.ADJUST_MINSIZE, 0)
822
823                        ctl2.Hide()
824                        if self.data.__class__.__name__ == "Data2D" or \
825                                self.enable2D:
826                            if self.is_mac:
827                                text2.Show(True)
828                                ctl2.Show(True)
829                           
830                        ix = 4
831                        ctl3 = self.ModelTextCtrl(self, -1,
832                                                  size=(_BOX_WIDTH / 2, 20),
833                                                  style=wx.TE_PROCESS_ENTER,
834                                text_enter_callback=self._onparamRangeEnter)
835
836                        self.sizer4_4.Add(ctl3, (iy, ix), (1, 1),
837                                          wx.EXPAND | wx.ADJUST_MINSIZE, 0)
838
839                        ctl3.Hide()
840               
841                        ix = 5
842                        ctl4 = self.ModelTextCtrl(self, -1,
843                            size=(_BOX_WIDTH / 2, 20),
844                            style=wx.TE_PROCESS_ENTER,
845                            text_enter_callback=self._onparamRangeEnter)
846                        self.sizer4_4.Add(ctl4, (iy, ix), (1, 1),
847                                          wx.EXPAND | wx.ADJUST_MINSIZE, 0)
848                        ctl4.Hide()
849                       
850                        if self.data.__class__.__name__ == "Data2D" or \
851                                self.enable2D:
852                            ctl3.Show(True)
853                            ctl4.Show(True)
854                             
855                    elif p == "npts":
856                        ix = 6
857                        value = self.model.getParam(name2)
858                        Tctl = self.ModelTextCtrl(self, -1,
859                                                 size=(_BOX_WIDTH / 2.2, 20),
860                                                 style=wx.TE_PROCESS_ENTER)
861                       
862                        Tctl.SetValue(str(format_number(value)))
863                        if self.data.__class__.__name__ == "Data2D" or \
864                                self.enable2D:
865                            Tctl.Show(True)
866                        else:
867                            Tctl.Hide()
868                        self.sizer4_4.Add(Tctl, (iy, ix), (1, 1),
869                                          wx.EXPAND | wx.ADJUST_MINSIZE, 0)
870                        self.fixed_param.append([None, name2, Tctl, None, None,
871                                                 None, None, None])
872                        self.orientation_params_disp.append([None, name2,
873                                                             Tctl, None, None,
874                                                             None, None, None])
875                    elif p == "nsigmas":
876                        ix = 7
877                        value = self.model.getParam(name3)
878                        Tct2 = self.ModelTextCtrl(self, -1,
879                                                  size=(_BOX_WIDTH / 2.2, 20),
880                                                  style=wx.TE_PROCESS_ENTER)
881                       
882                        Tct2.SetValue(str(format_number(value)))
883                        if self.data.__class__.__name__ == "Data2D" or \
884                                self.enable2D:
885                            Tct2.Show(True)
886                        else:
887                            Tct2.Hide()
888                        self.sizer4_4.Add(Tct2, (iy, ix), (1, 1),
889                                          wx.EXPAND | wx.ADJUST_MINSIZE, 0)
890
891                        self.fixed_param.append([None, name3, Tct2,
892                                                 None, None, None, None, None])
893                                                   
894                        self.orientation_params_disp.append([None, name3,
895                                        Tct2, None, None, None, None, None])
896
897                ix = 8
898                disp_box = wx.ComboBox(self, -1, size=(65, -1),
899                                style=wx.CB_READONLY, name='%s' % name1)
900                for key, value in self.polydisp.iteritems():
901                    name_disp = str(key)
902                    disp_box.Append(name_disp, value)
903                    disp_box.SetStringSelection("gaussian")
904                wx.EVT_COMBOBOX(disp_box, -1, self._on_disp_func)
905                self.sizer4_4.Add(disp_box, (iy, ix), (1, 1), wx.EXPAND)
906                self.fittable_param.append([cb, name1, ctl1, text2,
907                                            ctl2, ctl3, ctl4, disp_box])
908                self.orientation_params_disp.append([cb, name1, ctl1,
909                                            text2, ctl2, ctl3, ctl4, disp_box])
910                       
911                if self.data.__class__.__name__ == "Data2D" or \
912                                self.enable2D:
913                    disp_box.Show(True)
914                else:
915                    disp_box.Hide()
916       
917        self.state.disp_cb_dict = copy.deepcopy(self.disp_cb_dict)
918         
919        self.state.model = self.model.clone()
920        ## save state into
921        self.state.cb1 = self.cb1.GetValue()
922        self._copy_parameters_state(self.parameters, self.state.parameters)
923        self._copy_parameters_state(self.orientation_params_disp,
924                                     self.state.orientation_params_disp)
925        self._copy_parameters_state(self.fittable_param,
926                                    self.state.fittable_param)
927        self._copy_parameters_state(self.fixed_param, self.state.fixed_param)
928
929        wx.PostEvent(self.parent,
930                     StatusEvent(status=" Selected Distribution: Gaussian"))
931        #Fill the list of fittable parameters
932        #self.select_all_param(event=None)
933        self.get_all_checked_params()
934        self.Layout()
935
936    def _onDraw(self, event):
937        """
938        Update and Draw the model
939        """
940        if self.model == None:
941            msg = "Please select a Model first..."
942            wx.MessageBox(msg, 'Info')
943            return
944        """
945        if not self.data.is_data:
946            self.npts_x = self.Npts_total.GetValue()
947            self.Npts_fit.SetValue(self.npts_x)
948            self.create_default_data()
949        """
950        flag = self._update_paramv_on_fit()
951   
952        wx.CallAfter(self._onparamEnter_helper)
953        if not flag:
954            msg = "The parameters are invalid"
955            wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
956            return
957       
958    def _onFit(self, event):
959        """
960        Allow to fit
961        """
962        if event != None:
963            event.Skip()
964        if self.fit_started:
965            self._StopFit()
966            self.fit_started = False
967            wx.CallAfter(self.set_fitbutton)
968            return
969
970        if len(self.parent._manager.fit_thread_list) > 0 and\
971                    self.parent._manager._fit_engine != "park" and\
972                    self._manager.sim_page != None and \
973                    self._manager.sim_page.uid == self.uid:
974            msg = "The FitEnging will be set to 'ParkMC'\n"
975            msg += " to fit with more than one data set..."
976            wx.MessageBox(msg, 'Info')
977           
978        if self.data is None:
979            msg = "Please get Data first..."
980            wx.MessageBox(msg, 'Info')
981            wx.PostEvent(self._manager.parent,
982                         StatusEvent(status="Fit: %s" % msg))
983            return
984        if self.model is None:
985            msg = "Please select a Model first..."
986            wx.MessageBox(msg, 'Info')
987            wx.PostEvent(self._manager.parent,
988                         StatusEvent(status="Fit: %s" % msg, type="stop"))
989            return
990       
991        if len(self.param_toFit) <= 0:
992            msg = "Select at least one parameter to fit"
993            wx.MessageBox(msg, 'Info')
994            wx.PostEvent(self._manager.parent,
995                         StatusEvent(status=msg, type="stop"))
996            return
997       
998        flag = self._update_paramv_on_fit()
999       
1000        if self.batch_on and not self._is_2D():
1001            if not self._validate_Npts_1D():
1002                return
1003               
1004        if not flag:
1005            msg = "Fitting range or parameters are invalid"
1006            wx.PostEvent(self.parent.parent,
1007                         StatusEvent(status=msg, type="stop"))
1008            return
1009             
1010        self.select_param(event=None)
1011
1012        # Remove or do not allow fitting on the Q=0 point, especially
1013        # when y(q=0)=None at x[0].
1014        self.qmin_x = float(self.qmin.GetValue())
1015        self.qmax_x = float(self.qmax.GetValue())
1016        self._manager._reset_schedule_problem(value=0, uid=self.uid)
1017        self._manager.schedule_for_fit(uid=self.uid, value=1)
1018        self._manager.set_fit_range(uid=self.uid, qmin=self.qmin_x,
1019                                    qmax=self.qmax_x)
1020
1021        #single fit
1022        #self._manager.onFit(uid=self.uid)
1023        self.fit_started = self._manager.onFit(uid=self.uid)
1024        wx.CallAfter(self.set_fitbutton)
1025   
1026    def set_fitbutton(self):
1027        """
1028        Set fit button label depending on the fit_started[bool]
1029        """
1030        if self.fit_started:
1031            label = "Stop"
1032            color = "red"
1033        else:
1034            label = "Fit"
1035            color = "black"
1036        self.btFit.Enable(False)
1037        self.btFit.SetLabel(label)
1038        self.btFit.SetForegroundColour(color)
1039        self.btFit.Enable(True)
1040                     
1041    def get_weight_flag(self):
1042        """
1043        Get flag corresponding to a given weighting dI data.
1044        """
1045        button_list = [self.dI_noweight,
1046                       self.dI_didata,
1047                       self.dI_sqrdata,
1048                       self.dI_idata]
1049        flag = 1
1050        for item in button_list:
1051            if item.GetValue():
1052                if button_list.index(item) == 0:
1053                    flag = 0  # dy = numpy.ones_like(dy_data)
1054                elif button_list.index(item) == 1:
1055                    flag = 1  # dy = dy_data
1056                elif button_list.index(item) == 2:
1057                    flag = 2  # dy = numpy.sqrt(numpy.abs(data))
1058                elif button_list.index(item) == 3:
1059                    flag = 3  # dy = numpy.abs(data)
1060                break
1061        return flag
1062               
1063    def _StopFit(self, event=None):
1064        """
1065        Stop fit
1066        """
1067        if event != None:
1068            event.Skip()
1069        self._manager.stop_fit(self.uid)
1070        self._manager._reset_schedule_problem(value=0)
1071        self._on_fit_complete()
1072         
1073    def rename_model(self):
1074        """
1075        find a short name for model
1076        """
1077        if self.model is not None:
1078            self.model.name = "M" + str(self.index_model)
1079   
1080    def _on_select_model(self, event=None):
1081        """
1082        call back for model selection
1083        """
1084        self.Show(False)
1085        copy_flag = False
1086        is_poly_enabled = None
1087        if event != None:
1088            if (event.GetEventObject() == self.formfactorbox\
1089                        and self.structurebox.GetLabel() != 'None')\
1090                        or event.GetEventObject() == self.structurebox\
1091                        or event.GetEventObject() == self.multifactorbox:
1092                copy_flag = self.get_copy_params()
1093                is_poly_enabled = self.enable_disp.GetValue()
1094
1095        self._on_select_model_helper()
1096        self.set_model_param_sizer(self.model)
1097        if self.model is None:
1098            self._set_bookmark_flag(False)
1099            self._keep.Enable(False)
1100            self._set_save_flag(False)
1101        self.enable_disp.SetValue(False)
1102        self.disable_disp.SetValue(True)
1103        try:
1104            self.set_dispers_sizer()
1105        except:
1106            pass
1107        self.state.enable_disp = self.enable_disp.GetValue()
1108        self.state.disable_disp = self.disable_disp.GetValue()
1109        self.state.pinhole_smearer = self.pinhole_smearer.GetValue()
1110        self.state.slit_smearer = self.slit_smearer.GetValue()
1111   
1112        self.state.structurecombobox = self.structurebox.GetLabel()
1113        self.state.formfactorcombobox = self.formfactorbox.GetLabel()
1114        self.enable_fit_button()
1115        if self.model != None:
1116            self.m_name = self.model.name
1117            self.state.m_name = self.m_name
1118            self.rename_model()
1119            self._set_copy_flag(True)
1120            self._set_paste_flag(True)
1121            if self.data is not None:
1122                is_data = check_data_validity(self.data)
1123                if is_data:
1124                    self._set_bookmark_flag(not self.batch_on)
1125                    self._keep.Enable(not self.batch_on)
1126                    self._set_save_flag(True)
1127            # Reset smearer, model and data
1128            if not copy_flag:
1129                self.disable_smearer.SetValue(True)
1130                self.enable_smearer.SetValue(False)
1131   
1132            # more disables for 2D
1133            self._set_smear_buttons()
1134           
1135            try:
1136                # update smearer sizer
1137                #if not self.enable_smearer.GetValue():
1138                #    self.disable_smearer.SetValue(True)
1139                self.onSmear(None)
1140                temp_smear = None
1141                if not self.disable_smearer.GetValue():
1142                    # Set the smearer environments
1143                    temp_smear = self.current_smearer
1144            except:
1145                raise
1146                ## error occured on chisqr computation
1147                #pass
1148            ## event to post model to fit to fitting plugins
1149            (ModelEventbox, EVT_MODEL_BOX) = wx.lib.newevent.NewEvent()
1150         
1151            ## set smearing value whether or not
1152            #    the data contain the smearing info
1153            evt = ModelEventbox(model=self.model,
1154                            smearer=temp_smear,
1155                            enable_smearer=not self.disable_smearer.GetValue(),
1156                            qmin=float(self.qmin_x),
1157                            uid=self.uid,
1158                            caption=self.window_caption,
1159                            qmax=float(self.qmax_x))
1160   
1161            self._manager._on_model_panel(evt=evt)
1162            self.mbox_description.SetLabel("Model [ %s ]"% str(self.model.name))
1163            self.mbox_description.SetForegroundColour(wx.BLUE)
1164            self.state.model = self.model.clone()
1165            self.state.model.name = self.model.name
1166
1167        if event != None:
1168            ## post state to fit panel
1169            new_event = PageInfoEvent(page=self)
1170            wx.PostEvent(self.parent, new_event)
1171            #update list of plugins if new plugin is available
1172            if self.plugin_rbutton.GetValue():
1173                temp = self.parent.update_model_list()
1174                if temp:
1175                    self.model_list_box = temp
1176                    current_val = self.formfactorbox.GetLabel()
1177                    pos = self.formfactorbox.GetSelection()
1178                    self._show_combox_helper()
1179                    self.formfactorbox.SetSelection(pos)
1180                    self.formfactorbox.SetValue(current_val)
1181            # when select a model only from guictr/button
1182            if is_poly_enabled != None:
1183                self.enable_disp.SetValue(is_poly_enabled)
1184                self.disable_disp.SetValue(not is_poly_enabled)
1185                self._set_dipers_Param(event=None)
1186                self.state.enable_disp = self.enable_disp.GetValue()
1187                self.state.disable_disp = self.disable_disp.GetValue()
1188
1189            # Keep the previous param values
1190            if copy_flag:
1191                self.get_paste_params(copy_flag)
1192                wx.CallAfter(self._onDraw, None)
1193               
1194        else:
1195            self._draw_model()
1196           
1197        if self.batch_on:
1198            self.slit_smearer.Enable(False)
1199            self.pinhole_smearer.Enable(False)
1200            self.btEditMask.Disable()
1201            self.EditMask_title.Disable()
1202           
1203        self.Show(True)
1204        self.SetupScrolling()
1205         
1206    def _onparamEnter(self, event):
1207        """
1208        when enter value on panel redraw model according to changed
1209        """
1210        if self.model == None:
1211            msg = "Please select a Model first..."
1212            wx.MessageBox(msg, 'Info')
1213            return
1214
1215        #default flag
1216        flag = False
1217        self.fitrange = True
1218        #get event object
1219        tcrtl = event.GetEventObject()
1220        #Clear msg if previously shown.
1221        msg = ""
1222        wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
1223
1224        if check_float(tcrtl):
1225            flag = self._onparamEnter_helper()
1226            self.set_npts2fit()
1227            if self.fitrange:
1228                temp_smearer = None
1229                if not self.disable_smearer.GetValue():
1230                    temp_smearer = self.current_smearer
1231                    ## set smearing value whether or not
1232                    #        the data contain the smearing info
1233                    if self.slit_smearer.GetValue():
1234                        flag1 = self.update_slit_smear()
1235                        flag = flag or flag1
1236                    elif self.pinhole_smearer.GetValue():
1237                        flag1 = self.update_pinhole_smear()
1238                        flag = flag or flag1
1239                elif self.data.__class__.__name__ != "Data2D" and \
1240                        not self.enable2D:
1241                    self._manager.set_smearer(smearer=temp_smearer,
1242                                              fid=self.data.id,
1243                                              uid=self.uid,
1244                                              qmin=float(self.qmin_x),
1245                                              qmax=float(self.qmax_x),
1246                            enable_smearer=not self.disable_smearer.GetValue(),
1247                                            draw=True)
1248                if flag:
1249                    #self.compute_chisqr(smearer= temp_smearer)
1250       
1251                    ## new state posted
1252                    if self.state_change:
1253                        #self._undo.Enable(True)
1254                        event = PageInfoEvent(page=self)
1255                        wx.PostEvent(self.parent, event)
1256                    self.state_change = False
1257            else:
1258                # invalid fit range: do nothing here:
1259                # msg already displayed in validate
1260                return
1261        else:
1262            self.save_current_state()
1263            msg = "Cannot Plot :Must enter a number!!!  "
1264            wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
1265             
1266        self.save_current_state()
1267        return
1268   
1269    def _onparamRangeEnter(self, event):
1270        """
1271        Check validity of value enter in the parameters range field
1272        """
1273        tcrtl = event.GetEventObject()
1274        #Clear msg if previously shown.
1275        msg = ""
1276        wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
1277        # Flag to register when a parameter has changed.
1278        is_modified = False
1279        if tcrtl.GetValue().lstrip().rstrip() != "":
1280            try:
1281                tcrtl.SetBackgroundColour(wx.WHITE)
1282                self._check_value_enter(self.fittable_param, is_modified)
1283                self._check_value_enter(self.parameters, is_modified)
1284            except:
1285                tcrtl.SetBackgroundColour("pink")
1286                msg = "Model Error:wrong value entered : %s" % sys.exc_value
1287                wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
1288                return
1289        else:
1290            tcrtl.SetBackgroundColour(wx.WHITE)
1291           
1292        #self._undo.Enable(True)
1293        self.save_current_state()
1294        event = PageInfoEvent(page=self)
1295        wx.PostEvent(self.parent, event)
1296        self.state_change = False
1297         
1298    def _onQrangeEnter(self, event):
1299        """
1300        Check validity of value enter in the Q range field
1301        """
1302        tcrtl = event.GetEventObject()
1303        #Clear msg if previously shown.
1304        msg = ""
1305        wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
1306        # For theory mode
1307        if not self.data.is_data:
1308            self.npts_x = self.Npts_total.GetValue()
1309            self.Npts_fit.SetValue(self.npts_x)
1310            self.create_default_data()
1311        # Flag to register when a parameter has changed.
1312        if tcrtl.GetValue().lstrip().rstrip() != "":
1313            try:
1314                tcrtl.SetBackgroundColour(wx.WHITE)
1315                # If qmin and qmax have been modified, update qmin and qmax
1316                if self._validate_qrange(self.qmin, self.qmax):
1317                    tempmin = float(self.qmin.GetValue())
1318                    if tempmin != self.qmin_x:
1319                        self.qmin_x = tempmin
1320                    tempmax = float(self.qmax.GetValue())
1321                    if tempmax != self.qmax_x:
1322                        self.qmax_x = tempmax
1323                else:
1324                    tcrtl.SetBackgroundColour("pink")
1325                    msg = "Model Error:wrong value entered : %s" % sys.exc_value
1326                    wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
1327                    return
1328            except:
1329                tcrtl.SetBackgroundColour("pink")
1330                msg = "Model Error:wrong value entered : %s" % sys.exc_value
1331                wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
1332                return
1333            #Check if # of points for theory model are valid(>0).
1334            # check for 2d
1335            if self.data.__class__.__name__ == "Data2D" or \
1336                    self.enable2D:
1337                # set mask
1338                radius = numpy.sqrt(self.data.qx_data * self.data.qx_data +
1339                                    self.data.qy_data * self.data.qy_data)
1340                index_data = ((self.qmin_x <= radius) & \
1341                                (radius <= self.qmax_x))
1342                index_data = (index_data) & (self.data.mask)
1343                index_data = (index_data) & (numpy.isfinite(self.data.data))
1344                if len(index_data[index_data]) < 10:
1345                    msg = "Cannot Plot :No or too little npts in"
1346                    msg += " that data range!!!  "
1347                    wx.PostEvent(self.parent.parent,
1348                                 StatusEvent(status=msg))
1349                    return
1350                else:
1351                    #self.data.mask = index_data
1352                    #self.Npts_fit.SetValue(str(len(self.data.mask)))
1353                    self.set_npts2fit()
1354            else:
1355                index_data = ((self.qmin_x <= self.data.x) & \
1356                              (self.data.x <= self.qmax_x))
1357                self.Npts_fit.SetValue(str(len(self.data.x[index_data])))
1358           
1359            self.npts_x = self.Npts_total.GetValue()
1360            self.create_default_data()
1361            self._save_plotting_range()
1362        else:
1363            tcrtl.SetBackgroundColour("pink")
1364            msg = "Model Error:wrong value entered!!!"
1365            wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
1366       
1367        self._draw_model()
1368        self.save_current_state()
1369        event = PageInfoEvent(page=self)
1370        wx.PostEvent(self.parent, event)
1371        self.state_change = False
1372        return
1373   
1374    def _clear_Err_on_Fit(self):
1375        """
1376        hide the error text control shown
1377        after fitting
1378        """
1379        if self.is_mac:
1380            return
1381        if hasattr(self, "text2_3"):
1382            self.text2_3.Hide()
1383
1384        if len(self.parameters) > 0:
1385            for item in self.parameters:
1386                if item[0].IsShown():
1387                    #Skip t ifhe angle parameters if 1D data
1388                    if self.data.__class__.__name__ != "Data2D" and \
1389                            not self.enable2D:
1390                        if item in self.orientation_params:
1391                            continue
1392                    if item in self.param_toFit:
1393                        continue
1394                    ## hide statictext +/-
1395                    if len(item) < 4:
1396                        continue
1397                    if item[3] != None and item[3].IsShown():
1398                        item[3].Hide()
1399                    ## hide textcrtl  for error after fit
1400                    if item[4] != None and item[4].IsShown():
1401                        item[4].Hide()
1402 
1403        if len(self.fittable_param) > 0:
1404            for item in self.fittable_param:
1405                if item[0].IsShown():
1406                    #Skip t ifhe angle parameters if 1D data
1407                    if self.data.__class__.__name__ != "Data2D" and \
1408                            not self.enable2D:
1409                        if item in self.orientation_params:
1410                            continue
1411                    if item in self.param_toFit:
1412                        continue
1413                    if len(item) < 4:
1414                        continue
1415                    ## hide statictext +/-
1416                    if item[3] != None and item[3].IsShown():
1417                        item[3].Hide()
1418                    ## hide textcrtl  for error after fit
1419                    if item[4] != None and item[4].IsShown():
1420                        item[4].Hide()
1421        return
1422               
1423    def _get_defult_custom_smear(self):
1424        """
1425        Get the defult values for custum smearing.
1426        """
1427        # get the default values
1428        if self.dxl == None:
1429            self.dxl = 0.0
1430        if self.dxw == None:
1431            self.dxw = ""
1432        if self.dx_min == None:
1433            self.dx_min = SMEAR_SIZE_L
1434        if self.dx_max == None:
1435            self.dx_max = SMEAR_SIZE_H
1436       
1437    def _get_smear_info(self):
1438        """
1439        Get the smear info from data.
1440       
1441        :return: self.smear_type, self.dq_l and self.dq_r,
1442            respectively the type of the smear, dq_min and
1443            dq_max for pinhole smear data
1444            while dxl and dxw for slit smear
1445        """
1446        # default
1447        self.smear_type = None
1448        self.dq_l = None
1449        self.dq_r = None
1450        data = self.data
1451        if self.data is None:
1452            return
1453        elif self.data.__class__.__name__ == "Data2D" or \
1454            self.enable2D:
1455            if data.dqx_data == None or  data.dqy_data == None:
1456                return
1457            elif self.current_smearer != None \
1458                and data.dqx_data.any() != 0 \
1459                and data.dqx_data.any() != 0:
1460                self.smear_type = "Pinhole2d"
1461                self.dq_l = format_number(numpy.average(data.dqx_data))
1462                self.dq_r = format_number(numpy.average(data.dqy_data))
1463                return
1464            else:
1465                return
1466        # check if it is pinhole smear and get min max if it is.
1467        if data.dx != None and all(data.dx != 0):
1468            self.smear_type = "Pinhole"
1469            self.dq_l = data.dx[0]
1470            self.dq_r = data.dx[-1]
1471           
1472        # check if it is slit smear and get min max if it is.
1473        elif data.dxl != None or data.dxw != None:
1474            self.smear_type = "Slit"
1475            if data.dxl != None and all(data.dxl != 0):
1476                self.dq_l = data.dxl[0]
1477            if data.dxw != None and all(data.dxw != 0):
1478                self.dq_r = data.dxw[0]
1479        #return self.smear_type,self.dq_l,self.dq_r
1480   
1481    def _show_smear_sizer(self):
1482        """
1483        Show only the sizers depending on smear selection
1484        """
1485        # smear disabled
1486        if self.disable_smearer.GetValue():
1487            self.smear_description_none.Show(True)
1488        # 2Dsmear
1489        elif self._is_2D():
1490            self.smear_description_accuracy_type.Show(True)
1491            self.smear_accuracy.Show(True)
1492            self.smear_description_accuracy_type.Show(True)
1493            self.smear_description_2d.Show(True)
1494            self.smear_description_2d_x.Show(True)
1495            self.smear_description_2d_y.Show(True)
1496            if self.pinhole_smearer.GetValue():
1497                self.smear_pinhole_min.Show(True)
1498                self.smear_pinhole_max.Show(True)
1499        # smear from data
1500        elif self.enable_smearer.GetValue():
1501
1502            self.smear_description_dqdata.Show(True)
1503            if self.smear_type != None:
1504                self.smear_description_smear_type.Show(True)
1505                if self.smear_type == 'Slit':
1506                    self.smear_description_slit_height.Show(True)
1507                    self.smear_description_slit_width.Show(True)
1508                elif self.smear_type == 'Pinhole':
1509                    self.smear_description_pin_min.Show(True)
1510                    self.smear_description_pin_max.Show(True)
1511                self.smear_description_smear_type.Show(True)
1512                self.smear_description_type.Show(True)
1513                self.smear_data_left.Show(True)
1514                self.smear_data_right.Show(True)
1515        # custom pinhole smear
1516        elif self.pinhole_smearer.GetValue():
1517            if self.smear_type == 'Pinhole':
1518                self.smear_message_new_p.Show(True)
1519                self.smear_description_pin_min.Show(True)
1520                self.smear_description_pin_max.Show(True)
1521
1522            self.smear_pinhole_min.Show(True)
1523            self.smear_pinhole_max.Show(True)
1524        # custom slit smear
1525        elif self.slit_smearer.GetValue():
1526            self.smear_message_new_s.Show(True)
1527            self.smear_description_slit_height.Show(True)
1528            self.smear_slit_height.Show(True)
1529            self.smear_description_slit_width.Show(True)
1530            self.smear_slit_width.Show(True)
1531
1532    def _hide_all_smear_info(self):
1533        """
1534        Hide all smearing messages in the set_smearer sizer
1535        """
1536        self.smear_description_none.Hide()
1537        self.smear_description_dqdata.Hide()
1538        self.smear_description_type.Hide()
1539        self.smear_description_smear_type.Hide()
1540        self.smear_description_accuracy_type.Hide()
1541        self.smear_description_2d_x.Hide()
1542        self.smear_description_2d_y.Hide()
1543        self.smear_description_2d.Hide()
1544       
1545        self.smear_accuracy.Hide()
1546        self.smear_data_left.Hide()
1547        self.smear_data_right.Hide()
1548        self.smear_description_pin_min.Hide()
1549        self.smear_pinhole_min.Hide()
1550        self.smear_description_pin_max.Hide()
1551        self.smear_pinhole_max.Hide()
1552        self.smear_description_slit_height.Hide()
1553        self.smear_slit_height.Hide()
1554        self.smear_description_slit_width.Hide()
1555        self.smear_slit_width.Hide()
1556        self.smear_message_new_p.Hide()
1557        self.smear_message_new_s.Hide()
1558   
1559    def _set_accuracy_list(self):
1560        """
1561        Set the list of an accuracy in 2D custum smear:
1562                Xhigh, High, Med, or Low
1563        """
1564        # list of accuracy choices
1565        list = ['Low', 'Med', 'High', 'Xhigh']
1566        for idx in range(len(list)):
1567            self.smear_accuracy.Append(list[idx], idx)
1568           
1569    def _set_fun_box_list(self, fun_box):
1570        """
1571        Set the list of func for multifunctional models
1572        """
1573        # Check if it is multi_functional model
1574        if self.model.__class__ not in self.model_list_box["Multi-Functions"] \
1575                and not self.temp_multi_functional:
1576            return None
1577        # Get the func name list
1578        list = self.model.fun_list
1579        if len(list) == 0:
1580            return None
1581        # build function (combo)box
1582        ind = 0
1583        while(ind < len(list)):
1584            for key, val in list.iteritems():
1585                if (val == ind):
1586                    fun_box.Append(key, val)
1587                    break
1588            ind += 1
1589       
1590    def _on_select_accuracy(self, event):
1591        """
1592        Select an accuracy in 2D custom smear: Xhigh, High, Med, or Low
1593        """
1594        #event.Skip()
1595        # Check if the accuracy is same as before
1596        #self.smear2d_accuracy = event.GetEventObject().GetValue()
1597        self.smear2d_accuracy = self.smear_accuracy.GetValue()
1598        if self.pinhole_smearer.GetValue():
1599            self.onPinholeSmear(event=None)
1600        else:
1601            self.onSmear(event=None)
1602            if self.current_smearer != None:
1603                self.current_smearer.set_accuracy(accuracy=\
1604                                                  self.smear2d_accuracy) 
1605        event.Skip()
1606
1607    def _on_fun_box(self, event):
1608        """
1609        Select an func: Erf,Rparabola,LParabola
1610        """
1611        fun_val = None
1612        fun_box = event.GetEventObject()
1613        name = fun_box.Name
1614        value = fun_box.GetValue()
1615        if value in self.model.fun_list:
1616            fun_val = self.model.fun_list[value]
1617
1618        self.model.setParam(name, fun_val)
1619        # save state
1620        self._copy_parameters_state(self.str_parameters,
1621                                    self.state.str_parameters)
1622        # update params
1623        self._update_paramv_on_fit()
1624        # draw
1625        self._draw_model()
1626        self.Refresh()
1627        # get ready for new event
1628        event.Skip()
1629       
1630    def _onMask(self, event):
1631        """
1632        Build a panel to allow to edit Mask
1633        """
1634        from sans.guiframe.local_perspectives.plotting.masking \
1635        import MaskPanel as MaskDialog
1636       
1637        self.panel = MaskDialog(base=self, data=self.data, id=wx.NewId())
1638        self.panel.ShowModal()
1639       
1640    def _draw_masked_model(self, event):
1641        """
1642        Draw model image w/mask
1643        """
1644        is_valid_qrange = self._update_paramv_on_fit()
1645
1646        if is_valid_qrange and self.model != None:
1647            self.panel.MakeModal(False)
1648            event.Skip()
1649            # try re draw the model plot if it exists
1650            self._draw_model()
1651            self.set_npts2fit()
1652        elif self.model == None:
1653            self.panel.MakeModal(False)
1654            event.Skip()
1655            self.set_npts2fit()
1656            msg = "No model is found on updating MASK in the model plot... "
1657            wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
1658        else:
1659            event.Skip()
1660            msg = ' Please consider your Q range, too.'
1661            self.panel.ShowMessage(msg)
1662
1663    def _set_smear(self, data):
1664        """
1665        Set_smear
1666        """
1667        if data is None:
1668            return
1669        self.current_smearer = smear_selection(data, self.model)
1670        flag = self.disable_smearer.GetValue()
1671        self.disable_smearer.SetValue(flag)
1672        if self.current_smearer == None:
1673            self.enable_smearer.Disable()
1674        else:
1675            self.enable_smearer.Enable()
1676        if not flag:
1677            self.onSmear(None)
1678
1679    def _mac_sleep(self, sec=0.2):
1680        """
1681        Give sleep to MAC
1682        """
1683        if self.is_mac:
1684            time.sleep(sec)
1685
1686    def get_view_mode(self):
1687        """
1688        return True if the panel allow 2D or False if 1D
1689        """
1690        return self.enable2D
1691   
1692    def compute_data_set_range(self, data_list):
1693        """
1694        find the range that include all data  in the set
1695        return the minimum and the maximum values
1696        """
1697        if data_list is not None and data_list != []:
1698            for data in data_list:
1699                qmin, qmax, npts = self.compute_data_range(data)
1700                self.qmin_data_set = min(self.qmin_data_set, qmin)
1701                self.qmax_data_set = max(self.qmax_data_set, qmax)
1702                self.npts_data_set += npts
1703        return self.qmin_data_set, self.qmax_data_set, self.npts_data_set
1704       
1705    def compute_data_range(self, data):
1706        """
1707        compute the minimum and the maximum range of the data
1708        return the npts contains in data
1709        :param data:
1710        """
1711        qmin, qmax, npts = None, None, None
1712        if data is not None:
1713            if not hasattr(data, "data"):
1714                try:
1715                    qmin = min(data.x)
1716                    # Maximum value of data
1717                    qmax = max(data.x)
1718                    npts = len(data.x)
1719                except:
1720                    msg = "Unable to find min/max/length of \n data named %s"% \
1721                                data.filename 
1722                    wx.PostEvent(self._manager.parent, StatusEvent(status=msg,
1723                                               info="error"))
1724                    raise ValueError, msg
1725                   
1726            else:
1727                qmin = 0
1728                try:
1729                    x = max(math.fabs(data.xmin), math.fabs(data.xmax))
1730                    y = max(math.fabs(data.ymin), math.fabs(data.ymax))
1731                except:
1732                    msg = "Unable to find min/max of \n data named %s"% \
1733                                data.filename 
1734                    wx.PostEvent(self._manager.parent, StatusEvent(status=msg,
1735                                               info="error"))
1736                    raise ValueError, msg
1737                ## Maximum value of data
1738                qmax = math.sqrt(x * x + y * y)
1739                npts = len(data.data)
1740        return qmin, qmax, npts
1741           
1742    def set_data(self, data):
1743        """
1744        reset the current data
1745        """
1746        id = None
1747        flag = False
1748        is_data = False
1749        if self.data is not None:
1750            is_data = check_data_validity(self.data)
1751        if not is_data and data is not None:
1752                flag = True
1753        if data is not None:
1754            id = data.id
1755            if is_data:
1756                self.graph_id = self.data.group_id
1757                flag = (data.id != self.data.id)
1758        self.data = data
1759        if check_data_validity(data):
1760            self.graph_id = data.group_id
1761        self.data.group_id = self.graph_id
1762       
1763        if self.data is None:
1764            data_name = ""
1765            self._set_bookmark_flag(False)
1766            self._keep.Enable(False)
1767            self._set_save_flag(False)
1768        else:
1769            if self.model != None:
1770                self._set_bookmark_flag(not self.batch_on)
1771                self._keep.Enable(not self.batch_on)
1772               
1773            self._set_save_flag(True)
1774            self._set_preview_flag(True)
1775
1776            self._set_smear(data)
1777            # more disables for 2D
1778            if self.data.__class__.__name__ == "Data2D" or \
1779                        self.enable2D:
1780                self.slit_smearer.Disable()
1781                self.pinhole_smearer.Enable(True)
1782                self.default_mask = copy.deepcopy(self.data.mask)
1783                if self.data.err_data == None or\
1784                        (self.data.err_data == 1).all() or\
1785                        (self.data.err_data == 0).all():
1786                    self.dI_didata.Enable(False)
1787                    self.dI_noweight.SetValue(True)
1788                    self.weightbt_string = self.dI_noweight.GetLabelText()
1789                else:
1790                    self.dI_didata.Enable(True)
1791                    self.dI_didata.SetValue(True)
1792                    self.weightbt_string = self.dI_didata.GetLabelText()
1793            else:
1794                self.slit_smearer.Enable(True)
1795                self.pinhole_smearer.Enable(True)
1796                if self.data.dy == None or\
1797                     (self.data.dy == 1).all() or\
1798                     (self.data.dy == 0).all():
1799                    self.dI_didata.Enable(False)
1800                    self.dI_noweight.SetValue(True)
1801                    self.weightbt_string = self.dI_noweight.GetLabelText()
1802                else:
1803                    self.dI_didata.Enable(True)
1804                    self.dI_didata.SetValue(True)
1805                    self.weightbt_string = self.dI_didata.GetLabelText()
1806            # Enable weighting radio uttons
1807            self.dI_noweight.Enable(True)
1808            self.dI_sqrdata.Enable(True)
1809            self.dI_idata.Enable(True)
1810             
1811            self.formfactorbox.Enable()
1812            self.structurebox.Enable()
1813            data_name = self.data.name
1814            _, _, npts = self.compute_data_range(self.data)
1815            #set maximum range for x in linear scale
1816            if not hasattr(self.data, "data"):  # Display only for 1D data fit
1817                self.btEditMask.Disable()
1818                self.EditMask_title.Disable()
1819            else:
1820                self.btEditMask.Enable()
1821                self.EditMask_title.Enable()
1822   
1823        self.Npts_total.SetValue(str(npts))
1824        #default:number of data points selected to fit
1825        self.Npts_fit.SetValue(str(npts))
1826        self.Npts_total.SetEditable(False)
1827        self.Npts_total.SetBackgroundColour(\
1828                                    self.GetParent().GetBackgroundColour())
1829       
1830        self.Npts_total.Bind(wx.EVT_MOUSE_EVENTS, self._npts_click)
1831        self.dataSource.SetValue(data_name)
1832        self.state.data = data
1833        self.enable_fit_button()
1834        # send graph_id to page_finder
1835        self._manager.set_graph_id(uid=self.uid, graph_id=self.graph_id)
1836        #focus the page
1837        if check_data_validity(data):
1838            self.data_box_description.SetForegroundColour(wx.BLUE)
1839       
1840        if self.batch_on:
1841            self.slit_smearer.Enable(False)
1842            self.pinhole_smearer.Enable(False)
1843            self.btEditMask.Disable()
1844            self.EditMask_title.Disable()
1845
1846        self.on_set_focus(None)
1847        self.Refresh()
1848        #update model plot with new data information
1849        if flag:
1850            #set model view button
1851            if not self.enable_smearer.GetValue():
1852                    self.disable_smearer.SetValue(True)
1853            self.onSmear(None)
1854
1855            if self.data.__class__.__name__ == "Data2D":
1856                self.enable2D = True
1857                self.model_view.SetLabel("2D Mode")
1858            else:
1859                self.enable2D = False
1860                self.model_view.SetLabel("1D Mode")
1861            self.model_view.Disable()
1862            #replace data plot on combo box selection
1863            #by removing the previous selected data
1864            #wx.PostEvent(self._manager.parent,
1865            #             NewPlotEvent(action="remove",
1866            #                          group_id=self.graph_id, id=id))
1867            #plot the current selected data
1868            wx.PostEvent(self._manager.parent,
1869                         NewPlotEvent(action="check", plot=self.data,
1870                                      title=str(self.data.title)))
1871            self._draw_model()
1872   
1873    def _npts_click(self, event):
1874        """
1875        Prevent further handling of the mouse event on Npts_total
1876        by not calling Skip().
1877        """
1878        pass
1879   
1880    def reset_page(self, state, first=False):
1881        """
1882        reset the state
1883        """
1884        self.reset_page_helper(state)
1885
1886        self.select_param(event=None)
1887        #Save state_fit
1888        self.save_current_state_fit()
1889        self._lay_out()
1890        self.Refresh()
1891       
1892    def get_range(self):
1893        """
1894        return the fitting range
1895        """
1896        return float(self.qmin_x), float(self.qmax_x)
1897   
1898    def get_npts2fit(self):
1899        """
1900        return numbers of data points within qrange
1901       
1902        :Note: This is for Park where chi2 is not normalized by Npts of fit
1903       
1904        """
1905        if self.data is None:
1906            return
1907        npts2fit = 0
1908        qmin, qmax = self.get_range()
1909        if self.data.__class__.__name__ == "Data2D" or \
1910                        self.enable2D:
1911            radius = numpy.sqrt(self.data.qx_data * self.data.qx_data +
1912                                self.data.qy_data * self.data.qy_data)
1913            index_data = (self.qmin_x <= radius) & (radius <= self.qmax_x)
1914            index_data = (index_data) & (self.data.mask)
1915            index_data = (index_data) & (numpy.isfinite(self.data.data))
1916            npts2fit = len(self.data.data[index_data])
1917        else:
1918            for qx in self.data.x:
1919                if qx >= qmin and qx <= qmax:
1920                    npts2fit += 1
1921        return npts2fit
1922
1923    def set_npts2fit(self):
1924        """
1925        setValue Npts for fitting
1926        """
1927        self.Npts_fit.SetValue(str(self.get_npts2fit()))
1928       
1929    def get_chi2(self):
1930        """
1931        return the current chi2
1932        """
1933        return self.tcChi.GetValue()
1934       
1935    def get_param_list(self):
1936        """
1937        :return self.param_toFit: list containing  references to TextCtrl
1938            checked.Theses TextCtrl will allow reference to parameters to fit.
1939       
1940        :raise: if return an empty list of parameter fit will nnote work
1941            properly so raise ValueError,"missing parameter to fit"
1942        """
1943        if self.param_toFit != []:
1944            return self.param_toFit
1945        else:
1946            msg = "missing parameters to fit"
1947            wx.MessageBox(msg, 'warning')
1948            return False
1949     
1950    def onsetValues(self, chisqr, p_name, out, cov):
1951        """
1952        Build the panel from the fit result
1953       
1954        :param chisqr: Value of the goodness of fit metric
1955        :param p_name: the name of parameters
1956        :param out: list of parameter with the best value found during fitting
1957        :param cov: Covariance matrix
1958   
1959        """
1960        # make sure stop button to fit button all the time
1961        self._on_fit_complete()
1962        if out == None or not numpy.isfinite(chisqr):
1963            raise ValueError, "Fit error occured..."
1964       
1965        is_modified = False
1966        has_error = False
1967        dispersity = ''
1968       
1969        #Hide textctrl boxes of errors.
1970        self._clear_Err_on_Fit()
1971       
1972        #Check if chi2 is finite
1973        if chisqr != None and numpy.isfinite(chisqr):
1974            #format chi2
1975            if self.engine_type == "park":
1976                npt_fit = float(self.get_npts2fit())
1977            chi2 = format_number(chisqr, True)
1978            self.tcChi.SetValue(chi2)
1979            self.tcChi.Refresh()
1980        else:
1981            self.tcChi.SetValue("-")
1982       
1983        #Hide error title
1984        if self.text2_3.IsShown() and not self.is_mac:
1985            self.text2_3.Hide()
1986     
1987        try:
1988            if self.enable_disp.GetValue():
1989                if hasattr(self, "text_disp_1"):
1990                    if self.text_disp_1 != None and not self.is_mac:
1991                        self.text_disp_1.Hide()
1992        except:
1993            dispersity = None
1994            pass
1995     
1996        i = 0
1997        #Set the panel when fit result are list
1998        for item in self.param_toFit:
1999            if len(item) > 5 and item != None:
2000                if item[0].IsShown():
2001                    ## reset error value to initial state
2002                    if not self.is_mac:
2003                        item[3].Hide()
2004                        item[4].Hide()
2005                    for ind in range(len(out)):
2006                        if item[1] == p_name[ind]:
2007                            break
2008                    if len(out) > 0 and out[ind] != None:
2009                        val_out = format_number(out[ind], True)
2010                        item[2].SetValue(val_out)
2011   
2012                    if(cov != None and len(cov) == len(out)):
2013                        try:
2014                            if dispersity != None:
2015                                if self.enable_disp.GetValue():
2016                                    if hasattr(self, "text_disp_1"):
2017                                        if self.text_disp_1 != None:
2018                                            if not self.text_disp_1.IsShown()\
2019                                                and not self.is_mac:
2020                                                self.text_disp_1.Show(True)
2021                        except:
2022                            pass
2023                       
2024                        if cov[ind] != None:
2025                            if numpy.isfinite(float(cov[ind])):
2026                                val_err = format_number(cov[ind], True)
2027                                if not self.is_mac:
2028                                    item[3].Show(True)
2029                                    item[4].Show(True)
2030                                item[4].SetValue(val_err)
2031                                has_error = True
2032                i += 1
2033            else:
2034                raise ValueError, "onsetValues: Invalid parameters..."
2035        #Show error title when any errors displayed
2036        if has_error:
2037            if not self.text2_3.IsShown():
2038                self.text2_3.Show(True)
2039        ## save current state
2040        self.save_current_state()
2041       
2042        if not self.is_mac:
2043            self.Layout()
2044            self.Refresh()
2045        self._mac_sleep(0.1)
2046        #plot model ( when drawing, do not update chisqr value again)
2047        self._draw_model(update_chisqr=False, source='fit')
2048   
2049    def onWeighting(self, event):
2050        """
2051        On Weighting radio button event, sets the weightbt_string
2052        """
2053        self.weightbt_string = event.GetEventObject().GetLabelText()
2054        self._set_weight()
2055       
2056    def _set_weight(self, is_2D=None):
2057        """
2058        Set weight in fit problem
2059        """
2060        # compute weight for the current data
2061        from .utils import get_weight
2062        flag_weight = self.get_weight_flag()
2063        if is_2D == None:
2064            is_2D = self._is_2D()
2065        weight = get_weight(data=self.data,
2066                            is2d=is_2D,
2067                            flag=flag_weight)
2068        self._manager.set_fit_weight(uid=self.uid,
2069                                     flag=flag_weight,
2070                                     is2d=is_2D,
2071                                     fid=None)
2072   
2073    def onPinholeSmear(self, event):
2074        """
2075        Create a custom pinhole smear object that will change the way residuals
2076        are compute when fitting
2077       
2078        :Note: accuracy is given by strings'High','Med', 'Low' FOR 2d,
2079                     None for 1D
2080                     
2081        """
2082        if self.model == None:
2083            self.disable_smearer.SetValue(True)
2084            if event == None:
2085                return
2086            msg = "Please select a Model first..."
2087            wx.MessageBox(msg, 'Info')
2088            wx.PostEvent(self._manager.parent,
2089                         StatusEvent(status="Smear: %s" % msg))
2090            return
2091
2092        # Need update param values
2093        self._update_paramv_on_fit()
2094
2095        # msg default
2096        msg = None
2097        if event != None:
2098            tcrtl = event.GetEventObject()
2099            # event case of radio button
2100            if tcrtl.GetValue() == True:
2101                self.dx_min = 0.0
2102                self.dx_max = 0.0
2103                is_new_pinhole = True
2104            else:
2105                is_new_pinhole = self._is_changed_pinhole()
2106        else:
2107            is_new_pinhole = True
2108        # if any value is changed
2109        if is_new_pinhole:
2110            msg = self._set_pinhole_smear()
2111        # hide all silt sizer
2112        self._hide_all_smear_info()
2113       
2114        # show relevant slit sizers
2115        self._show_smear_sizer()
2116
2117        self.sizer_set_smearer.Layout()
2118        self.Layout()
2119       
2120        if event != None:
2121            event.Skip()
2122        #self._undo.Enable(True)
2123        self.save_current_state()
2124        event = PageInfoEvent(page=self)
2125        wx.PostEvent(self.parent, event)
2126       
2127    def _is_changed_pinhole(self):
2128        """
2129        check if any of pinhole smear is changed
2130       
2131        :return: True or False
2132       
2133        """
2134        # get the values
2135        pin_min = self.smear_pinhole_min.GetValue()
2136        pin_max = self.smear_pinhole_max.GetValue()
2137                   
2138        # Check changes in slit width
2139        try:
2140            dx_min = float(pin_min)
2141        except:
2142            return True
2143        if self.dx_min != dx_min:
2144            return True
2145       
2146        # Check changes in slit heigth
2147        try:
2148            dx_max = float(pin_max)
2149        except:
2150            return True
2151        if self.dx_max != dx_max:
2152            return True
2153        return False
2154   
2155    def _set_pinhole_smear(self):
2156        """
2157        Set custom pinhole smear
2158       
2159        :return: msg
2160       
2161        """
2162        # copy data
2163        data = copy.deepcopy(self.data)
2164        if self._is_2D():
2165            self.smear_type = 'Pinhole2d'
2166            len_data = len(data.data)
2167            data.dqx_data = numpy.zeros(len_data)
2168            data.dqy_data = numpy.zeros(len_data)
2169        else:
2170            self.smear_type = 'Pinhole'
2171            len_data = len(data.x)
2172            data.dx = numpy.zeros(len_data)
2173            data.dxl = None
2174            data.dxw = None
2175        msg = None
2176   
2177        get_pin_min = self.smear_pinhole_min
2178        get_pin_max = self.smear_pinhole_max
2179
2180        if not check_float(get_pin_min):
2181            get_pin_min.SetBackgroundColour("pink")
2182            msg = "Model Error:wrong value entered!!!"
2183        elif not check_float(get_pin_max):
2184            get_pin_max.SetBackgroundColour("pink")
2185            msg = "Model Error:wrong value entered!!!"
2186        else:
2187            if len_data < 2:
2188                len_data = 2
2189            self.dx_min = float(get_pin_min.GetValue())
2190            self.dx_max = float(get_pin_max.GetValue())
2191            if self.dx_min < 0:
2192                get_pin_min.SetBackgroundColour("pink")
2193                msg = "Model Error:This value can not be negative!!!"
2194            elif self.dx_max < 0:
2195                get_pin_max.SetBackgroundColour("pink")
2196                msg = "Model Error:This value can not be negative!!!"
2197            elif self.dx_min != None and self.dx_max != None:
2198                if self._is_2D():
2199                    data.dqx_data[data.dqx_data == 0] = self.dx_min
2200                    data.dqy_data[data.dqy_data == 0] = self.dx_max
2201                elif self.dx_min == self.dx_max:
2202                    data.dx[data.dx == 0] = self.dx_min
2203                else:
2204                    step = (self.dx_max - self.dx_min) / (len_data - 1)
2205                    data.dx = numpy.arange(self.dx_min,
2206                                           self.dx_max + step / 1.1,
2207                                           step)
2208            elif self.dx_min != None:
2209                if self._is_2D():
2210                    data.dqx_data[data.dqx_data == 0] = self.dx_min
2211                else:
2212                    data.dx[data.dx == 0] = self.dx_min
2213            elif self.dx_max != None:
2214                if self._is_2D():
2215                    data.dqy_data[data.dqy_data == 0] = self.dx_max
2216                else:
2217                    data.dx[data.dx == 0] = self.dx_max
2218            self.current_smearer = smear_selection(data, self.model)
2219            # 2D need to set accuracy
2220            if self._is_2D():
2221                self.current_smearer.set_accuracy(accuracy=\
2222                                                  self.smear2d_accuracy)
2223
2224        if msg != None:
2225            wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
2226        else:
2227            get_pin_min.SetBackgroundColour("white")
2228            get_pin_max.SetBackgroundColour("white")
2229        ## set smearing value whether or not the data contain the smearing info
2230       
2231        self._manager.set_smearer(smearer=self.current_smearer,
2232                            fid=self.data.id,
2233                            qmin=float(self.qmin_x),
2234                            qmax=float(self.qmax_x),
2235                            enable_smearer=not self.disable_smearer.GetValue(),
2236                            uid=self.uid)
2237        return msg
2238       
2239    def update_pinhole_smear(self):
2240        """
2241        called by kill_focus on pinhole TextCntrl
2242        to update the changes
2243       
2244        :return: False when wrong value was entered
2245       
2246        """
2247        # msg default
2248        msg = None
2249        # check if any value is changed
2250        if self._is_changed_pinhole():
2251            msg = self._set_pinhole_smear()
2252        wx.CallAfter(self.save_current_state)
2253
2254        if msg != None:
2255            return False
2256        else:
2257            return True
2258                     
2259    def onSlitSmear(self, event):
2260        """
2261        Create a custom slit smear object that will change the way residuals
2262        are compute when fitting
2263        """
2264        if self.model == None:
2265            self.disable_smearer.SetValue(True)
2266            if event == None:
2267                return
2268            msg = "Please select a Model first..."
2269            wx.MessageBox(msg, 'Info')
2270            wx.PostEvent(self._manager.parent,
2271                         StatusEvent(status="Smear: %s" % msg))
2272            return
2273
2274        # Need update param values
2275        self._update_paramv_on_fit()
2276
2277        # msg default
2278        msg = None
2279        # for event given
2280        if event != None:
2281            tcrtl = event.GetEventObject()
2282            # event case of radio button
2283            if tcrtl.GetValue():
2284                self.dxl = 0.0
2285                self.dxw = 0.0
2286                is_new_slit = True
2287            else:
2288                is_new_slit = self._is_changed_slit()
2289        else:
2290            is_new_slit = True
2291       
2292        # if any value is changed
2293        if is_new_slit:
2294            msg = self._set_slit_smear()
2295           
2296        # hide all silt sizer
2297        self._hide_all_smear_info()
2298        # show relevant slit sizers
2299        self._show_smear_sizer()
2300        self.sizer_set_smearer.Layout()
2301        self.Layout()
2302
2303        if event != None:
2304            event.Skip()
2305        self.save_current_state()
2306        event = PageInfoEvent(page=self)
2307        wx.PostEvent(self.parent, event)
2308        if msg != None:
2309            wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
2310
2311    def _is_changed_slit(self):
2312        """
2313        check if any of slit lengths is changed
2314       
2315        :return: True or False
2316       
2317        """
2318        # get the values
2319        width = self.smear_slit_width.GetValue()
2320        height = self.smear_slit_height.GetValue()
2321       
2322        # check and change the box bg color if it was pink
2323        #    but it should be white now
2324        # because this is the case that _set_slit_smear() will not handle
2325        if height.lstrip().rstrip() == "":
2326            self.smear_slit_height.SetBackgroundColour(wx.WHITE)
2327        if width.lstrip().rstrip() == "":
2328            self.smear_slit_width.SetBackgroundColour(wx.WHITE)
2329           
2330        # Check changes in slit width
2331        if width == "":
2332            dxw = 0.0
2333        else:
2334            try:
2335                dxw = float(width)
2336            except:
2337                return True
2338        if self.dxw != dxw:
2339            return True
2340       
2341        # Check changes in slit heigth
2342        if height == "":
2343            dxl = 0.0
2344        else:
2345            try:
2346                dxl = float(height)
2347            except:
2348                return True
2349        if self.dxl != dxl:
2350            return True
2351
2352        return False
2353   
2354    def _set_slit_smear(self):
2355        """
2356        Set custom slit smear
2357       
2358        :return: message to inform the user about the validity
2359            of the values entered for slit smear
2360        """
2361        if self.data.__class__.__name__ == "Data2D" or \
2362                        self.enable2D:
2363            return
2364        # make sure once more if it is smearer
2365        data = copy.deepcopy(self.data)
2366        data_len = len(data.x)
2367        data.dx = None
2368        data.dxl = None
2369        data.dxw = None
2370        msg = None
2371   
2372        try:
2373            self.dxl = float(self.smear_slit_height.GetValue())
2374            data.dxl = self.dxl * numpy.ones(data_len)
2375            self.smear_slit_height.SetBackgroundColour(wx.WHITE)
2376        except:
2377            data.dxl = numpy.zeros(data_len)
2378            if self.smear_slit_height.GetValue().lstrip().rstrip() != "":
2379                self.smear_slit_height.SetBackgroundColour("pink")
2380                msg = "Wrong value entered... "
2381            else:
2382                self.smear_slit_height.SetBackgroundColour(wx.WHITE)
2383        try:
2384            self.dxw = float(self.smear_slit_width.GetValue())
2385            self.smear_slit_width.SetBackgroundColour(wx.WHITE)
2386            data.dxw = self.dxw * numpy.ones(data_len)
2387        except:
2388            data.dxw = numpy.zeros(data_len)
2389            if self.smear_slit_width.GetValue().lstrip().rstrip() != "":
2390                self.smear_slit_width.SetBackgroundColour("pink")
2391                msg = "Wrong Fit value entered... "
2392            else:
2393                self.smear_slit_width.SetBackgroundColour(wx.WHITE)
2394             
2395        self.current_smearer = smear_selection(data, self.model)
2396        ## set smearing value whether or not the data contain the smearing info
2397        self._manager.set_smearer(smearer=self.current_smearer,
2398                                 fid=self.data.id,
2399                                 qmin=float(self.qmin_x),
2400                                 qmax=float(self.qmax_x),
2401                        enable_smearer=not self.disable_smearer.GetValue(),
2402                                 uid=self.uid)
2403        return msg
2404   
2405    def update_slit_smear(self):
2406        """
2407        called by kill_focus on pinhole TextCntrl
2408        to update the changes
2409       
2410        :return: False when wrong value was entered
2411       
2412        """
2413        # msg default
2414        msg = None
2415        # check if any value is changed
2416        if self._is_changed_slit():
2417            msg = self._set_slit_smear()
2418        #self._undo.Enable(True)
2419        self.save_current_state()
2420
2421        if msg != None:
2422            return False
2423        else:
2424            return True
2425                           
2426    def onSmear(self, event):
2427        """
2428        Create a smear object that will change the way residuals
2429        are compute when fitting
2430        """
2431        if event != None:
2432            event.Skip()
2433        if self.data is None:
2434            return
2435
2436        if self.model == None:
2437            self.disable_smearer.SetValue(True)
2438            if event == None:
2439                return
2440            msg = "Please select a Model first..."
2441            wx.MessageBox(msg, 'Info')
2442            wx.PostEvent(self._manager.parent,
2443                         StatusEvent(status="Smear: %s" % msg))
2444            return
2445        # Need update param values
2446        self._update_paramv_on_fit()
2447        if self.model != None:
2448            if self.data.is_data:
2449                self._manager.page_finder[self.uid].add_data(data=self.data)
2450        temp_smearer = self.on_smear_helper()
2451       
2452        self.sizer_set_smearer.Layout()
2453        self.Layout()
2454        self._set_weight()
2455       
2456        ## set smearing value whether or not the data contain the smearing info
2457        wx.CallAfter(self._manager.set_smearer, uid=self.uid,
2458                     smearer=temp_smearer,
2459                     fid=self.data.id,
2460                     qmin=float(self.qmin_x),
2461                     qmax=float(self.qmax_x),
2462                     enable_smearer=not self.disable_smearer.GetValue(),
2463                     draw=True)
2464       
2465        self.state.enable_smearer = self.enable_smearer.GetValue()
2466        self.state.disable_smearer = self.disable_smearer.GetValue()
2467        self.state.pinhole_smearer = self.pinhole_smearer.GetValue()
2468        self.state.slit_smearer = self.slit_smearer.GetValue()
2469       
2470    def on_smear_helper(self, update=False):
2471        """
2472        Help for onSmear
2473       
2474        :param update: force or not to update
2475        """
2476        self._get_smear_info()
2477        #renew smear sizer
2478        if self.smear_type != None:
2479            self.smear_description_smear_type.SetValue(str(self.smear_type))
2480            self.smear_data_left.SetValue(str(self.dq_l))
2481            self.smear_data_right.SetValue(str(self.dq_r))
2482
2483        self._hide_all_smear_info()
2484        data = copy.deepcopy(self.data)
2485       
2486        # make sure once more if it is smearer
2487        temp_smearer = smear_selection(data, self.model)
2488        if self.current_smearer != temp_smearer or update:
2489            self.current_smearer = temp_smearer
2490        if self.enable_smearer.GetValue():
2491            if self.current_smearer == None:
2492                wx.PostEvent(self._manager.parent,
2493                    StatusEvent(status="Data contains no smearing information"))
2494            else:
2495                wx.PostEvent(self._manager.parent,
2496                    StatusEvent(status="Data contains smearing information"))
2497
2498            self.smear_data_left.Show(True)
2499            self.smear_data_right.Show(True)
2500            temp_smearer = self.current_smearer
2501        elif self.disable_smearer.GetValue():
2502            self.smear_description_none.Show(True)
2503        elif self.pinhole_smearer.GetValue():
2504            self.onPinholeSmear(None)
2505        elif self.slit_smearer.GetValue():
2506            self.onSlitSmear(None)
2507        self._show_smear_sizer()
2508       
2509        return temp_smearer
2510   
2511    def on_complete_chisqr(self, event):
2512        """
2513        Display result chisqr on the panel
2514        :event: activated by fitting/ complete after draw
2515        """
2516        try:
2517            if event == None:
2518                output = "-"
2519            elif not numpy.isfinite(event.output):
2520                output = "-"
2521            else:
2522                output = event.output
2523            self.tcChi.SetValue(str(format_number(output, True)))
2524            self.state.tcChi = self.tcChi.GetValue()
2525        except:
2526            pass
2527           
2528    def get_all_checked_params(self):
2529        """
2530        Found all parameters current check and add them to list of parameters
2531        to fit
2532        """
2533        self.param_toFit = []
2534        for item in self.parameters:
2535            if item[0].GetValue() and item not in self.param_toFit:
2536                if item[0].IsShown():
2537                    self.param_toFit.append(item)
2538        for item in self.fittable_param:
2539            if item[0].GetValue() and item not in self.param_toFit:
2540                if item[0].IsShown():
2541                    self.param_toFit.append(item)
2542        self.save_current_state_fit()
2543       
2544        event = PageInfoEvent(page=self)
2545        wx.PostEvent(self.parent, event)
2546        param2fit = []
2547        for item in self.param_toFit:
2548            if item[0] and item[0].IsShown():
2549                param2fit.append(item[1])
2550        self.parent._manager.set_param2fit(self.uid, param2fit)
2551               
2552    def select_all_param(self, event):
2553        """
2554        set to true or false all checkBox given the main checkbox value cb1
2555        """
2556        self.param_toFit = []
2557        if  self.parameters != []:
2558            if  self.cb1.GetValue():
2559                for item in self.parameters:
2560                    if item[0].IsShown():
2561                        ## for data2D select all to fit
2562                        if self.data.__class__.__name__ == "Data2D" or \
2563                                self.enable2D:
2564                            item[0].SetValue(True)
2565                            self.param_toFit.append(item)
2566                        else:
2567                            ## for 1D all parameters except orientation
2568                            if not item in self.orientation_params:
2569                                item[0].SetValue(True)
2570                                self.param_toFit.append(item)
2571                    else:
2572                        item[0].SetValue(False)
2573                #if len(self.fittable_param)>0:
2574                for item in self.fittable_param:
2575                    if item[0].IsShown():
2576                        if self.data.__class__.__name__ == "Data2D" or \
2577                                self.enable2D:
2578                            item[0].SetValue(True)
2579                            self.param_toFit.append(item)
2580                            try:
2581                                if len(self.values[item[1]]) > 0:
2582                                    item[0].SetValue(False)
2583                            except:
2584                                pass
2585   
2586                        else:
2587                            ## for 1D all parameters except orientation
2588                            if not item in self.orientation_params_disp:
2589                                item[0].SetValue(True)
2590                                self.param_toFit.append(item)
2591                                try:
2592                                    if len(self.values[item[1]]) > 0:
2593                                        item[0].SetValue(False)
2594                                except:
2595                                    pass
2596                    else:
2597                        item[0].SetValue(False)
2598
2599            else:
2600                for item in self.parameters:
2601                    item[0].SetValue(False)
2602                for item in self.fittable_param:
2603                    item[0].SetValue(False)
2604                self.param_toFit = []
2605           
2606        self.save_current_state_fit()
2607       
2608        if event != None:
2609            #self._undo.Enable(True)
2610            ## post state to fit panel
2611            event = PageInfoEvent(page=self)
2612            wx.PostEvent(self.parent, event)
2613        param2fit = []
2614        for item in self.param_toFit:
2615            if item[0] and item[0].IsShown():
2616                param2fit.append(item[1])
2617        self.parent._manager.set_param2fit(self.uid, param2fit)
2618
2619    def select_param(self, event):
2620        """
2621        Select TextCtrl  checked for fitting purpose and stores them
2622        in  self.param_toFit=[] list
2623        """
2624        self.param_toFit = []
2625        for item in self.parameters:
2626            #Skip t ifhe angle parameters if 1D data
2627            if self.data.__class__.__name__ != "Data2D" and\
2628                        not self.enable2D:
2629                if item in self.orientation_params:
2630                    continue
2631            #Select parameters to fit for list of primary parameters
2632            if item[0].GetValue() and item[0].IsShown():
2633                if not (item in self.param_toFit):
2634                    self.param_toFit.append(item)
2635            else:
2636                #remove parameters from the fitting list
2637                if item in self.param_toFit:
2638                    self.param_toFit.remove(item)
2639
2640        #Select parameters to fit for list of fittable parameters
2641        #        with dispersion
2642        for item in self.fittable_param:
2643            #Skip t ifhe angle parameters if 1D data
2644            if self.data.__class__.__name__ != "Data2D" and\
2645                        not self.enable2D:
2646                if item in self.orientation_params:
2647                    continue
2648            if item[0].GetValue() and item[0].IsShown():
2649                if not (item in self.param_toFit):
2650                    self.param_toFit.append(item)
2651            else:
2652                #remove parameters from the fitting list
2653                if item in self.param_toFit:
2654                    self.param_toFit.remove(item)
2655
2656        #Calculate num. of angle parameters
2657        if self.data.__class__.__name__ == "Data2D" or \
2658                       self.enable2D:
2659            len_orient_para = 0
2660        else:
2661            len_orient_para = len(self.orientation_params)  # assume even len
2662        #Total num. of angle parameters
2663        if len(self.fittable_param) > 0:
2664            len_orient_para *= 2
2665        #Set the value of checkbox that selected every checkbox or not
2666        if len(self.parameters) + len(self.fittable_param) - len_orient_para \
2667            == len(self.param_toFit):
2668            self.cb1.SetValue(True)
2669        else:
2670            self.cb1.SetValue(False)
2671       
2672        self.save_current_state_fit()
2673        if event != None:
2674            ## post state to fit panel
2675            event = PageInfoEvent(page=self)
2676            wx.PostEvent(self.parent, event)
2677       
2678        param2fit = []
2679        for item in self.param_toFit:
2680            if item[0] and item[0].IsShown():
2681                param2fit.append(item[1])
2682        self.parent._manager.set_param2fit(self.uid, param2fit)
2683       
2684    def set_model_param_sizer(self, model):
2685        """
2686        Build the panel from the model content
2687       
2688        :param model: the model selected in combo box for fitting purpose
2689       
2690        """
2691        self.sizer3.Clear(True)
2692        self.parameters = []
2693        self.str_parameters = []
2694        self.param_toFit = []
2695        self.fittable_param = []
2696        self.fixed_param = []
2697        self.orientation_params = []
2698        self.orientation_params_disp = []
2699       
2700        if model == None:
2701            self.sizer3.Layout()
2702            self.SetupScrolling()
2703            return
2704        ## the panel is drawn using the current value of the fit engine
2705        if self.engine_type == None and self._manager != None:
2706            self.engine_type = self._manager._return_engine_type()
2707
2708        box_description = wx.StaticBox(self, -1, str("Model Parameters"))
2709        boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
2710        sizer = wx.GridBagSizer(5, 5)
2711        ## save the current model
2712        self.model = model
2713           
2714        keys = self.model.getParamList()
2715        #list of dispersion paramaters
2716        self.disp_list = self.model.getDispParamList()
2717
2718        def custom_compare(a, b):
2719            """
2720            Custom compare to order, first by alphabets then second by number.
2721            """
2722            # number at the last digit
2723            a_last = a[len(a) - 1]
2724            b_last = b[len(b) - 1]
2725            # default
2726            num_a = None
2727            num_b = None
2728            # split the names
2729            a2 = a.lower().split('_')
2730            b2 = b.lower().split('_')
2731            # check length of a2, b2
2732            len_a2 = len(a2)
2733            len_b2 = len(b2)
2734            # check if it contains a int number(<10)
2735            try:
2736                num_a = int(a_last)
2737            except:
2738                pass
2739            try:
2740                num_b = int(b_last)
2741            except:
2742                pass
2743            # Put 'scale' near the top; happens
2744            # when numbered param name exists
2745            if a == 'scale':
2746                return -1
2747            # both have a number
2748            if num_a != None and num_b != None:
2749                if num_a > num_b:
2750                    return -1
2751                # same number
2752                elif num_a == num_b:
2753                    # different last names
2754                    if a2[len_a2 - 1] != b2[len_b2 - 1] and num_a != 0:
2755                        return -cmp(a2[len_a2 - 1], b2[len_b2 - 1])
2756                    else:
2757                        return cmp(a, b)
2758                else:
2759                    return 1
2760            # one of them has a number
2761            elif num_a != None:
2762                return 1
2763            elif num_b != None:
2764                return -1
2765            # no numbers
2766            else:
2767                return cmp(a.lower(), b.lower())
2768
2769        keys.sort(custom_compare)
2770   
2771        iy = 0
2772        ix = 0
2773        select_text = "Select All"
2774        self.cb1 = wx.CheckBox(self, -1, str(select_text), (10, 10))
2775        wx.EVT_CHECKBOX(self, self.cb1.GetId(), self.select_all_param)
2776        self.cb1.SetToolTipString("To check/uncheck all the boxes below.")
2777        self.cb1.SetValue(True)
2778       
2779        sizer.Add(self.cb1, (iy, ix), (1, 1), \
2780                             wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 5)
2781        ix += 1
2782        self.text2_2 = wx.StaticText(self, -1, 'Value')
2783        sizer.Add(self.text2_2, (iy, ix), (1, 1), \
2784                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2785        ix += 2
2786        self.text2_3 = wx.StaticText(self, -1, 'Error')
2787        sizer.Add(self.text2_3, (iy, ix), (1, 1), \
2788                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2789        if not self.is_mac:
2790            self.text2_3.Hide()
2791        ix += 1
2792        self.text2_min = wx.StaticText(self, -1, 'Min')
2793        sizer.Add(self.text2_min, (iy, ix), (1, 1), \
2794                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2795        #self.text2_min.Hide()
2796        ix += 1
2797        self.text2_max = wx.StaticText(self, -1, 'Max')
2798        sizer.Add(self.text2_max, (iy, ix), (1, 1), \
2799                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2800        #self.text2_max.Hide()
2801        ix += 1
2802        self.text2_4 = wx.StaticText(self, -1, '[Units]')
2803        sizer.Add(self.text2_4, (iy, ix), (1, 1), \
2804                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2805        self.text2_4.Hide()
2806       
2807        CHECK_STATE = self.cb1.GetValue()
2808        for item in keys:
2809            if not item in self.disp_list and not item in \
2810                    self.model.orientation_params:
2811               
2812                ##prepare a spot to store errors
2813                if not item in self.model.details:
2814                    self.model.details[item] = ["", None, None]
2815         
2816                iy += 1
2817                ix = 0
2818                if (self.model.__class__ in \
2819                    self.model_list_box["Multi-Functions"] or \
2820                    self.temp_multi_functional)\
2821                    and (item in self.model.non_fittable):
2822                    non_fittable_name = wx.StaticText(self, -1, item)
2823                    sizer.Add(non_fittable_name, (iy, ix), (1, 1), \
2824                            wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 21)
2825                    ## add parameter value
2826                    ix += 1
2827                    value = self.model.getParam(item)
2828                    if len(self.model.fun_list) > 0:
2829                        #num = item.split('_')[1][5:7]
2830                        fun_box = wx.ComboBox(self, -1, size=(100, -1),
2831                                    style=wx.CB_READONLY, name='%s' % item)
2832                        self._set_fun_box_list(fun_box)
2833                        fun_box.SetSelection(0)
2834                        #self.fun_box.SetToolTipString("A function
2835                        #    describing the interface")
2836                        wx.EVT_COMBOBOX(fun_box, -1, self._on_fun_box)
2837                    else:
2838                        fun_box = self.ModelTextCtrl(self, -1,
2839                                                     size=(_BOX_WIDTH, 20),
2840                                style=wx.TE_PROCESS_ENTER, name='%s' % item)
2841                        fun_box.SetToolTipString(\
2842                                "Hit 'Enter' after typing to update the plot.")
2843                        fun_box.SetValue(format_number(value, True))
2844                    sizer.Add(fun_box, (iy, ix), (1, 1), wx.EXPAND)
2845                    self.str_parameters.append([None, item, fun_box,
2846                                                None, None, None,
2847                                                None, None])
2848                else:
2849                    ## add parameters name with checkbox for selecting to fit
2850                    cb = wx.CheckBox(self, -1, item)
2851                    cb.SetValue(CHECK_STATE)
2852                    cb.SetToolTipString(" Check mark to fit.")
2853                    #cb.SetValue(True)
2854                    wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
2855                   
2856                    sizer.Add(cb, (iy, ix), (1, 1),
2857                              wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 5)
2858
2859                    ## add parameter value
2860                    ix += 1
2861                    value = self.model.getParam(item)
2862                    ctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
2863                                        style=wx.TE_PROCESS_ENTER)
2864                    ctl1.SetToolTipString(\
2865                                "Hit 'Enter' after typing to update the plot.")
2866                    ctl1.SetValue(format_number(value, True))
2867                    sizer.Add(ctl1, (iy, ix), (1, 1), wx.EXPAND)
2868                    ## text to show error sign
2869                    ix += 1
2870                    text2 = wx.StaticText(self, -1, '+/-')
2871                    sizer.Add(text2, (iy, ix), (1, 1), \
2872                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2873                    if not self.is_mac:
2874                        text2.Hide()
2875                    ix += 1
2876                    ctl2 = wx.TextCtrl(self, -1,
2877                                       size=(_BOX_WIDTH / 1.2, 20), style=0)
2878                    sizer.Add(ctl2, (iy, ix), (1, 1),
2879                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2880                    if not self.is_mac:
2881                        ctl2.Hide()
2882                   
2883                    ix += 1
2884                    ctl3 = self.ModelTextCtrl(self, -1,
2885                                              size=(_BOX_WIDTH / 1.9, 20),
2886                                              style=wx.TE_PROCESS_ENTER,
2887                                text_enter_callback=self._onparamRangeEnter)
2888         
2889                    sizer.Add(ctl3, (iy, ix), (1, 1),
2890                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2891           
2892                    ix += 1
2893                    ctl4 = self.ModelTextCtrl(self, -1,
2894                                              size=(_BOX_WIDTH / 1.9, 20),
2895                                              style=wx.TE_PROCESS_ENTER,
2896                                text_enter_callback=self._onparamRangeEnter)
2897                    sizer.Add(ctl4, (iy, ix), (1, 1),
2898                              wx.EXPAND | wx.FIXED_MINSIZE, 0)
2899   
2900                    ix += 1
2901                    # Units
2902                    if item in self.model.details:
2903                        units = wx.StaticText(self, -1,
2904                            self.model.details[item][0], style=wx.ALIGN_LEFT)
2905                    else:
2906                        units = wx.StaticText(self, -1, "",
2907                                              style=wx.ALIGN_LEFT)
2908                    sizer.Add(units, (iy, ix), (1, 1),
2909                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2910                       
2911                    self.parameters.append([cb, item, ctl1,
2912                                            text2, ctl2, ctl3, ctl4, units])
2913                                 
2914        iy += 1
2915        sizer.Add((10, 10), (iy, ix), (1, 1),
2916                  wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
2917       
2918        # type can be either Guassian or Array
2919        if len(self.model.dispersion.values()) > 0:
2920            type = self.model.dispersion.values()[0]["type"]
2921        else:
2922            type = "Gaussian"
2923           
2924        iy += 1
2925        ix = 0
2926        #Add tile for orientational angle
2927        for item in keys:
2928            if item in self.model.orientation_params:
2929                orient_angle = wx.StaticText(self, -1, '[For 2D only]:')
2930                sizer.Add(orient_angle, (iy, ix), (1, 1),
2931                          wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
2932                if not self.data.__class__.__name__ == "Data2D" and \
2933                        not self.enable2D:
2934                    orient_angle.Hide()
2935                else:
2936                    orient_angle.Show(True)
2937                break
2938     
2939        #For Gaussian only
2940        if type.lower() != "array":
2941            for item in self.model.orientation_params:
2942                if not item in self.disp_list:
2943                    ##prepare a spot to store min max
2944                    if not item in self.model.details:
2945                        self.model.details[item] = ["", None, None]
2946                         
2947                    iy += 1
2948                    ix = 0
2949                    ## add parameters name with checkbox for selecting to fit
2950                    cb = wx.CheckBox(self, -1, item)
2951                    cb.SetValue(CHECK_STATE)
2952                    cb.SetToolTipString("Check mark to fit")
2953                    wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
2954                    if self.data.__class__.__name__ == "Data2D" or \
2955                            self.enable2D:
2956                        cb.Show(True)
2957                    else:
2958                        cb.Hide()
2959                    sizer.Add(cb, (iy, ix), (1, 1),
2960                              wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 5)
2961   
2962                    ## add parameter value
2963                    ix += 1
2964                    value = self.model.getParam(item)
2965                    ctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
2966                                        style=wx.TE_PROCESS_ENTER)
2967                    ctl1.SetToolTipString(\
2968                                "Hit 'Enter' after typing to update the plot.")
2969                    ctl1.SetValue(format_number(value, True))
2970                    if self.data.__class__.__name__ == "Data2D" or \
2971                            self.enable2D:
2972                        ctl1.Show(True)
2973                    else:
2974                        ctl1.Hide()
2975                    sizer.Add(ctl1, (iy, ix), (1, 1), wx.EXPAND)
2976                    ## text to show error sign
2977                    ix += 1
2978                    text2 = wx.StaticText(self, -1, '+/-')
2979                    sizer.Add(text2, (iy, ix), (1, 1), \
2980                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2981
2982                    text2.Hide()
2983                    ix += 1
2984                    ctl2 = wx.TextCtrl(self, -1,
2985                                       size=(_BOX_WIDTH / 1.2, 20), style=0)
2986                    sizer.Add(ctl2, (iy, ix), (1, 1),
2987                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2988
2989                    ctl2.Hide()
2990                   
2991                    ix += 1
2992                    ctl3 = self.ModelTextCtrl(self, -1,
2993                                              size=(_BOX_WIDTH / 1.8, 20),
2994                                              style=wx.TE_PROCESS_ENTER,
2995                                text_enter_callback=self._onparamRangeEnter)
2996                   
2997                    sizer.Add(ctl3, (iy, ix), (1, 1),
2998                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2999                    ctl3.Hide()
3000                 
3001                    ix += 1
3002                    ctl4 = self.ModelTextCtrl(self, -1,
3003                                              size=(_BOX_WIDTH / 1.8, 20),
3004                                              style=wx.TE_PROCESS_ENTER,
3005                            text_enter_callback=self._onparamRangeEnter)
3006                    sizer.Add(ctl4, (iy, ix), (1, 1),
3007                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
3008                   
3009                    ctl4.Hide()
3010                   
3011                    if self.data.__class__.__name__ == "Data2D" or \
3012                            self.enable2D:
3013                        if self.is_mac:
3014                            text2.Show(True)
3015                            ctl2.Show(True)
3016                        ctl3.Show(True)
3017                        ctl4.Show(True)
3018                   
3019                    ix += 1
3020                    # Units
3021                    if item in self.model.details:
3022                        units = wx.StaticText(self, -1,
3023                                              self.model.details[item][0],
3024                                              style=wx.ALIGN_LEFT)
3025                    else:
3026                        units = wx.StaticText(self, -1, "",
3027                                              style=wx.ALIGN_LEFT)
3028                    if self.data.__class__.__name__ == "Data2D" or \
3029                            self.enable2D:
3030                        units.Show(True)
3031                    else:
3032                        units.Hide()
3033                   
3034                    sizer.Add(units, (iy, ix), (1, 1),
3035                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
3036                                         
3037                    self.parameters.append([cb, item, ctl1,
3038                                            text2, ctl2, ctl3, ctl4, units])
3039                    self.orientation_params.append([cb, item, ctl1,
3040                                            text2, ctl2, ctl3, ctl4, units])
3041             
3042        iy += 1
3043        box_description.SetForegroundColour(wx.BLUE)
3044        #Display units text on panel
3045        for item in keys:
3046            if item in self.model.details:
3047                self.text2_4.Show()
3048        #Fill the list of fittable parameters
3049        self.get_all_checked_params()
3050        self.save_current_state_fit()
3051        boxsizer1.Add(sizer)
3052        self.sizer3.Add(boxsizer1, 0, wx.EXPAND | wx.ALL, 10)
3053        self.sizer3.Layout()
3054        self.Layout()
3055
3056    def on_right_down(self, event):
3057        """
3058        Get key stroke event
3059        """
3060        if self.data == None:
3061            return
3062        # Figuring out key combo: Cmd for copy, Alt for paste
3063        if event.AltDown() and event.ShiftDown():
3064            self._manager.show_ftol_dialog()
3065            flag = True
3066        elif event.AltDown() or event.ShiftDown():
3067            flag = False
3068        else:
3069            return
3070        # make event free
3071        event.Skip()
3072        # messages depending on the flag
3073        if not flag:
3074            msg = " Could not open ftol dialog;"
3075            msg += " Check if the Scipy fit engine is selected in the menubar."
3076            infor = 'warning'
3077            # inform msg to wx
3078            wx.PostEvent(self.parent.parent,
3079                        StatusEvent(status=msg, info=infor))
3080       
3081    def _onModel2D(self, event):
3082        """
3083        toggle view of model from 1D to 2D  or 2D from 1D
3084        """
3085        if self.model_view.GetLabelText() == "Show 2D":
3086            self.model_view.SetLabel("Show 1D")
3087            self.enable2D = True
3088             
3089        else:
3090            self.model_view.SetLabel("Show 2D")
3091            self.enable2D = False
3092        self.Show(False)
3093        self.create_default_data()
3094        self._manager.store_data(self.uid, data_list=[self.data])
3095
3096        self.set_model_param_sizer(self.model)
3097        self._set_sizer_dispersion()
3098        self._set_weight(is_2D=self.enable2D)
3099        self._set_smear_buttons()
3100        self.Show(True)
3101        self.SetupScrolling()
3102        self._draw_model()
3103       
3104        self.state.enable2D = copy.deepcopy(self.enable2D)
3105   
3106    def _set_smear_buttons(self):
3107        """
3108        Set semarer radio buttons
3109        """
3110        # more disables for 2D
3111        if self.data.__class__.__name__ == "Data2D" or \
3112                    self.enable2D:
3113            self.slit_smearer.Disable()
3114            self.pinhole_smearer.Enable(True)
3115            self.default_mask = copy.deepcopy(self.data.mask)
3116        else:
3117            self.slit_smearer.Enable(True)
3118            self.pinhole_smearer.Enable(True)
3119           
3120           
3121class BGTextCtrl(wx.TextCtrl):
3122    """
3123    Text control used to display outputs.
3124    No editing allowed. The background is
3125    grayed out. User can't select text.
3126    """
3127    def __init__(self, *args, **kwds):
3128        wx.TextCtrl.__init__(self, *args, **kwds)
3129        self.SetEditable(False)
3130        self.SetBackgroundColour(self.GetParent().parent.GetBackgroundColour())
3131       
3132        # Bind to mouse event to avoid text highlighting
3133        # The event will be skipped once the call-back
3134        # is called.
3135        self.Bind(wx.EVT_MOUSE_EVENTS, self._click)
3136       
3137    def _click(self, event):
3138        """
3139        Prevent further handling of the mouse event
3140        by not calling Skip().
3141        """
3142        pass
Note: See TracBrowser for help on using the repository browser.