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

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 b582d6bc was 2d0756a5, checked in by Jae Cho <jhjcho@…>, 13 years ago

fixed fit/stop button behavior

  • Property mode set to 100644
File size: 134.8 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.set_fitbutton()
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 event != None:
1087            event.Skip() 
1088        if self.fit_started:
1089            self._StopFit()
1090            self.fit_started = False
1091            wx.CallAfter(self.set_fitbutton)
1092            return   
1093
1094        if len(self.parent._manager.fit_thread_list)>0 and\
1095                    self.parent._manager._fit_engine != "park" and\
1096                    self._manager.sim_page != None and \
1097                    self._manager.sim_page.uid == self.uid: 
1098            msg = "The FitEnging will be set to 'ParkMC'\n"
1099            msg += " to fit with more than one data set..."
1100            wx.MessageBox(msg, 'Info')
1101            #wx.PostEvent(self._manager.parent, StatusEvent(status=\
1102            #                "Fitting: %s"%msg))
1103           
1104        if self.data is None:
1105            msg = "Please get Data first..."
1106            wx.MessageBox(msg, 'Info')
1107            wx.PostEvent(self._manager.parent, StatusEvent(status=\
1108                            "Fit: %s" % msg))
1109            return
1110        if self.model is None:
1111            msg = "Please select a Model first..."
1112            wx.MessageBox(msg, 'Info')
1113            wx.PostEvent(self._manager.parent, StatusEvent(status=\
1114                            "Fit: %s"%msg, type="stop"))
1115            return
1116       
1117        if len(self.param_toFit) <= 0:
1118            msg= "Select at least one parameter to fit"
1119            wx.MessageBox(msg, 'Info')
1120            wx.PostEvent(self._manager.parent, StatusEvent(status= msg, 
1121                                                         type="stop" ))
1122            return 
1123       
1124        flag = self._update_paramv_on_fit() 
1125       
1126        if self.batch_on and not self._is_2D():
1127            if not self._validate_Npts_1D():
1128                return
1129               
1130        if not flag:
1131            msg= "Fitting range or parameters are invalid"
1132            wx.PostEvent(self.parent.parent, StatusEvent(status= msg, 
1133                                                         type="stop"))
1134            return 
1135             
1136        self.select_param(event =None)
1137       
1138        #Clear errors if exist from previous fitting
1139        #self._clear_Err_on_Fit()
1140
1141        # Remove or do not allow fitting on the Q=0 point, especially
1142        # when y(q=0)=None at x[0].         
1143        self.qmin_x = float(self.qmin.GetValue())
1144        self.qmax_x = float(self.qmax.GetValue())
1145        self._manager._reset_schedule_problem(value=0, uid=self.uid)
1146        self._manager.schedule_for_fit(uid=self.uid,value=1) 
1147        self._manager.set_fit_range(uid=self.uid,qmin=self.qmin_x, 
1148                                   qmax=self.qmax_x)
1149
1150        #single fit
1151        #self._manager.onFit(uid=self.uid)
1152        self.fit_started = self._manager.onFit(uid=self.uid)
1153        wx.CallAfter(self.set_fitbutton)
1154   
1155    def set_fitbutton(self): 
1156        """
1157        Set fit button label depending on the fit_started[bool]
1158        """
1159        if self.fit_started:
1160            label = "Stop"
1161            color = "red"
1162        else:
1163            label = "Fit"
1164            color = "black"
1165        self.btFit.Enable(False)
1166        self.btFit.SetLabel(label)
1167        self.btFit.SetForegroundColour(color)
1168        self.btFit.Enable(True)
1169                     
1170    def get_weight_flag(self):
1171        """
1172        Get flag corresponding to a given weighting dI data.
1173        """
1174        button_list = [self.dI_noweight,
1175                       self.dI_didata,
1176                       self.dI_sqrdata,
1177                       self.dI_idata]
1178        flag = 1
1179        for item in button_list:
1180            if item.GetValue():
1181                if button_list.index(item) == 0:
1182                    flag = 0 #dy = numpy.ones_like(dy_data)
1183                elif button_list.index(item) == 1:
1184                    flag = 1 #dy = dy_data
1185                elif button_list.index(item) == 2:
1186                    flag = 2 #dy = numpy.sqrt(numpy.abs(data))
1187                elif button_list.index(item) == 3:
1188                    flag = 3 # dy = numpy.abs(data)
1189                break
1190        return flag
1191               
1192           
1193    def _StopFit(self, event=None):
1194        """
1195        Stop fit
1196        """
1197        if event != None:
1198            event.Skip()
1199        self._manager.stop_fit(self.uid)
1200        self._manager._reset_schedule_problem(value=0)
1201        self._on_fit_complete()
1202         
1203    def rename_model(self):
1204        """
1205        find a short name for model
1206        """
1207        if self.model is not None:
1208            self.model.name = "M" + str(self.index_model)
1209   
1210
1211    def _on_select_model(self, event=None): 
1212        """
1213        call back for model selection
1214        """ 
1215        self.Show(False) 
1216        copy_flag = False 
1217        is_poly_enabled = None 
1218        if event != None:
1219            if (event.GetEventObject() == self.formfactorbox\
1220                        and self.structurebox.GetLabel() != 'None')\
1221                        or event.GetEventObject() == self.structurebox\
1222                        or event.GetEventObject() == self.multifactorbox:
1223                copy_flag = self.get_copy_params()
1224                is_poly_enabled = self.enable_disp.GetValue() 
1225
1226        self._on_select_model_helper() 
1227        self.set_model_param_sizer(self.model)                   
1228        if self.model is None:
1229            self._set_bookmark_flag(False)
1230            self._keep.Enable(False)
1231            self._set_save_flag(False)
1232        self.enable_disp.SetValue(False)
1233        self.disable_disp.SetValue(True)
1234        try:
1235            self.set_dispers_sizer()
1236        except:
1237            pass
1238        #self.btFit.SetFocus()
1239        self.state.enable_disp = self.enable_disp.GetValue()
1240        self.state.disable_disp = self.disable_disp.GetValue()
1241        self.state.pinhole_smearer = self.pinhole_smearer.GetValue()
1242        self.state.slit_smearer = self.slit_smearer.GetValue()
1243   
1244        self.state.structurecombobox = self.structurebox.GetLabel()#.GetCurrentSelection()
1245        self.state.formfactorcombobox = self.formfactorbox.GetLabel()#.GetCurrentSelection()
1246        self.enable_fit_button()
1247        if self.model != None:
1248            self.m_name = self.model.name
1249            self.state.m_name = self.m_name
1250            self.rename_model()
1251            self._set_copy_flag(True)
1252            self._set_paste_flag(True)
1253            if self.data is not None:
1254                is_data = check_data_validity(self.data) 
1255                if is_data:
1256                    self._set_bookmark_flag(True)
1257                    self._keep.Enable(True)
1258                    self._set_save_flag(True)
1259            # Reset smearer, model and data
1260            if not copy_flag:
1261                self.disable_smearer.SetValue(True)
1262                self.enable_smearer.SetValue(False)
1263   
1264            # more disables for 2D
1265            self._set_smear_buttons()
1266           
1267            try:
1268                # update smearer sizer
1269                #if not self.enable_smearer.GetValue():
1270                #    self.disable_smearer.SetValue(True)
1271                self.onSmear(None)
1272                temp_smear = None
1273                if not self.disable_smearer.GetValue():
1274                    # Set the smearer environments
1275                    temp_smear = self.current_smearer
1276            except:
1277                raise
1278                ## error occured on chisqr computation
1279                #pass
1280            ## event to post model to fit to fitting plugins
1281            (ModelEventbox, EVT_MODEL_BOX) = wx.lib.newevent.NewEvent()
1282         
1283            ## set smearing value whether or not
1284            #    the data contain the smearing info
1285            evt = ModelEventbox(model=self.model, 
1286                                        smearer=temp_smear, 
1287                             enable_smearer=not self.disable_smearer.GetValue(),
1288                                        qmin=float(self.qmin_x),
1289                                        uid=self.uid,
1290                                        caption=self.window_caption,
1291                                     qmax=float(self.qmax_x)) 
1292   
1293            self._manager._on_model_panel(evt=evt)
1294            self.mbox_description.SetLabel("Model [ %s ]" % str(self.model.name))
1295            self.mbox_description.SetForegroundColour(wx.BLUE)
1296            self.state.model = self.model.clone()
1297            self.state.model.name = self.model.name
1298
1299           
1300        if event != None:
1301            ## post state to fit panel
1302            new_event = PageInfoEvent(page = self)
1303            wx.PostEvent(self.parent, new_event) 
1304            #update list of plugins if new plugin is available
1305            if self.plugin_rbutton.GetValue():
1306                temp = self.parent.update_model_list()
1307                if temp:
1308                    self.model_list_box = temp
1309                    current_val = self.formfactorbox.GetLabel()
1310                    pos = self.formfactorbox.GetSelection()
1311                    self._show_combox_helper()
1312                    self.formfactorbox.SetSelection(pos)
1313                    self.formfactorbox.SetValue(current_val)
1314            # when select a model only from guictr/button
1315            if is_poly_enabled != None:
1316                self.enable_disp.SetValue(is_poly_enabled)
1317                self.disable_disp.SetValue(not is_poly_enabled)
1318                self._set_dipers_Param(event=None)
1319                self.state.enable_disp = self.enable_disp.GetValue()
1320                self.state.disable_disp = self.disable_disp.GetValue()
1321
1322            # Keep the previous param values
1323            if copy_flag:
1324                self.get_paste_params(copy_flag)
1325                wx.CallAfter(self._onDraw, None)
1326               
1327        else:
1328            self._draw_model()
1329           
1330        if self.batch_on:
1331            self.slit_smearer.Enable(False)
1332            self.pinhole_smearer.Enable(False)
1333            self.btEditMask.Disable() 
1334            self.EditMask_title.Disable()
1335           
1336        self.Show(True)     
1337        self.SetupScrolling()
1338         
1339    def _onparamEnter(self,event):
1340        """
1341        when enter value on panel redraw model according to changed
1342        """
1343        if self.model ==None:
1344            msg="Please select a Model first..."
1345            wx.MessageBox(msg, 'Info')
1346            #wx.PostEvent(self._manager.parent, StatusEvent(status=\
1347            #                "Parameters: %s"%msg))
1348            return
1349
1350        #default flag
1351        flag = False
1352        self.fitrange = True
1353        #get event object
1354        tcrtl = event.GetEventObject()
1355       
1356        #wx.PostEvent(self._manager.parent, StatusEvent(status=" \
1357        #                        updating ... ",type="update"))
1358        #Clear msg if previously shown.
1359        msg= ""
1360        wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
1361
1362        if check_float(tcrtl):
1363            flag = self._onparamEnter_helper() 
1364            self.set_npts2fit() 
1365            if self.fitrange:             
1366                temp_smearer = None
1367                if not self.disable_smearer.GetValue():
1368                    temp_smearer= self.current_smearer
1369                    ## set smearing value whether or not
1370                    #        the data contain the smearing info
1371                    if self.slit_smearer.GetValue():
1372                        flag1 = self.update_slit_smear()
1373                        flag = flag or flag1
1374                    elif self.pinhole_smearer.GetValue():
1375                        flag1 = self.update_pinhole_smear()
1376                        flag = flag or flag1
1377                elif self.data.__class__.__name__ !=  "Data2D" and \
1378                        not self.enable2D:
1379                    self._manager.set_smearer(smearer=temp_smearer, 
1380                                              fid=self.data.id,
1381                                              uid=self.uid,
1382                                             qmin= float(self.qmin_x),
1383                                            qmax= float(self.qmax_x),
1384                            enable_smearer=not self.disable_smearer.GetValue(),
1385                                            draw=True) 
1386                if flag:   
1387                    #self.compute_chisqr(smearer= temp_smearer)
1388       
1389                    ## new state posted
1390                    if self.state_change:
1391                        #self._undo.Enable(True)
1392                        event = PageInfoEvent(page = self)
1393                        wx.PostEvent(self.parent, event)
1394                    self.state_change= False 
1395            else: 
1396                # invalid fit range: do nothing here:
1397                # msg already displayed in validate
1398                return     
1399        else:
1400            self.save_current_state()
1401            msg= "Cannot Plot :Must enter a number!!!  "
1402            wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
1403             
1404        self.save_current_state() 
1405        return 
1406   
1407    def _onparamRangeEnter(self, event):
1408        """
1409        Check validity of value enter in the parameters range field
1410        """
1411        #if self.check_invalid_panel():
1412        #    return
1413        tcrtl= event.GetEventObject()
1414        #Clear msg if previously shown.
1415        msg= ""
1416        wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
1417        # Flag to register when a parameter has changed.
1418        is_modified = False
1419        if tcrtl.GetValue().lstrip().rstrip()!="":
1420            try:
1421                value = float(tcrtl.GetValue())
1422                tcrtl.SetBackgroundColour(wx.WHITE)
1423                self._check_value_enter(self.fittable_param ,is_modified)
1424                self._check_value_enter(self.parameters ,is_modified) 
1425            except:
1426                tcrtl.SetBackgroundColour("pink")
1427                msg= "Model Error:wrong value entered : %s"% sys.exc_value
1428                wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
1429                return 
1430        else:
1431           tcrtl.SetBackgroundColour(wx.WHITE)
1432           
1433        #self._undo.Enable(True)
1434        self.save_current_state()
1435        event = PageInfoEvent(page = self)
1436        wx.PostEvent(self.parent, event)
1437        self.state_change= False
1438
1439                   
1440    def _onQrangeEnter(self, event):
1441        """
1442        Check validity of value enter in the Q range field
1443        """
1444        tcrtl = event.GetEventObject()
1445        #Clear msg if previously shown.
1446        msg= ""
1447        wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
1448        # For theory mode
1449        if not self.data.is_data:
1450            self.npts_x = self.Npts_total.GetValue()
1451            self.Npts_fit.SetValue(self.npts_x)
1452            self.create_default_data()
1453        # Flag to register when a parameter has changed.
1454        is_modified = False
1455        if tcrtl.GetValue().lstrip().rstrip()!="":
1456            try:
1457                value = float(tcrtl.GetValue())
1458                tcrtl.SetBackgroundColour(wx.WHITE)
1459
1460                # If qmin and qmax have been modified, update qmin and qmax
1461                if self._validate_qrange( self.qmin, self.qmax):
1462                    tempmin = float(self.qmin.GetValue())
1463                    if tempmin != self.qmin_x:
1464                        self.qmin_x = tempmin
1465                    tempmax = float(self.qmax.GetValue())
1466                    if tempmax != self.qmax_x:
1467                        self.qmax_x = tempmax
1468                else:
1469                    tcrtl.SetBackgroundColour("pink")
1470                    msg= "Model Error:wrong value entered : %s"% sys.exc_value
1471                    wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
1472                    return 
1473               
1474            except:
1475                tcrtl.SetBackgroundColour("pink")
1476                msg= "Model Error:wrong value entered : %s"% sys.exc_value
1477                wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
1478                return 
1479            #Check if # of points for theory model are valid(>0).
1480            # check for 2d
1481            if self.data.__class__.__name__ == "Data2D" or \
1482                    self.enable2D:
1483                # set mask   
1484                radius= numpy.sqrt(self.data.qx_data*self.data.qx_data + 
1485                                    self.data.qy_data*self.data.qy_data )
1486                index_data = ((self.qmin_x <= radius)& \
1487                                (radius<= self.qmax_x))
1488                index_data = (index_data)&(self.data.mask)
1489                index_data = (index_data)&(numpy.isfinite(self.data.data))
1490                if len(index_data[index_data]) < 10:
1491                    msg = "Cannot Plot :No or too little npts in"
1492                    msg += " that data range!!!  "
1493                    wx.PostEvent(self.parent.parent, 
1494                                 StatusEvent(status=msg))
1495                    return
1496                else:
1497                    #self.data.mask = index_data
1498                    #self.Npts_fit.SetValue(str(len(self.data.mask)))
1499                    self.set_npts2fit() 
1500            else:
1501                index_data = ((self.qmin_x <= self.data.x)& \
1502                              (self.data.x <= self.qmax_x))
1503                self.Npts_fit.SetValue(str(len(self.data.x[index_data])))
1504           
1505            self.npts_x = self.Npts_total.GetValue()
1506            self.create_default_data()
1507            self._save_plotting_range()
1508        else:
1509           tcrtl.SetBackgroundColour("pink")
1510           msg= "Model Error:wrong value entered!!!"
1511           wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
1512       
1513        self._draw_model()
1514        self.save_current_state()
1515        event = PageInfoEvent(page = self)
1516        wx.PostEvent(self.parent, event)
1517        self.state_change= False
1518        return
1519   
1520    def _clear_Err_on_Fit(self):
1521        """
1522        hide the error text control shown
1523        after fitting
1524        """
1525        if self.is_mac:
1526            return
1527        if hasattr(self,"text2_3"):
1528            self.text2_3.Hide()
1529
1530        if len(self.parameters)>0:
1531            for item in self.parameters:
1532                #Skip t ifhe angle parameters if 1D data
1533                if self.data.__class__.__name__ !=  "Data2D" and \
1534                        not self.enable2D:
1535                    if item in self.orientation_params:
1536                        continue
1537                if item in self.param_toFit:
1538                    continue
1539                ## hide statictext +/-   
1540                if len(item) < 4 :
1541                    continue
1542                if item[3]!=None and item[3].IsShown():
1543                    item[3].Hide()
1544                ## hide textcrtl  for error after fit
1545                if item[4]!=None and item[4].IsShown():                   
1546                    item[4].Hide()
1547 
1548        if len(self.fittable_param)>0:
1549            for item in self.fittable_param:
1550                #Skip t ifhe angle parameters if 1D data
1551                if self.data.__class__.__name__ !=  "Data2D" and \
1552                        not self.enable2D:
1553                    if item in self.orientation_params:
1554                        continue
1555                if item in self.param_toFit:
1556                    continue
1557                if len(item) < 4 :
1558                    continue
1559                ## hide statictext +/-   
1560                if item[3]!=None and item[3].IsShown():
1561                    item[3].Hide()
1562                ## hide textcrtl  for error after fit
1563                if item[4]!=None and item[4].IsShown():
1564                    item[4].Hide()
1565        return       
1566               
1567    def _get_defult_custom_smear(self):
1568        """
1569        Get the defult values for custum smearing.
1570        """
1571        # get the default values
1572        if self.dxl == None: self.dxl = 0.0
1573        if self.dxw == None: self.dxw = ""
1574        if self.dx_min == None: self.dx_min = SMEAR_SIZE_L
1575        if self.dx_max == None: self.dx_max = SMEAR_SIZE_H
1576       
1577    def _get_smear_info(self):
1578        """
1579        Get the smear info from data.
1580       
1581        :return: self.smear_type, self.dq_l and self.dq_r,
1582            respectively the type of the smear, dq_min and
1583            dq_max for pinhole smear data
1584            while dxl and dxw for slit smear
1585           
1586        """
1587
1588        # default
1589        self.smear_type = None
1590        self.dq_l = None
1591        self.dq_r = None
1592        data = self.data
1593        if self.data is None:
1594            return
1595        elif self.data.__class__.__name__ ==  "Data2D" or \
1596                        self.enable2D: 
1597            if data.dqx_data == None or  data.dqy_data ==None: 
1598                return
1599            elif self.current_smearer != None and (data.dqx_data.any()!=0) and \
1600                            (data.dqx_data.any()!=0): 
1601                self.smear_type = "Pinhole2d"
1602                self.dq_l = format_number(numpy.average(data.dqx_data)) 
1603                self.dq_r = format_number(numpy.average(data.dqy_data)) 
1604                return 
1605            else: 
1606                return
1607        # check if it is pinhole smear and get min max if it is.
1608        if data.dx != None and all(data.dx !=0): 
1609            self.smear_type = "Pinhole" 
1610            self.dq_l = data.dx[0]
1611            self.dq_r = data.dx[-1]
1612           
1613        # check if it is slit smear and get min max if it is.
1614        elif data.dxl != None or data.dxw != None: 
1615            self.smear_type = "Slit" 
1616            if data.dxl != None and all(data.dxl !=0):
1617                self.dq_l = data.dxl[0]
1618            if data.dxw != None and all(data.dxw !=0): 
1619                self.dq_r = data.dxw[0]   
1620        #return self.smear_type,self.dq_l,self.dq_r       
1621   
1622    def _show_smear_sizer(self):   
1623        """
1624        Show only the sizers depending on smear selection
1625        """
1626        # smear disabled
1627        if self.disable_smearer.GetValue():
1628            self.smear_description_none.Show(True)
1629        # 2Dsmear
1630        elif self._is_2D():
1631            self.smear_description_accuracy_type.Show(True)
1632            self.smear_accuracy.Show(True)
1633            self.smear_description_accuracy_type.Show(True)
1634            self.smear_description_2d.Show(True)
1635            self.smear_description_2d_x.Show(True)
1636            self.smear_description_2d_y.Show(True)
1637            if self.pinhole_smearer.GetValue():
1638                self.smear_pinhole_min.Show(True)
1639                self.smear_pinhole_max.Show(True)
1640        # smear from data
1641        elif self.enable_smearer.GetValue():
1642
1643            self.smear_description_dqdata.Show(True)
1644            if self.smear_type != None:
1645                self.smear_description_smear_type.Show(True)
1646                if self.smear_type == 'Slit':
1647                    self.smear_description_slit_height.Show(True)
1648                    self.smear_description_slit_width.Show(True)               
1649                elif self.smear_type == 'Pinhole':
1650                    self.smear_description_pin_min.Show(True)
1651                    self.smear_description_pin_max.Show(True)
1652                self.smear_description_smear_type.Show(True)
1653                self.smear_description_type.Show(True)
1654                self.smear_data_left.Show(True)
1655                self.smear_data_right.Show(True)
1656        # custom pinhole smear
1657        elif self.pinhole_smearer.GetValue():
1658            if self.smear_type == 'Pinhole':
1659                self.smear_message_new_p.Show(True)
1660                self.smear_description_pin_min.Show(True)
1661                self.smear_description_pin_max.Show(True)
1662
1663            self.smear_pinhole_min.Show(True)
1664            self.smear_pinhole_max.Show(True)
1665        # custom slit smear
1666        elif self.slit_smearer.GetValue():
1667            self.smear_message_new_s.Show(True)
1668            self.smear_description_slit_height.Show(True)
1669            self.smear_slit_height.Show(True)
1670            self.smear_description_slit_width.Show(True)
1671            self.smear_slit_width.Show(True)
1672
1673    def _hide_all_smear_info(self):
1674        """
1675        Hide all smearing messages in the set_smearer sizer
1676        """
1677        self.smear_description_none.Hide()
1678        self.smear_description_dqdata.Hide()
1679        self.smear_description_type.Hide()
1680        self.smear_description_smear_type.Hide()
1681        self.smear_description_accuracy_type.Hide()
1682        self.smear_description_2d_x.Hide()
1683        self.smear_description_2d_y.Hide()
1684        self.smear_description_2d.Hide()
1685       
1686        self.smear_accuracy.Hide()
1687        self.smear_data_left.Hide()
1688        self.smear_data_right.Hide()
1689        self.smear_description_pin_min.Hide()
1690        self.smear_pinhole_min.Hide()
1691        self.smear_description_pin_max.Hide()
1692        self.smear_pinhole_max.Hide()
1693        self.smear_description_slit_height.Hide()
1694        self.smear_slit_height.Hide()
1695        self.smear_description_slit_width.Hide()
1696        self.smear_slit_width.Hide()
1697        self.smear_message_new_p.Hide()
1698        self.smear_message_new_s.Hide()
1699   
1700    def _set_accuracy_list(self):
1701        """
1702        Set the list of an accuracy in 2D custum smear: Xhigh, High, Med, or Low
1703        """
1704        # list of accuracy choices
1705        list = ['Low','Med','High','Xhigh']
1706        for idx in range(len(list)):
1707            self.smear_accuracy.Append(list[idx],idx)
1708           
1709    def _set_fun_box_list(self,fun_box):
1710        """
1711        Set the list of func for multifunctional models
1712        """
1713        # Check if it is multi_functional model
1714        if self.model.__class__ not in self.model_list_box["Multi-Functions"] \
1715                and not self.temp_multi_functional:
1716            return None
1717        # Get the func name list
1718        list = self.model.fun_list
1719        if len(list) == 0:
1720            return None
1721        # build function (combo)box
1722        ind = 0
1723        while(ind < len(list)):
1724            for key, val in list.iteritems():
1725                if (val == ind):
1726                    fun_box.Append(key,val)
1727                    break
1728            ind += 1
1729       
1730    def _on_select_accuracy(self,event):
1731        """
1732        Select an accuracy in 2D custom smear: Xhigh, High, Med, or Low
1733        """
1734        #event.Skip()
1735        # Check if the accuracy is same as before
1736        #self.smear2d_accuracy = event.GetEventObject().GetValue()
1737        self.smear2d_accuracy = self.smear_accuracy.GetValue()
1738        if self.pinhole_smearer.GetValue():
1739            self.onPinholeSmear(event=None)
1740        else:   
1741            self.onSmear(event=None)
1742            if self.current_smearer != None:
1743                self.current_smearer.set_accuracy(accuracy = 
1744                                                  self.smear2d_accuracy) 
1745        event.Skip()
1746
1747    def _on_fun_box(self,event):
1748        """
1749        Select an func: Erf,Rparabola,LParabola
1750        """
1751        fun_val = None
1752        fun_box = event.GetEventObject()
1753        name = fun_box.Name
1754        value = fun_box.GetValue()
1755        if self.model.fun_list.has_key(value):
1756            fun_val = self.model.fun_list[value]
1757
1758        self.model.setParam(name,fun_val)
1759        # save state
1760        self._copy_parameters_state(self.str_parameters, 
1761                                    self.state.str_parameters)
1762        # update params
1763        self._update_paramv_on_fit() 
1764        # draw
1765        self._draw_model()
1766        self.Refresh()
1767        # get ready for new event
1768        event.Skip()
1769       
1770    def _onMask(self, event):     
1771        """
1772        Build a panel to allow to edit Mask
1773        """
1774       
1775        from sans.guiframe.local_perspectives.plotting.masking \
1776        import MaskPanel as MaskDialog
1777       
1778        self.panel = MaskDialog(base=self, data=self.data, id=wx.NewId())
1779        #self.panel.Bind(wx.EVT_CLOSE, self._draw_masked_model)
1780        self.panel.ShowModal()
1781        #wx.PostEvent(self.parent, event)
1782       
1783    def _draw_masked_model(self, event):
1784        """
1785        Draw model image w/mask
1786        """
1787        #event.Skip()
1788        is_valid_qrange = self._update_paramv_on_fit()
1789
1790        if is_valid_qrange and self.model != None:
1791            #self.panel.Show(0)
1792            #self.panel.Destroy() # frame
1793            self.panel.MakeModal(False)
1794            event.Skip() 
1795            # try re draw the model plot if it exists
1796            self._draw_model()
1797            self.set_npts2fit()
1798        elif self.model == None:
1799            #self.panel.Show(0)
1800            #self.panel.Destroy() # frame
1801            self.panel.MakeModal(False)
1802            event.Skip()
1803            self.set_npts2fit()
1804            msg= "No model is found on updating MASK in the model plot... "
1805            wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
1806        else:
1807            event.Skip()
1808            msg = ' Please consider your Q range, too.'
1809            self.panel.ShowMessage(msg)
1810
1811       
1812    def _set_smear(self, data):
1813        """
1814        """
1815        if data is None:
1816            return
1817        self.current_smearer = smear_selection(data, self.model)
1818        flag =  self.disable_smearer.GetValue()
1819        self.disable_smearer.SetValue(flag)
1820        if self.current_smearer == None:
1821            self.enable_smearer.Disable()
1822        else:
1823            self.enable_smearer.Enable()
1824        if not flag:
1825            self.onSmear(None)
1826
1827    def _mac_sleep(self, sec=0.2):
1828        """
1829        Give sleep to MAC
1830        """
1831        if self.is_mac:
1832            time.sleep(sec)
1833
1834    def get_view_mode(self):
1835        """
1836        return True if the panel allow 2D or False if 1D
1837        """
1838        return self.enable2D
1839   
1840    def compute_data_set_range(self, data_list):
1841        """
1842        find the range that include all data  in the set
1843        return the minimum and the maximum values
1844        """
1845        if data_list is not None and data_list != []:
1846            for data in data_list:
1847                qmin, qmax, npts = self.compute_data_range(data)
1848                self.qmin_data_set = min(self.qmin_data_set, qmin)
1849                self.qmax_data_set = max(self.qmax_data_set, qmax)
1850                self.npts_data_set += npts
1851        return self.qmin_data_set, self.qmax_data_set, self.npts_data_set
1852       
1853    def compute_data_range(self, data):
1854        """
1855        compute the minimum and the maximum range of the data
1856        return the npts contains in data
1857        :param data:
1858        """
1859        qmin, qmax, npts = None, None, None
1860        if data is not None:
1861            if not hasattr(data,"data"):
1862                qmin = min(data.x)
1863                # Maximum value of data 
1864                qmax = max(data.x)
1865                npts = len(data.x)
1866            else:
1867                qmin = 0
1868                x = max(math.fabs(data.xmin), math.fabs(data.xmax)) 
1869                y = max(math.fabs(data.ymin), math.fabs(data.ymax))
1870                ## Maximum value of data 
1871                qmax = math.sqrt(x*x + y*y)
1872                npts = len(data.data)
1873        return qmin, qmax, npts
1874           
1875   
1876    def set_data(self, data):
1877        """
1878        reset the current data
1879        """
1880        from sans.guiframe.dataFitting import check_data_validity
1881        id = None
1882        flag = False
1883        is_data = False
1884        if self.data is not None:
1885            is_data = check_data_validity(self.data) 
1886        if not is_data and data is not None:
1887                flag = True
1888        if data is not None:
1889            id = data.id
1890            if is_data:
1891                self.graph_id = self.data.group_id
1892                flag = (data.id != self.data.id)
1893        self.data = data
1894        if check_data_validity(data):
1895            self.graph_id = data.group_id
1896        self.data.group_id = self.graph_id
1897       
1898        if self.data is None:
1899            data_name = ""
1900            self._set_bookmark_flag(False)
1901            self._keep.Enable(False)
1902            self._set_save_flag(False)
1903        else:
1904            if self.model != None:
1905                self._set_bookmark_flag(True)
1906                self._keep.Enable(True)
1907               
1908            self._set_save_flag(True)
1909            self._set_preview_flag(True)
1910
1911            self._set_smear(data)
1912            # more disables for 2D
1913            if self.data.__class__.__name__ ==  "Data2D" or \
1914                        self.enable2D:
1915                self.slit_smearer.Disable()
1916                self.pinhole_smearer.Enable(True) 
1917                self.default_mask = copy.deepcopy(self.data.mask)
1918                if self.data.err_data == None or\
1919                        (self.data.err_data == 1).all() or\
1920                        (self.data.err_data == 0).all():
1921                    self.dI_didata.Enable(False)
1922                    self.dI_noweight.SetValue(True)
1923                    self.weightbt_string = self.dI_noweight.GetLabelText()
1924                else:
1925                    self.dI_didata.Enable(True)
1926                    self.dI_didata.SetValue(True)
1927                    self.weightbt_string = self.dI_didata.GetLabelText()
1928            else:
1929                self.slit_smearer.Enable(True) 
1930                self.pinhole_smearer.Enable(True) 
1931                if self.data.dy == None or\
1932                     (self.data.dy == 1).all() or\
1933                     (self.data.dy == 0).all():
1934                    self.dI_didata.Enable(False)
1935                    self.dI_noweight.SetValue(True)
1936                    self.weightbt_string = self.dI_noweight.GetLabelText()
1937                else:
1938                    self.dI_didata.Enable(True)
1939                    self.dI_didata.SetValue(True)
1940                    self.weightbt_string = self.dI_didata.GetLabelText()
1941            # Enable weighting radio uttons     
1942            self.dI_noweight.Enable(True)   
1943            self.dI_sqrdata.Enable(True)
1944            self.dI_idata.Enable(True)
1945             
1946            self.formfactorbox.Enable()
1947            self.structurebox.Enable()
1948            data_name = self.data.name
1949            _, _, npts =  self.compute_data_range(self.data)
1950            #set maximum range for x in linear scale
1951            if not hasattr(self.data, "data"): #Display only for 1D data fit
1952                self.btEditMask.Disable() 
1953                self.EditMask_title.Disable()
1954            else:
1955                self.btEditMask.Enable() 
1956                self.EditMask_title.Enable() 
1957   
1958        self.Npts_total.SetValue(str(npts))
1959        #default:number of data points selected to fit
1960        self.Npts_fit.SetValue(str(npts))
1961        self.Npts_total.SetEditable(False)
1962        self.Npts_total.SetBackgroundColour(\
1963                                    self.GetParent().GetBackgroundColour())
1964       
1965        self.Npts_total.Bind(wx.EVT_MOUSE_EVENTS, self._npts_click)
1966        self.dataSource.SetValue(data_name)
1967        self.state.data = data
1968        self.enable_fit_button()
1969        # send graph_id to page_finder
1970        self._manager.set_graph_id(uid=self.uid, graph_id=self.graph_id)
1971        #focus the page
1972        if check_data_validity(data):
1973            self.data_box_description.SetForegroundColour(wx.BLUE)
1974       
1975        if self.batch_on:
1976            self.slit_smearer.Enable(False)
1977            self.pinhole_smearer.Enable(False)
1978            self.btEditMask.Disable() 
1979            self.EditMask_title.Disable()
1980
1981       
1982        self.on_set_focus(None)
1983        self.Refresh()
1984        #update model plot with new data information
1985        if flag:
1986            #set model view button
1987            if not self.enable_smearer.GetValue():
1988                    self.disable_smearer.SetValue(True)
1989            self.onSmear(None)
1990            #self._set_smear(self.data)
1991
1992            if self.data.__class__.__name__ == "Data2D":
1993                self.enable2D = True
1994                self.model_view.SetLabel("2D Mode")
1995            else:
1996                self.enable2D = False
1997                self.model_view.SetLabel("1D Mode")
1998            self.model_view.Disable()
1999            #replace data plot on combo box selection
2000            #by removing the previous selected data
2001            wx.PostEvent(self._manager.parent, NewPlotEvent(action="remove",
2002                                                    group_id=self.graph_id, id=id))
2003            #plot the current selected data
2004            wx.PostEvent(self._manager.parent, NewPlotEvent(plot=self.data, 
2005                                                title=str(self.data.title)))
2006            #self._manager.store_data(uid=self.uid, data_list=self.data_list,
2007            #                          caption=self.window_name)
2008            self._draw_model()
2009   
2010    def _npts_click(self, event):
2011        """
2012        Prevent further handling of the mouse event on Npts_total
2013        by not calling Skip().
2014        """ 
2015        pass
2016   
2017    def reset_page(self, state,first=False):
2018        """
2019        reset the state
2020        """
2021        self.reset_page_helper(state)
2022
2023        self.select_param(event = None) 
2024        #Save state_fit
2025        self.save_current_state_fit()
2026        self._lay_out()
2027        self.Refresh()
2028       
2029    def get_range(self):
2030        """
2031        return the fitting range
2032        """
2033        return float(self.qmin_x) , float(self.qmax_x)
2034   
2035    def get_npts2fit(self):
2036        """
2037        return numbers of data points within qrange
2038       
2039        :Note: This is for Park where chi2 is not normalized by Npts of fit
2040       
2041        """
2042        if self.data is None:
2043            return
2044        npts2fit = 0
2045        qmin,qmax = self.get_range()
2046        if self.data.__class__.__name__ == "Data2D" or \
2047                        self.enable2D:
2048            radius= numpy.sqrt( self.data.qx_data*self.data.qx_data + 
2049                                self.data.qy_data*self.data.qy_data )
2050            index_data = (self.qmin_x <= radius)&(radius<= self.qmax_x)
2051            index_data= (index_data)&(self.data.mask)
2052            index_data = (index_data)&(numpy.isfinite(self.data.data))
2053            npts2fit = len(self.data.data[index_data])
2054        else:
2055            for qx in self.data.x:
2056                   if qx >= qmin and qx <= qmax:
2057                       npts2fit += 1
2058        return npts2fit
2059
2060    def set_npts2fit(self):
2061        """
2062        setValue Npts for fitting
2063        """
2064        self.Npts_fit.SetValue(str(self.get_npts2fit()))
2065       
2066    def get_chi2(self):
2067        """
2068        return the current chi2
2069        """
2070        return self.tcChi.GetValue()
2071       
2072    def get_param_list(self):
2073        """
2074        :return self.param_toFit: list containing  references to TextCtrl
2075            checked.Theses TextCtrl will allow reference to parameters to fit.
2076       
2077        :raise: if return an empty list of parameter fit will nnote work
2078            properly so raise ValueError,"missing parameter to fit"
2079        """
2080        if self.param_toFit !=[]:
2081            return self.param_toFit
2082        else:
2083            msg = "missing parameters to fit" 
2084            wx.MessageBox(msg, 'warning')
2085            return False
2086            #raise ValueError,"missing parameters to fit"   
2087     
2088    def onsetValues(self, chisqr, p_name, out, cov):
2089        """
2090        Build the panel from the fit result
2091       
2092        :param chisqr: Value of the goodness of fit metric
2093        :param p_name: the name of parameters
2094        :param out: list of parameter with the best value found during fitting
2095        :param cov: Covariance matrix
2096   
2097        """
2098        # make sure stop button to fit button all the time
2099        self._on_fit_complete()
2100        if out == None or not numpy.isfinite(chisqr):
2101            raise ValueError,"Fit error occured..." 
2102       
2103        is_modified = False
2104        has_error = False 
2105        dispersity = ''   
2106       
2107        #Hide textctrl boxes of errors.
2108        self._clear_Err_on_Fit()   
2109       
2110        #Check if chi2 is finite
2111        if chisqr != None and numpy.isfinite(chisqr):
2112        #format chi2 
2113            if self.engine_type == "park": 
2114                npt_fit = float(self.get_npts2fit()) 
2115                # Taking care this in parkemgine
2116                #if npt_fit > 0:
2117                #    chisqr =chisqr/npt_fit   
2118            chi2 = format_number(chisqr, True)   
2119            self.tcChi.SetValue(chi2)   
2120            self.tcChi.Refresh()   
2121        else:
2122            self.tcChi.SetValue("-")
2123       
2124        #Hide error title
2125        if self.text2_3.IsShown() and not self.is_mac:
2126            self.text2_3.Hide()
2127     
2128        try:
2129            if self.enable_disp.GetValue():
2130                if hasattr(self,"text_disp_1" ):
2131                    if self.text_disp_1 != None and not self.is_mac:
2132                        self.text_disp_1.Hide()
2133        except:
2134            dispersity = None
2135            pass
2136     
2137           
2138        i = 0
2139        #Set the panel when fit result are list
2140        for item in self.param_toFit:     
2141            if len(item)>5 and item != None:     
2142                ## reset error value to initial state
2143                if not self.is_mac:
2144                    item[3].Hide()
2145                    item[4].Hide()
2146                for ind in range(len(out)):
2147                    if item[1] == p_name[ind]:
2148                        break       
2149                if len(out)<=len(self.param_toFit) and out[ind] !=None:   
2150                    val_out = format_number(out[ind], True)                 
2151                    item[2].SetValue(val_out)
2152
2153                if(cov !=None and len(cov) == len(out)):
2154                    try:
2155                        if dispersity !=None:
2156                            if self.enable_disp.GetValue():
2157                                if hasattr(self,"text_disp_1" ):
2158                                    if self.text_disp_1!=None:
2159                                        if not self.text_disp_1.IsShown()\
2160                                            and not self.is_mac:
2161                                            self.text_disp_1.Show(True)
2162                    except:
2163                        pass   
2164                   
2165                    if cov[ind]!=None :
2166                        if numpy.isfinite(float(cov[ind])):
2167                            val_err = format_number(cov[ind], True)
2168                            if not self.is_mac:
2169                                item[3].Show(True)
2170                                item[4].Show(True)
2171                            item[4].SetValue(val_err)
2172                            has_error = True
2173                i += 1         
2174        #Show error title when any errors displayed
2175        if has_error: 
2176            if not self.text2_3.IsShown():
2177                self.text2_3.Show(True)   
2178        ## save current state 
2179        self.save_current_state()         
2180       
2181        #self._lay_out()
2182        if not self.is_mac:
2183            self.Layout() 
2184            self.Refresh() 
2185        self._mac_sleep(0.1) 
2186        #plot model ( when drawing, do not update chisqr value again)
2187        self._draw_model(update_chisqr=False, source = 'fit')   
2188        #PostStatusEvent     
2189        #msg = "Fit completed!dddd "
2190        #wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
2191   
2192    def onWeighting(self, event):
2193        """
2194        On Weighting radio button event, sets the weightbt_string
2195        """
2196        self.weightbt_string = event.GetEventObject().GetLabelText()
2197        self._set_weight()
2198       
2199    def _set_weight(self, is_2D=None):
2200        """
2201        Set weight in fit problem
2202        """
2203        # compute weight for the current data
2204        from .utils import get_weight
2205        flag_weight = self.get_weight_flag()
2206        if is_2D == None:
2207            is_2D = self._is_2D()
2208        weight = get_weight(data=self.data, 
2209                            is2d=is_2D, 
2210                            flag=flag_weight)
2211        self._manager.set_fit_weight(uid=self.uid, 
2212                                     flag=flag_weight, 
2213                                     is2d=is_2D, 
2214                                     fid=None)
2215   
2216    def onPinholeSmear(self, event):
2217        """
2218        Create a custom pinhole smear object that will change the way residuals
2219        are compute when fitting
2220       
2221        :Note: accuracy is given by strings'High','Med', 'Low' FOR 2d,
2222                     None for 1D
2223                     
2224        """
2225        if self.model == None:
2226            self.disable_smearer.SetValue(True)
2227            if event == None:
2228                return
2229            msg="Please select a Model first..."
2230            wx.MessageBox(msg, 'Info')
2231            wx.PostEvent(self._manager.parent, StatusEvent(status=\
2232                            "Smear: %s"%msg))
2233            return
2234
2235        # Need update param values
2236        self._update_paramv_on_fit()     
2237
2238        # msg default
2239        msg = None
2240        if event != None:
2241            tcrtl= event.GetEventObject()
2242            # event case of radio button
2243            if tcrtl.GetValue()== True:
2244                self.dx_min = 0.0
2245                self.dx_max = 0.0
2246                is_new_pinhole = True
2247            else:
2248                is_new_pinhole = self._is_changed_pinhole()
2249        else:
2250            is_new_pinhole = True 
2251        # if any value is changed
2252        if is_new_pinhole:
2253            msg = self._set_pinhole_smear()
2254        # hide all silt sizer   
2255        self._hide_all_smear_info()
2256       
2257        ##Calculate chi2
2258        temp_smearer = self.current_smearer
2259        #self.compute_chisqr(smearer= temp_smearer)
2260           
2261        # show relevant slit sizers
2262        self._show_smear_sizer()
2263
2264        self.sizer_set_smearer.Layout()
2265        self.Layout()   
2266       
2267        if event != None: 
2268            event.Skip()                 
2269        #self._undo.Enable(True)
2270        self.save_current_state()
2271        event = PageInfoEvent(page = self)
2272        wx.PostEvent(self.parent, event)
2273       
2274    def _is_changed_pinhole(self): 
2275        """
2276        check if any of pinhole smear is changed
2277       
2278        :return: True or False
2279       
2280        """
2281        # get the values
2282        pin_min = self.smear_pinhole_min.GetValue()
2283        pin_max = self.smear_pinhole_max.GetValue()
2284                   
2285        # Check changes in slit width   
2286        try:
2287            dx_min = float(pin_min)
2288        except:
2289            return True
2290        if self.dx_min != dx_min:
2291            return True
2292       
2293        # Check changes in slit heigth
2294        try:
2295            dx_max = float(pin_max)
2296        except:
2297            return True
2298        if self.dx_max != dx_max:
2299            return True
2300        return False
2301   
2302    def _set_pinhole_smear(self):
2303        """
2304        Set custom pinhole smear
2305       
2306        :return: msg
2307       
2308        """
2309        # copy data
2310        data = copy.deepcopy(self.data)
2311        if self._is_2D():
2312            self.smear_type = 'Pinhole2d'
2313            len_data = len(data.data)
2314            data.dqx_data = numpy.zeros(len_data)
2315            data.dqy_data = numpy.zeros(len_data)
2316        else:
2317            self.smear_type = 'Pinhole'
2318            len_data = len(data.x)
2319            data.dx = numpy.zeros(len_data)
2320            data.dxl = None
2321            data.dxw = None
2322        msg = None
2323   
2324        get_pin_min = self.smear_pinhole_min
2325        get_pin_max = self.smear_pinhole_max       
2326
2327        if not check_float(get_pin_min):
2328            get_pin_min.SetBackgroundColour("pink")
2329            msg= "Model Error:wrong value entered!!!"
2330        elif not check_float(get_pin_max ):
2331            get_pin_max.SetBackgroundColour("pink")
2332            msg= "Model Error:wrong value entered!!!"
2333        else:
2334            if len_data < 2: len_data = 2     
2335            self.dx_min = float(get_pin_min.GetValue())
2336            self.dx_max = float(get_pin_max.GetValue())
2337            if self.dx_min < 0:
2338                get_pin_min.SetBackgroundColour("pink")
2339                msg= "Model Error:This value can not be negative!!!"
2340            elif self.dx_max <0:
2341                get_pin_max.SetBackgroundColour("pink")
2342                msg= "Model Error:This value can not be negative!!!"
2343            elif self.dx_min != None and self.dx_max != None:   
2344                if self._is_2D():
2345                    data.dqx_data[data.dqx_data==0] = self.dx_min
2346                    data.dqy_data[data.dqy_data==0] = self.dx_max         
2347                elif self.dx_min == self.dx_max:
2348                    data.dx[data.dx==0] = self.dx_min
2349                else:
2350                    step = (self.dx_max - self.dx_min)/(len_data-1)   
2351                    data.dx = numpy.arange(self.dx_min,self.dx_max+step/1.1,
2352                                           step)           
2353            elif self.dx_min != None: 
2354                if self._is_2D(): data.dqx_data[data.dqx_data==0] = self.dx_min
2355                else: data.dx[data.dx==0] = self.dx_min
2356            elif self.dx_max != None:
2357                if self._is_2D(): data.dqy_data[data.dqy_data==0] = self.dx_max
2358                else: data.dx[data.dx==0] = self.dx_max         
2359            self.current_smearer = smear_selection(data, self.model)
2360            # 2D need to set accuracy
2361            if self._is_2D(): 
2362                self.current_smearer.set_accuracy(accuracy = \
2363                                                  self.smear2d_accuracy)
2364
2365        if msg != None:
2366            wx.PostEvent(self._manager.parent, StatusEvent(status = msg ))
2367        else:
2368            get_pin_min.SetBackgroundColour("white")
2369            get_pin_max.SetBackgroundColour("white")
2370        ## set smearing value whether or not the data contain the smearing info
2371       
2372        self._manager.set_smearer(smearer=self.current_smearer,
2373                                fid=self.data.id,
2374                                 qmin=float(self.qmin_x),
2375                                 qmax= float(self.qmax_x),
2376                                 enable_smearer=not self.disable_smearer.GetValue(),
2377                                 uid=self.uid)
2378        return msg
2379       
2380    def update_pinhole_smear(self):
2381        """
2382        called by kill_focus on pinhole TextCntrl
2383        to update the changes
2384       
2385        :return: False when wrong value was entered
2386       
2387        """
2388        # msg default
2389        msg = None
2390        # check if any value is changed
2391        if self._is_changed_pinhole():
2392            msg = self._set_pinhole_smear()           
2393        #self._undo.Enable(True)
2394        wx.CallAfter(self.save_current_state)
2395
2396        if msg != None:
2397            return False   
2398        else:
2399            return True
2400                     
2401    def onSlitSmear(self, event):
2402        """
2403        Create a custom slit smear object that will change the way residuals
2404        are compute when fitting
2405        """
2406        if self.model == None:
2407            self.disable_smearer.SetValue(True)
2408            if event == None:
2409                return
2410            msg="Please select a Model first..."
2411            wx.MessageBox(msg, 'Info')
2412            wx.PostEvent(self._manager.parent, StatusEvent(status=\
2413                            "Smear: %s"%msg))
2414            return
2415
2416        # Need update param values
2417        self._update_paramv_on_fit()
2418
2419        # msg default
2420        msg = None
2421        # for event given
2422        if event != None:
2423            tcrtl= event.GetEventObject()
2424            # event case of radio button
2425            if tcrtl.GetValue():
2426                self.dxl = 0.0
2427                self.dxw = 0.0
2428                is_new_slit = True
2429            else:
2430                is_new_slit = self._is_changed_slit()
2431        else:
2432            is_new_slit = True 
2433       
2434        # if any value is changed
2435        if is_new_slit:
2436            msg = self._set_slit_smear()
2437           
2438        # hide all silt sizer
2439        self._hide_all_smear_info()       
2440        ##Calculate chi2
2441        #self.compute_chisqr(smearer= self.current_smearer) 
2442        # show relevant slit sizers       
2443        self._show_smear_sizer()
2444        self.sizer_set_smearer.Layout()
2445        self.Layout()
2446
2447        if event != None:
2448            event.Skip()     
2449        #self._undo.Enable(True)
2450        self.save_current_state()
2451        event = PageInfoEvent(page = self)
2452        wx.PostEvent(self.parent, event)
2453        if msg != None:
2454            wx.PostEvent(self._manager.parent, StatusEvent(status = msg))
2455
2456    def _is_changed_slit(self): 
2457        """
2458        check if any of slit lengths is changed
2459       
2460        :return: True or False
2461       
2462        """
2463        # get the values
2464        width = self.smear_slit_width.GetValue()
2465        height = self.smear_slit_height.GetValue()
2466       
2467        # check and change the box bg color if it was pink
2468        #    but it should be white now
2469        # because this is the case that _set_slit_smear() will not handle
2470        if height.lstrip().rstrip()=="":
2471            self.smear_slit_height.SetBackgroundColour(wx.WHITE)
2472        if width.lstrip().rstrip()=="":
2473            self.smear_slit_width.SetBackgroundColour(wx.WHITE)
2474           
2475        # Check changes in slit width   
2476        if width == "": 
2477            dxw = 0.0
2478        else:
2479            try:
2480                dxw = float(width)
2481            except:
2482                return True
2483        if self.dxw != dxw:
2484            return True
2485       
2486        # Check changes in slit heigth
2487        if height == "": 
2488            dxl = 0.0
2489        else:
2490            try:
2491                dxl = float(height)
2492            except:
2493                return True
2494        if self.dxl != dxl:
2495            return True
2496
2497        return False
2498   
2499    def _set_slit_smear(self):
2500        """
2501        Set custom slit smear
2502       
2503        :return: message to inform the user about the validity
2504            of the values entered for slit smear
2505        """
2506        if self.data.__class__.__name__ ==  "Data2D" or \
2507                        self.enable2D:
2508            return
2509        temp_smearer = None
2510        # make sure once more if it is smearer
2511        data = copy.deepcopy(self.data)
2512        data_len = len(data.x)
2513        data.dx = None
2514        data.dxl = None
2515        data.dxw = None
2516        msg = None
2517   
2518        try:
2519            self.dxl = float(self.smear_slit_height.GetValue())
2520            data.dxl = self.dxl* numpy.ones(data_len)
2521            self.smear_slit_height.SetBackgroundColour(wx.WHITE)
2522        except: 
2523            data.dxl = numpy.zeros(data_len)
2524            if self.smear_slit_height.GetValue().lstrip().rstrip()!="":
2525                self.smear_slit_height.SetBackgroundColour("pink")
2526                msg = "Wrong value entered... " 
2527            else:
2528                self.smear_slit_height.SetBackgroundColour(wx.WHITE)
2529        try:
2530            self.dxw = float(self.smear_slit_width.GetValue())
2531            self.smear_slit_width.SetBackgroundColour(wx.WHITE)
2532            data.dxw = self.dxw* numpy.ones(data_len)
2533        except: 
2534            data.dxw = numpy.zeros(data_len)
2535            if self.smear_slit_width.GetValue().lstrip().rstrip()!="":
2536                self.smear_slit_width.SetBackgroundColour("pink")
2537                msg = "Wrong Fit value entered... "
2538            else:
2539                self.smear_slit_width.SetBackgroundColour(wx.WHITE)
2540             
2541        self.current_smearer = smear_selection(data, self.model)
2542        #temp_smearer = self.current_smearer
2543        ## set smearing value whether or not the data contain the smearing info
2544        self._manager.set_smearer(smearer=self.current_smearer, 
2545                                 fid=self.data.id,
2546                                 qmin=float(self.qmin_x), 
2547                                 qmax= float(self.qmax_x),
2548                        enable_smearer=not self.disable_smearer.GetValue(),
2549                                 uid=self.uid) 
2550        return msg
2551   
2552    def update_slit_smear(self):
2553        """
2554        called by kill_focus on pinhole TextCntrl
2555        to update the changes
2556       
2557        :return: False when wrong value was entered
2558       
2559        """             
2560        # msg default
2561        msg = None
2562        # check if any value is changed
2563        if self._is_changed_slit():
2564            msg = self._set_slit_smear()           
2565        #self._undo.Enable(True)
2566        self.save_current_state()
2567
2568        if msg != None:
2569            return False   
2570        else:
2571            return True
2572                           
2573    def onSmear(self, event):
2574        """
2575        Create a smear object that will change the way residuals
2576        are compute when fitting
2577        """
2578        if event != None: 
2579            event.Skip()   
2580        if self.data is None:
2581            return
2582
2583        if self.model == None:
2584            self.disable_smearer.SetValue(True)
2585            if event == None:
2586                return
2587            msg="Please select a Model first..."
2588            wx.MessageBox(msg, 'Info')
2589            wx.PostEvent(self._manager.parent, StatusEvent(status=\
2590                            "Smear: %s"%msg))
2591            return
2592        # Need update param values
2593        self._update_paramv_on_fit()
2594        temp_smearer = self.on_smear_helper()           
2595       
2596        self.sizer_set_smearer.Layout()
2597        self.Layout()
2598        self._set_weight()
2599       
2600        ## set smearing value whether or not the data contain the smearing info
2601        wx.CallAfter(self._manager.set_smearer, uid=self.uid, smearer=temp_smearer,
2602                                  fid=self.data.id,
2603                        qmin=float(self.qmin_x),
2604                        qmax=float(self.qmax_x),
2605                        enable_smearer=not self.disable_smearer.GetValue(),
2606                         draw=True) 
2607       
2608        self.state.enable_smearer=  self.enable_smearer.GetValue()
2609        self.state.disable_smearer=self.disable_smearer.GetValue()
2610        self.state.pinhole_smearer = self.pinhole_smearer.GetValue()
2611        self.state.slit_smearer = self.slit_smearer.GetValue()
2612       
2613    def on_smear_helper(self, update=False):
2614        """
2615        Help for onSmear
2616       
2617        :param update: force or not to update
2618        """
2619        self._get_smear_info()
2620        temp_smearer = None
2621        #renew smear sizer
2622        if self.smear_type != None:
2623            self.smear_description_smear_type.SetValue(str(self.smear_type))
2624            self.smear_data_left.SetValue(str(self.dq_l))   
2625            self.smear_data_right.SetValue(str(self.dq_r)) 
2626
2627        self._hide_all_smear_info()
2628        data = copy.deepcopy(self.data)
2629       
2630        # make sure once more if it is smearer
2631        temp_smearer = smear_selection(data, self.model)
2632        if self.current_smearer != temp_smearer or update:
2633            self.current_smearer = temp_smearer
2634        if self.enable_smearer.GetValue():
2635            if hasattr(self.data,"dxl"):
2636                msg= ": Resolution smearing parameters"
2637            if hasattr(self.data,"dxw"):
2638                msg= ": Slit smearing parameters"
2639            if self.current_smearer ==None:
2640                wx.PostEvent(self._manager.parent, StatusEvent(status=\
2641                            "Data contains no smearing information"))
2642            else:
2643                wx.PostEvent(self._manager.parent, StatusEvent(status=\
2644                            "Data contains smearing information"))
2645
2646            #self.smear_description_dqdata.Show(True)
2647            self.smear_data_left.Show(True)
2648            self.smear_data_right.Show(True)
2649            temp_smearer= self.current_smearer
2650        elif self.disable_smearer.GetValue():
2651            self.smear_description_none.Show(True)
2652        elif self.pinhole_smearer.GetValue():
2653            self.onPinholeSmear(None)
2654        elif self.slit_smearer.GetValue():
2655            self.onSlitSmear(None)
2656        self._show_smear_sizer()
2657       
2658        return temp_smearer
2659   
2660    def on_complete_chisqr(self, event): 
2661        """
2662        Display result chisqr on the panel
2663        :event: activated by fitting/ complete after draw
2664        """
2665        try:
2666            if event == None:
2667                output= "-"
2668            elif not numpy.isfinite(event.output):
2669                output= "-"
2670            else:
2671                output = event.output
2672            self.tcChi.SetValue(str(format_number(output, True)))
2673            self.state.tcChi = self.tcChi.GetValue()
2674        except:
2675            pass 
2676           
2677   
2678    def get_all_checked_params(self):
2679        """
2680        Found all parameters current check and add them to list of parameters to
2681        fit
2682        """
2683        self.param_toFit = []
2684        for item in self.parameters:
2685            if item[0].GetValue() and item not in self.param_toFit:
2686                self.param_toFit.append(item)
2687        for item in self.fittable_param:
2688            if item[0].GetValue() and item not in self.param_toFit:
2689                self.param_toFit.append(item)
2690        self.save_current_state_fit() 
2691       
2692     
2693        event = PageInfoEvent(page = self)
2694        wx.PostEvent(self.parent, event) 
2695        param2fit = []
2696        for item in self.param_toFit:
2697            if item[0]:
2698                param2fit.append(item[1])     
2699        self.parent._manager.set_param2fit(self.uid, param2fit)
2700               
2701    def select_all_param(self, event): 
2702        """
2703        set to true or false all checkBox given the main checkbox value cb1
2704        """           
2705        self.param_toFit = []
2706        if  self.parameters !=[]:
2707            if  self.cb1.GetValue():
2708                for item in self.parameters:
2709                    ## for data2D select all to fit
2710                    if self.data.__class__.__name__==  "Data2D" or \
2711                            self.enable2D:
2712                        item[0].SetValue(True)
2713                        self.param_toFit.append(item)
2714                    else:
2715                        ## for 1D all parameters except orientation
2716                        if not item in self.orientation_params:
2717                            item[0].SetValue(True)
2718                            self.param_toFit.append(item )
2719                #if len(self.fittable_param)>0:
2720                for item in self.fittable_param:
2721                    if self.data.__class__.__name__== "Data2D" or \
2722                            self.enable2D:
2723                        item[0].SetValue(True)
2724                        self.param_toFit.append(item)
2725                        try:
2726                            if len(self.values[item[1]]) > 0:
2727                                item[0].SetValue(False)
2728                        except:
2729                            pass
2730
2731                    else:
2732                        ## for 1D all parameters except orientation
2733                        if not item in self.orientation_params_disp:
2734                            item[0].SetValue(True)
2735                            self.param_toFit.append(item )
2736                            try:
2737                                if len(self.values[item[1]]) > 0:
2738                                    item[0].SetValue(False)
2739                            except:
2740                                pass
2741
2742            else:
2743                for item in self.parameters:
2744                    item[0].SetValue(False)
2745                for item in self.fittable_param:
2746                    item[0].SetValue(False)
2747                self.param_toFit=[]
2748           
2749        self.save_current_state_fit() 
2750       
2751        if event !=None:
2752            #self._undo.Enable(True)
2753            ## post state to fit panel
2754            event = PageInfoEvent(page = self)
2755            wx.PostEvent(self.parent, event) 
2756        param2fit = []
2757        for item in self.param_toFit:
2758            if item[0]:
2759                param2fit.append(item[1])     
2760        self.parent._manager.set_param2fit(self.uid, param2fit)
2761
2762       
2763    def select_param(self,event):
2764        """
2765        Select TextCtrl  checked for fitting purpose and stores them
2766        in  self.param_toFit=[] list
2767        """
2768        self.param_toFit = []
2769        for item in self.parameters:
2770            #Skip t ifhe angle parameters if 1D data
2771            if self.data.__class__.__name__ != "Data2D" and\
2772                        not self.enable2D:
2773                if item in self.orientation_params:
2774                    continue
2775            #Select parameters to fit for list of primary parameters
2776            if item[0].GetValue():
2777                if not (item in self.param_toFit):
2778                    self.param_toFit.append(item ) 
2779            else:
2780                #remove parameters from the fitting list
2781                if item in self.param_toFit:
2782                    self.param_toFit.remove(item)
2783
2784        #Select parameters to fit for list of fittable parameters
2785        #        with dispersion         
2786        for item in self.fittable_param:
2787            #Skip t ifhe angle parameters if 1D data
2788            if self.data.__class__.__name__ !=  "Data2D" and\
2789                        not self.enable2D:
2790                if item in self.orientation_params:
2791                    continue
2792            if item[0].GetValue():
2793                if not (item in self.param_toFit):
2794                    self.param_toFit.append(item) 
2795            else:
2796                #remove parameters from the fitting list
2797                if item in self.param_toFit:
2798                    self.param_toFit.remove(item)
2799
2800        #Calculate num. of angle parameters
2801        if self.data.__class__.__name__ ==  "Data2D" or \
2802                       self.enable2D:
2803            len_orient_para = 0
2804        else:
2805            len_orient_para = len(self.orientation_params)  #assume even len
2806        #Total num. of angle parameters
2807        if len(self.fittable_param) > 0:
2808            len_orient_para *= 2
2809        #Set the value of checkbox that selected every checkbox or not       
2810        if len(self.parameters)+len(self.fittable_param)-len_orient_para ==\
2811                len(self.param_toFit):
2812            self.cb1.SetValue(True)
2813        else:
2814            self.cb1.SetValue(False)
2815       
2816       
2817       
2818        self.save_current_state_fit()
2819        if event !=None:
2820            #self._undo.Enable(True)
2821            ## post state to fit panel
2822            event = PageInfoEvent(page = self)
2823            wx.PostEvent(self.parent, event) 
2824       
2825        param2fit = []
2826        for item in self.param_toFit:
2827            if item[0]:
2828                param2fit.append(item[1])     
2829        self.parent._manager.set_param2fit(self.uid, param2fit)
2830       
2831    def set_model_param_sizer(self, model):
2832        """
2833        Build the panel from the model content
2834       
2835        :param model: the model selected in combo box for fitting purpose
2836       
2837        """
2838        self.sizer3.Clear(True)
2839        self.parameters = []
2840        self.str_parameters = []
2841        self.param_toFit=[]
2842        self.fittable_param=[]
2843        self.fixed_param=[]
2844        self.orientation_params=[]
2845        self.orientation_params_disp=[]
2846       
2847        if model ==None:
2848            self.sizer3.Layout()
2849            self.SetupScrolling()
2850            return
2851        ## the panel is drawn using the current value of the fit engine
2852        if self.engine_type==None and self._manager !=None:
2853            self.engine_type= self._manager._return_engine_type()
2854
2855        box_description= wx.StaticBox(self, -1,str("Model Parameters"))
2856        boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
2857        sizer = wx.GridBagSizer(5,5)
2858        ## save the current model
2859        self.model = model
2860           
2861        keys = self.model.getParamList()
2862        #list of dispersion paramaters
2863        self.disp_list=self.model.getDispParamList()
2864
2865        def custom_compare(a,b):
2866            """
2867            Custom compare to order, first by alphabets then second by number.
2868            """ 
2869            # number at the last digit
2870            a_last = a[len(a)-1]
2871            b_last = b[len(b)-1]
2872            # default
2873            num_a = None
2874            num_b = None
2875            # split the names
2876            a2 = a.lower().split('_')
2877            b2 = b.lower().split('_')
2878            # check length of a2, b2
2879            len_a2 = len(a2)
2880            len_b2 = len(b2)
2881            # check if it contains a int number(<10)
2882            try: 
2883                num_a = int(a_last)
2884            except: pass
2885            try:
2886                num_b = int(b_last)
2887            except: pass
2888            # Put 'scale' near the top; happens
2889            # when numbered param name exists
2890            if a == 'scale':
2891                return -1
2892            # both have a number   
2893            if num_a != None and num_b != None:
2894                if num_a > num_b: return -1
2895                # same number
2896                elif num_a == num_b: 
2897                    # different last names
2898                    if a2[len_a2-1] != b2[len_b2-1] and num_a != 0:
2899                        return -cmp(a2[len_a2-1], b2[len_b2-1])
2900                    else: 
2901                        return cmp(a, b) 
2902                else: return 1
2903            # one of them has a number
2904            elif num_a != None: return 1
2905            elif num_b != None: return -1
2906            # no numbers
2907            else: return cmp(a.lower(), b.lower())
2908
2909                       
2910        keys.sort(custom_compare)
2911   
2912        iy = 0
2913        ix = 0
2914        select_text = "Select All"
2915        self.cb1 = wx.CheckBox(self, -1,str(select_text), (10, 10))
2916        wx.EVT_CHECKBOX(self, self.cb1.GetId(), self.select_all_param)
2917        self.cb1.SetToolTipString("To check/uncheck all the boxes below.")
2918        self.cb1.SetValue(True)
2919       
2920        sizer.Add(self.cb1,(iy, ix),(1,1),\
2921                             wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 5)
2922        ix +=1
2923        self.text2_2 = wx.StaticText(self, -1, 'Value')
2924        sizer.Add(self.text2_2,(iy, ix),(1,1),\
2925                            wx.EXPAND|wx.ADJUST_MINSIZE, 0)
2926        ix +=2 
2927        self.text2_3 = wx.StaticText(self, -1, 'Error')
2928        sizer.Add(self.text2_3,(iy, ix),(1,1),\
2929                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
2930        if not self.is_mac:
2931            self.text2_3.Hide()
2932        ix +=1 
2933        self.text2_min = wx.StaticText(self, -1, 'Min')
2934        sizer.Add(self.text2_min,(iy, ix),(1,1),\
2935                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
2936        #self.text2_min.Hide()
2937        ix +=1 
2938        self.text2_max = wx.StaticText(self, -1, 'Max')
2939        sizer.Add(self.text2_max,(iy, ix),(1,1),\
2940                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
2941        #self.text2_max.Hide()
2942        ix += 1
2943        self.text2_4 = wx.StaticText(self, -1, '[Units]')
2944        sizer.Add(self.text2_4,(iy, ix),(1,1),\
2945                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
2946        self.text2_4.Hide()
2947       
2948        CHECK_STATE = self.cb1.GetValue()
2949        for item in keys:
2950            if not item in self.disp_list and not item in \
2951                    self.model.orientation_params:
2952               
2953                ##prepare a spot to store errors
2954                if not self.model.details.has_key(item):
2955                    self.model.details [item] = ["",None,None] 
2956         
2957                iy += 1
2958                ix = 0
2959                if (self.model.__class__ in \
2960                    self.model_list_box["Multi-Functions"] or \
2961                    self.temp_multi_functional)\
2962                    and (item in self.model.non_fittable):
2963                    non_fittable_name = wx.StaticText(self, -1, item )
2964                    sizer.Add(non_fittable_name,(iy, ix),(1,1),\
2965                            wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 21)
2966                    ## add parameter value
2967                    ix += 1
2968                    value= self.model.getParam(item)
2969                    if len(self.model.fun_list) > 0:
2970                        num = item.split('_')[1][5:7]
2971                        fun_box = wx.ComboBox(self, -1,size=(100,-1),
2972                                    style=wx.CB_READONLY, name = '%s'% item)
2973                        self._set_fun_box_list(fun_box)
2974                        fun_box.SetSelection(0)
2975                        #self.fun_box.SetToolTipString("A function
2976                        #    describing the interface")
2977                        wx.EVT_COMBOBOX(fun_box,-1, self._on_fun_box)
2978                    else:
2979                        fun_box = self.ModelTextCtrl(self, -1, 
2980                                                     size=(_BOX_WIDTH,20),
2981                                style=wx.TE_PROCESS_ENTER, name ='%s'% item)
2982                        fun_box.SetToolTipString(\
2983                                "Hit 'Enter' after typing to update the plot.")
2984                        fun_box.SetValue(format_number(value, True))
2985                    sizer.Add(fun_box, (iy,ix),(1,1), wx.EXPAND)
2986                    self.str_parameters.append([None,item, fun_box,
2987                                                None, None, None, 
2988                                                None, None])
2989
2990                   
2991                else:
2992                    ## add parameters name with checkbox for selecting to fit
2993                    cb = wx.CheckBox(self, -1, item) 
2994                    cb.SetValue(CHECK_STATE)           
2995                    cb.SetToolTipString(" Check mark to fit.")
2996                    #cb.SetValue(True)
2997                    wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
2998                   
2999                    sizer.Add( cb,( iy, ix),(1,1),
3000                                 wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 5)
3001
3002                    ## add parameter value
3003                    ix += 1
3004                    value= self.model.getParam(item)
3005                    ctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH,20),
3006                                        style=wx.TE_PROCESS_ENTER)
3007                    ctl1.SetToolTipString(\
3008                                "Hit 'Enter' after typing to update the plot.")
3009                    ctl1.SetValue(format_number(value, True))
3010                    sizer.Add(ctl1, (iy,ix),(1,1), wx.EXPAND)
3011                    ## text to show error sign
3012                    ix += 1
3013                    text2=wx.StaticText(self, -1, '+/-')
3014                    sizer.Add(text2,(iy, ix),(1,1),\
3015                                    wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
3016                    if not self.is_mac:
3017                        text2.Hide() 
3018                    ix += 1
3019                    ctl2 = wx.TextCtrl(self, -1, size=(_BOX_WIDTH/1.2,20), style=0)
3020                    sizer.Add(ctl2, (iy,ix),(1,1), 
3021                              wx.EXPAND|wx.ADJUST_MINSIZE, 0)
3022                    if not self.is_mac:
3023                        ctl2.Hide()
3024                   
3025                    ix += 1
3026                    ctl3 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/1.9,20),
3027                                               style=wx.TE_PROCESS_ENTER,
3028                                text_enter_callback = self._onparamRangeEnter)
3029         
3030                    sizer.Add(ctl3, (iy,ix),(1,1), 
3031                              wx.EXPAND|wx.ADJUST_MINSIZE, 0)
3032           
3033                    ix += 1
3034                    ctl4 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/1.9,20),
3035                                               style=wx.TE_PROCESS_ENTER,
3036                                text_enter_callback = self._onparamRangeEnter)
3037                    sizer.Add(ctl4, (iy,ix),(1,1), 
3038                              wx.EXPAND|wx.FIXED_MINSIZE, 0)
3039   
3040                    ix +=1
3041                    # Units
3042                    if self.model.details.has_key(item):
3043                        units = wx.StaticText(self, -1, 
3044                            self.model.details[item][0], style=wx.ALIGN_LEFT)
3045                    else:
3046                        units = wx.StaticText(self, -1, "", style=wx.ALIGN_LEFT)
3047                    sizer.Add(units, (iy,ix),(1,1), 
3048                               wx.EXPAND|wx.ADJUST_MINSIZE, 0)
3049                       
3050                    ##[cb state, name, value, "+/-", error of fit, min, max , units]
3051                    self.parameters.append([cb,item, ctl1,
3052                                            text2,ctl2, ctl3, ctl4,units])
3053                                 
3054        iy+=1
3055        sizer.Add((10,10),(iy,ix),(1,1), 
3056                  wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
3057       
3058        # type can be either Guassian or Array
3059        if len(self.model.dispersion.values())>0:
3060            type= self.model.dispersion.values()[0]["type"]
3061        else:
3062            type = "Gaussian"
3063           
3064        iy += 1
3065        ix = 0
3066        #Add tile for orientational angle
3067        for item in keys:
3068            if item in self.model.orientation_params:       
3069                orient_angle = wx.StaticText(self, -1, '[For 2D only]:')
3070                sizer.Add(orient_angle,(iy, ix),(1,1), 
3071                          wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15) 
3072                if not self.data.__class__.__name__ == "Data2D" and \
3073                        not self.enable2D:
3074                    orient_angle.Hide()
3075                else:
3076                    orient_angle.Show(True)
3077                break
3078     
3079        #For Gaussian only
3080        if type.lower() != "array":
3081            for item in self.model.orientation_params:
3082                if not item in self.disp_list:
3083                    ##prepare a spot to store min max
3084                    if not self.model.details.has_key(item):
3085                        self.model.details [item] = ["",None,None] 
3086                         
3087                    iy += 1
3088                    ix = 0
3089                    ## add parameters name with checkbox for selecting to fit
3090                    cb = wx.CheckBox(self, -1, item )
3091                    cb.SetValue(CHECK_STATE)
3092                    cb.SetToolTipString("Check mark to fit")
3093                    wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
3094                    if self.data.__class__.__name__ == "Data2D" or \
3095                            self.enable2D:
3096                        cb.Show(True)
3097                    else:
3098                        cb.Hide()
3099                    sizer.Add( cb,( iy, ix),(1,1),
3100                                 wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 5)
3101   
3102                    ## add parameter value
3103                    ix += 1
3104                    value= self.model.getParam(item)
3105                    ctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH,20),
3106                                        style=wx.TE_PROCESS_ENTER)
3107                    ctl1.SetToolTipString(\
3108                                "Hit 'Enter' after typing to update the plot.")
3109                    ctl1.SetValue(format_number(value, True))
3110                    if self.data.__class__.__name__ == "Data2D" or \
3111                            self.enable2D:
3112                        ctl1.Show(True)
3113                    else:
3114                        ctl1.Hide()
3115                    sizer.Add(ctl1, (iy,ix),(1,1), wx.EXPAND)
3116                    ## text to show error sign
3117                    ix += 1
3118                    text2=wx.StaticText(self, -1, '+/-')
3119                    sizer.Add(text2,(iy, ix),(1,1),\
3120                                    wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
3121
3122                    text2.Hide() 
3123                    ix += 1
3124                    ctl2 = wx.TextCtrl(self, -1, size=(_BOX_WIDTH/1.2,20), style=0)
3125                    sizer.Add(ctl2, (iy,ix),(1,1), 
3126                              wx.EXPAND|wx.ADJUST_MINSIZE, 0)
3127
3128                    ctl2.Hide()
3129                   
3130                   
3131                    ix += 1
3132                    ctl3 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/1.8,20), 
3133                                              style=wx.TE_PROCESS_ENTER,
3134                                text_enter_callback = self._onparamRangeEnter)
3135                   
3136                    sizer.Add(ctl3, (iy,ix),(1,1), 
3137                              wx.EXPAND|wx.ADJUST_MINSIZE, 0)
3138                    ctl3.Hide()
3139                 
3140                    ix += 1
3141                    ctl4 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH/1.8,20),
3142                                               style=wx.TE_PROCESS_ENTER,
3143                            text_enter_callback = self._onparamRangeEnter)
3144                    sizer.Add(ctl4, (iy,ix),(1,1), 
3145                              wx.EXPAND|wx.ADJUST_MINSIZE, 0)
3146                   
3147                    ctl4.Hide()
3148                   
3149                    if self.data.__class__.__name__ == "Data2D" or \
3150                            self.enable2D: 
3151                        if self.is_mac: 
3152                            text2.Show(True)
3153                            ctl2.Show(True)                 
3154                        ctl3.Show(True)
3155                        ctl4.Show(True)
3156                   
3157                    ix +=1
3158                    # Units
3159                    if self.model.details.has_key(item):
3160                        units = wx.StaticText(self, -1, 
3161                                              self.model.details[item][0], 
3162                                              style=wx.ALIGN_LEFT)
3163                    else:
3164                        units = wx.StaticText(self, -1, "", style=wx.ALIGN_LEFT)
3165                    if self.data.__class__.__name__ == "Data2D" or \
3166                            self.enable2D:
3167                        units.Show(True)
3168                   
3169                    else:
3170                        units.Hide()
3171                   
3172                    sizer.Add(units, (iy,ix),(1,1), 
3173                              wx.EXPAND|wx.ADJUST_MINSIZE, 0)
3174                                         
3175                    ##[cb state, name, value, "+/-", error of fit,min,max,units]
3176                    self.parameters.append([cb,item, ctl1,
3177                                            text2,ctl2, ctl3, ctl4,units])
3178                    self.orientation_params.append([cb,item, ctl1,
3179                                            text2,ctl2, ctl3, ctl4,units])
3180             
3181        iy+=1
3182       
3183        #Display units text on panel
3184        for item in keys:   
3185            if self.model.details.has_key(item):
3186                self.text2_4.Show()
3187        #Fill the list of fittable parameters
3188        self.get_all_checked_params()
3189        self.save_current_state_fit()
3190        boxsizer1.Add(sizer)
3191        self.sizer3.Add(boxsizer1,0, wx.EXPAND | wx.ALL, 10)
3192        self.sizer3.Layout()
3193        self.Layout()
3194        #self.Refresh()
3195
3196    def on_right_down(self, event):
3197        """
3198        Get key stroke event
3199        """
3200        if self.data == None:
3201            return
3202        # Figuring out key combo: Cmd for copy, Alt for paste
3203        if event.AltDown() and event.ShiftDown():
3204            self._manager.show_ftol_dialog()
3205            flag = True
3206        elif event.AltDown() or event.ShiftDown():
3207            flag = False
3208        else:
3209            return
3210        # make event free
3211        event.Skip()
3212        # messages depending on the flag
3213        if not flag:
3214            msg = " Could not open ftol dialog;"
3215            msg += " Check if the Scipy fit engine is selected in the menubar."
3216            infor = 'warning'
3217            # inform msg to wx
3218            wx.PostEvent( self.parent.parent, 
3219                          StatusEvent(status= msg, info=infor))
3220
3221       
3222    def _onModel2D(self, event):
3223        """
3224        toggle view of model from 1D to 2D  or 2D from 1D
3225        """
3226        if self.model_view.GetLabelText() == "Show 2D":
3227            self.model_view.SetLabel("Show 1D")
3228            self.enable2D = True
3229             
3230        else:
3231            self.model_view.SetLabel("Show 2D")
3232            self.enable2D = False
3233        self.Show(False)
3234        self.create_default_data()
3235        self._manager.store_data(self.uid, data_list=[self.data])
3236
3237        self.set_model_param_sizer(self.model)
3238        self._set_sizer_dispersion() 
3239        self._set_weight(is_2D= self.enable2D)
3240        self._set_smear_buttons()
3241        self.Show(True)
3242        self.SetupScrolling()
3243        self._draw_model()
3244       
3245        self.state.enable2D =  copy.deepcopy(self.enable2D)
3246   
3247    def _set_smear_buttons(self):
3248        """
3249        Set semarer radio buttons
3250        """
3251        # more disables for 2D
3252        if self.data.__class__.__name__ ==  "Data2D" or \
3253                    self.enable2D:
3254            self.slit_smearer.Disable()
3255            self.pinhole_smearer.Enable(True) 
3256            self.default_mask = copy.deepcopy(self.data.mask)
3257        else:
3258            self.slit_smearer.Enable(True) 
3259            self.pinhole_smearer.Enable(True) 
3260           
3261           
3262class BGTextCtrl(wx.TextCtrl):
3263    """
3264    Text control used to display outputs.
3265    No editing allowed. The background is
3266    grayed out. User can't select text.
3267    """
3268    def __init__(self, *args, **kwds):
3269        wx.TextCtrl.__init__(self, *args, **kwds)
3270        self.SetEditable(False)
3271        self.SetBackgroundColour(self.GetParent().parent.GetBackgroundColour())
3272       
3273        # Bind to mouse event to avoid text highlighting
3274        # The event will be skipped once the call-back
3275        # is called.
3276        self.Bind(wx.EVT_MOUSE_EVENTS, self._click)
3277       
3278    def _click(self, event):
3279        """
3280        Prevent further handling of the mouse event
3281        by not calling Skip().
3282        """ 
3283        pass
3284 
Note: See TracBrowser for help on using the repository browser.