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

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 c4f6851 was 2f4b430, checked in by Doucet, Mathieu <doucetm@…>, 10 years ago

Take care of white spaces (pylint)

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