source: sasview/src/sas/perspectives/fitting/fitpage.py @ 0e4e554

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 0e4e554 was 0e4e554, checked in by ajj, 9 years ago

start switching to sasmodels including dispersion

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