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

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 56acb5d was ac2b835, checked in by Mathieu Doucet <doucetm@…>, 13 years ago

Pep-8-ification

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