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

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 e1bc51d was 48f4467, checked in by Jae Cho <jhjcho@…>, 13 years ago

more fix on stop button

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