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

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 67dd757 was ae4c139, checked in by Jae Cho <jhjcho@…>, 12 years ago

fixed a little bit of error msg

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