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

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

Re #216 Merging wx30 branch

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