source: sasview/fittingview/src/sans/perspectives/fitting/fitpage.py @ 9e91546

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 9e91546 was 14cd6b92, checked in by Mathieu Doucet <doucetm@…>, 13 years ago

Fixing code style problems and bugs

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