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

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

category stuffs start working in interp. environment

  • Property mode set to 100644
File size: 128.7 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        self.reset_page_helper(state)
1892
1893        self.select_param(event=None)
1894        #Save state_fit
1895        self.save_current_state_fit()
1896        self._lay_out()
1897        self.Refresh()
1898       
1899    def get_range(self):
1900        """
1901        return the fitting range
1902        """
1903        return float(self.qmin_x), float(self.qmax_x)
1904   
1905    def get_npts2fit(self):
1906        """
1907        return numbers of data points within qrange
1908       
1909        :Note: This is for Park where chi2 is not normalized by Npts of fit
1910       
1911        """
1912        if self.data is None:
1913            return
1914        npts2fit = 0
1915        qmin, qmax = self.get_range()
1916        if self.data.__class__.__name__ == "Data2D" or \
1917                        self.enable2D:
1918            radius = numpy.sqrt(self.data.qx_data * self.data.qx_data +
1919                                self.data.qy_data * self.data.qy_data)
1920            index_data = (self.qmin_x <= radius) & (radius <= self.qmax_x)
1921            index_data = (index_data) & (self.data.mask)
1922            index_data = (index_data) & (numpy.isfinite(self.data.data))
1923            npts2fit = len(self.data.data[index_data])
1924        else:
1925            for qx in self.data.x:
1926                if qx >= qmin and qx <= qmax:
1927                    npts2fit += 1
1928        return npts2fit
1929
1930    def set_npts2fit(self):
1931        """
1932        setValue Npts for fitting
1933        """
1934        self.Npts_fit.SetValue(str(self.get_npts2fit()))
1935       
1936    def get_chi2(self):
1937        """
1938        return the current chi2
1939        """
1940        return self.tcChi.GetValue()
1941       
1942    def get_param_list(self):
1943        """
1944        :return self.param_toFit: list containing  references to TextCtrl
1945            checked.Theses TextCtrl will allow reference to parameters to fit.
1946       
1947        :raise: if return an empty list of parameter fit will nnote work
1948            properly so raise ValueError,"missing parameter to fit"
1949        """
1950        if self.param_toFit != []:
1951            return self.param_toFit
1952        else:
1953            msg = "missing parameters to fit"
1954            wx.MessageBox(msg, 'warning')
1955            return False
1956     
1957    def onsetValues(self, chisqr, p_name, out, cov):
1958        """
1959        Build the panel from the fit result
1960       
1961        :param chisqr: Value of the goodness of fit metric
1962        :param p_name: the name of parameters
1963        :param out: list of parameter with the best value found during fitting
1964        :param cov: Covariance matrix
1965   
1966        """
1967        # make sure stop button to fit button all the time
1968        self._on_fit_complete()
1969        if out == None or not numpy.isfinite(chisqr):
1970            raise ValueError, "Fit error occured..."
1971       
1972        is_modified = False
1973        has_error = False
1974        dispersity = ''
1975       
1976        #Hide textctrl boxes of errors.
1977        self._clear_Err_on_Fit()
1978       
1979        #Check if chi2 is finite
1980        if chisqr != None and numpy.isfinite(chisqr):
1981            #format chi2
1982            if self.engine_type == "park":
1983                npt_fit = float(self.get_npts2fit())
1984            chi2 = format_number(chisqr, True)
1985            self.tcChi.SetValue(chi2)
1986            self.tcChi.Refresh()
1987        else:
1988            self.tcChi.SetValue("-")
1989       
1990        #Hide error title
1991        if self.text2_3.IsShown() and not self.is_mac:
1992            self.text2_3.Hide()
1993     
1994        try:
1995            if self.enable_disp.GetValue():
1996                if hasattr(self, "text_disp_1"):
1997                    if self.text_disp_1 != None and not self.is_mac:
1998                        self.text_disp_1.Hide()
1999        except:
2000            dispersity = None
2001            pass
2002     
2003        i = 0
2004        #Set the panel when fit result are list
2005        for item in self.param_toFit:
2006            if len(item) > 5 and item != None:
2007                if item[0].IsShown():
2008                    ## reset error value to initial state
2009                    if not self.is_mac:
2010                        item[3].Hide()
2011                        item[4].Hide()
2012                    for ind in range(len(out)):
2013                        if item[1] == p_name[ind]:
2014                            break
2015                    if len(out) > 0 and out[ind] != None:
2016                        val_out = format_number(out[ind], True)
2017                        item[2].SetValue(val_out)
2018   
2019                    if(cov != None and len(cov) == len(out)):
2020                        try:
2021                            if dispersity != None:
2022                                if self.enable_disp.GetValue():
2023                                    if hasattr(self, "text_disp_1"):
2024                                        if self.text_disp_1 != None:
2025                                            if not self.text_disp_1.IsShown()\
2026                                                and not self.is_mac:
2027                                                self.text_disp_1.Show(True)
2028                        except:
2029                            pass
2030                       
2031                        if cov[ind] != None:
2032                            if numpy.isfinite(float(cov[ind])):
2033                                val_err = format_number(cov[ind], True)
2034                                if not self.is_mac:
2035                                    item[3].Show(True)
2036                                    item[4].Show(True)
2037                                item[4].SetValue(val_err)
2038                                has_error = True
2039                i += 1
2040            else:
2041                raise ValueError, "onsetValues: Invalid parameters..."
2042        #Show error title when any errors displayed
2043        if has_error:
2044            if not self.text2_3.IsShown():
2045                self.text2_3.Show(True)
2046        ## save current state
2047        self.save_current_state()
2048       
2049        if not self.is_mac:
2050            self.Layout()
2051            self.Refresh()
2052        self._mac_sleep(0.1)
2053        #plot model ( when drawing, do not update chisqr value again)
2054        self._draw_model(update_chisqr=False, source='fit')
2055   
2056    def onWeighting(self, event):
2057        """
2058        On Weighting radio button event, sets the weightbt_string
2059        """
2060        self.weightbt_string = event.GetEventObject().GetLabelText()
2061        self._set_weight()
2062       
2063    def _set_weight(self, is_2D=None):
2064        """
2065        Set weight in fit problem
2066        """
2067        # compute weight for the current data
2068        from .utils import get_weight
2069        flag_weight = self.get_weight_flag()
2070        if is_2D == None:
2071            is_2D = self._is_2D()
2072        weight = get_weight(data=self.data,
2073                            is2d=is_2D,
2074                            flag=flag_weight)
2075        self._manager.set_fit_weight(uid=self.uid,
2076                                     flag=flag_weight,
2077                                     is2d=is_2D,
2078                                     fid=None)
2079   
2080    def onPinholeSmear(self, event):
2081        """
2082        Create a custom pinhole smear object that will change the way residuals
2083        are compute when fitting
2084       
2085        :Note: accuracy is given by strings'High','Med', 'Low' FOR 2d,
2086                     None for 1D
2087                     
2088        """
2089        if self.model == None:
2090            self.disable_smearer.SetValue(True)
2091            if event == None:
2092                return
2093            msg = "Please select a Model first..."
2094            wx.MessageBox(msg, 'Info')
2095            wx.PostEvent(self._manager.parent,
2096                         StatusEvent(status="Smear: %s" % msg))
2097            return
2098
2099        # Need update param values
2100        self._update_paramv_on_fit()
2101
2102        # msg default
2103        msg = None
2104        if event != None:
2105            tcrtl = event.GetEventObject()
2106            # event case of radio button
2107            if tcrtl.GetValue() == True:
2108                self.dx_min = 0.0
2109                self.dx_max = 0.0
2110                is_new_pinhole = True
2111            else:
2112                is_new_pinhole = self._is_changed_pinhole()
2113        else:
2114            is_new_pinhole = True
2115        # if any value is changed
2116        if is_new_pinhole:
2117            msg = self._set_pinhole_smear()
2118        # hide all silt sizer
2119        self._hide_all_smear_info()
2120       
2121        # show relevant slit sizers
2122        self._show_smear_sizer()
2123
2124        self.sizer_set_smearer.Layout()
2125        self.Layout()
2126       
2127        if event != None:
2128            event.Skip()
2129        #self._undo.Enable(True)
2130        self.save_current_state()
2131        event = PageInfoEvent(page=self)
2132        wx.PostEvent(self.parent, event)
2133       
2134    def _is_changed_pinhole(self):
2135        """
2136        check if any of pinhole smear is changed
2137       
2138        :return: True or False
2139       
2140        """
2141        # get the values
2142        pin_min = self.smear_pinhole_min.GetValue()
2143        pin_max = self.smear_pinhole_max.GetValue()
2144                   
2145        # Check changes in slit width
2146        try:
2147            dx_min = float(pin_min)
2148        except:
2149            return True
2150        if self.dx_min != dx_min:
2151            return True
2152       
2153        # Check changes in slit heigth
2154        try:
2155            dx_max = float(pin_max)
2156        except:
2157            return True
2158        if self.dx_max != dx_max:
2159            return True
2160        return False
2161   
2162    def _set_pinhole_smear(self):
2163        """
2164        Set custom pinhole smear
2165       
2166        :return: msg
2167       
2168        """
2169        # copy data
2170        data = copy.deepcopy(self.data)
2171        if self._is_2D():
2172            self.smear_type = 'Pinhole2d'
2173            len_data = len(data.data)
2174            data.dqx_data = numpy.zeros(len_data)
2175            data.dqy_data = numpy.zeros(len_data)
2176        else:
2177            self.smear_type = 'Pinhole'
2178            len_data = len(data.x)
2179            data.dx = numpy.zeros(len_data)
2180            data.dxl = None
2181            data.dxw = None
2182        msg = None
2183   
2184        get_pin_min = self.smear_pinhole_min
2185        get_pin_max = self.smear_pinhole_max
2186
2187        if not check_float(get_pin_min):
2188            get_pin_min.SetBackgroundColour("pink")
2189            msg = "Model Error:wrong value entered!!!"
2190        elif not check_float(get_pin_max):
2191            get_pin_max.SetBackgroundColour("pink")
2192            msg = "Model Error:wrong value entered!!!"
2193        else:
2194            if len_data < 2:
2195                len_data = 2
2196            self.dx_min = float(get_pin_min.GetValue())
2197            self.dx_max = float(get_pin_max.GetValue())
2198            if self.dx_min < 0:
2199                get_pin_min.SetBackgroundColour("pink")
2200                msg = "Model Error:This value can not be negative!!!"
2201            elif self.dx_max < 0:
2202                get_pin_max.SetBackgroundColour("pink")
2203                msg = "Model Error:This value can not be negative!!!"
2204            elif self.dx_min != None and self.dx_max != None:
2205                if self._is_2D():
2206                    data.dqx_data[data.dqx_data == 0] = self.dx_min
2207                    data.dqy_data[data.dqy_data == 0] = self.dx_max
2208                elif self.dx_min == self.dx_max:
2209                    data.dx[data.dx == 0] = self.dx_min
2210                else:
2211                    step = (self.dx_max - self.dx_min) / (len_data - 1)
2212                    data.dx = numpy.arange(self.dx_min,
2213                                           self.dx_max + step / 1.1,
2214                                           step)
2215            elif self.dx_min != None:
2216                if self._is_2D():
2217                    data.dqx_data[data.dqx_data == 0] = self.dx_min
2218                else:
2219                    data.dx[data.dx == 0] = self.dx_min
2220            elif self.dx_max != None:
2221                if self._is_2D():
2222                    data.dqy_data[data.dqy_data == 0] = self.dx_max
2223                else:
2224                    data.dx[data.dx == 0] = self.dx_max
2225            self.current_smearer = smear_selection(data, self.model)
2226            # 2D need to set accuracy
2227            if self._is_2D():
2228                self.current_smearer.set_accuracy(accuracy=\
2229                                                  self.smear2d_accuracy)
2230
2231        if msg != None:
2232            wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
2233        else:
2234            get_pin_min.SetBackgroundColour("white")
2235            get_pin_max.SetBackgroundColour("white")
2236        ## set smearing value whether or not the data contain the smearing info
2237       
2238        self._manager.set_smearer(smearer=self.current_smearer,
2239                            fid=self.data.id,
2240                            qmin=float(self.qmin_x),
2241                            qmax=float(self.qmax_x),
2242                            enable_smearer=not self.disable_smearer.GetValue(),
2243                            uid=self.uid)
2244        return msg
2245       
2246    def update_pinhole_smear(self):
2247        """
2248        called by kill_focus on pinhole TextCntrl
2249        to update the changes
2250       
2251        :return: False when wrong value was entered
2252       
2253        """
2254        # msg default
2255        msg = None
2256        # check if any value is changed
2257        if self._is_changed_pinhole():
2258            msg = self._set_pinhole_smear()
2259        wx.CallAfter(self.save_current_state)
2260
2261        if msg != None:
2262            return False
2263        else:
2264            return True
2265                     
2266    def onSlitSmear(self, event):
2267        """
2268        Create a custom slit smear object that will change the way residuals
2269        are compute when fitting
2270        """
2271        if self.model == None:
2272            self.disable_smearer.SetValue(True)
2273            if event == None:
2274                return
2275            msg = "Please select a Model first..."
2276            wx.MessageBox(msg, 'Info')
2277            wx.PostEvent(self._manager.parent,
2278                         StatusEvent(status="Smear: %s" % msg))
2279            return
2280
2281        # Need update param values
2282        self._update_paramv_on_fit()
2283
2284        # msg default
2285        msg = None
2286        # for event given
2287        if event != None:
2288            tcrtl = event.GetEventObject()
2289            # event case of radio button
2290            if tcrtl.GetValue():
2291                self.dxl = 0.0
2292                self.dxw = 0.0
2293                is_new_slit = True
2294            else:
2295                is_new_slit = self._is_changed_slit()
2296        else:
2297            is_new_slit = True
2298       
2299        # if any value is changed
2300        if is_new_slit:
2301            msg = self._set_slit_smear()
2302           
2303        # hide all silt sizer
2304        self._hide_all_smear_info()
2305        # show relevant slit sizers
2306        self._show_smear_sizer()
2307        self.sizer_set_smearer.Layout()
2308        self.Layout()
2309
2310        if event != None:
2311            event.Skip()
2312        self.save_current_state()
2313        event = PageInfoEvent(page=self)
2314        wx.PostEvent(self.parent, event)
2315        if msg != None:
2316            wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
2317
2318    def _is_changed_slit(self):
2319        """
2320        check if any of slit lengths is changed
2321       
2322        :return: True or False
2323       
2324        """
2325        # get the values
2326        width = self.smear_slit_width.GetValue()
2327        height = self.smear_slit_height.GetValue()
2328       
2329        # check and change the box bg color if it was pink
2330        #    but it should be white now
2331        # because this is the case that _set_slit_smear() will not handle
2332        if height.lstrip().rstrip() == "":
2333            self.smear_slit_height.SetBackgroundColour(wx.WHITE)
2334        if width.lstrip().rstrip() == "":
2335            self.smear_slit_width.SetBackgroundColour(wx.WHITE)
2336           
2337        # Check changes in slit width
2338        if width == "":
2339            dxw = 0.0
2340        else:
2341            try:
2342                dxw = float(width)
2343            except:
2344                return True
2345        if self.dxw != dxw:
2346            return True
2347       
2348        # Check changes in slit heigth
2349        if height == "":
2350            dxl = 0.0
2351        else:
2352            try:
2353                dxl = float(height)
2354            except:
2355                return True
2356        if self.dxl != dxl:
2357            return True
2358
2359        return False
2360   
2361    def _set_slit_smear(self):
2362        """
2363        Set custom slit smear
2364       
2365        :return: message to inform the user about the validity
2366            of the values entered for slit smear
2367        """
2368        if self.data.__class__.__name__ == "Data2D" or \
2369                        self.enable2D:
2370            return
2371        # make sure once more if it is smearer
2372        data = copy.deepcopy(self.data)
2373        data_len = len(data.x)
2374        data.dx = None
2375        data.dxl = None
2376        data.dxw = None
2377        msg = None
2378   
2379        try:
2380            self.dxl = float(self.smear_slit_height.GetValue())
2381            data.dxl = self.dxl * numpy.ones(data_len)
2382            self.smear_slit_height.SetBackgroundColour(wx.WHITE)
2383        except:
2384            data.dxl = numpy.zeros(data_len)
2385            if self.smear_slit_height.GetValue().lstrip().rstrip() != "":
2386                self.smear_slit_height.SetBackgroundColour("pink")
2387                msg = "Wrong value entered... "
2388            else:
2389                self.smear_slit_height.SetBackgroundColour(wx.WHITE)
2390        try:
2391            self.dxw = float(self.smear_slit_width.GetValue())
2392            self.smear_slit_width.SetBackgroundColour(wx.WHITE)
2393            data.dxw = self.dxw * numpy.ones(data_len)
2394        except:
2395            data.dxw = numpy.zeros(data_len)
2396            if self.smear_slit_width.GetValue().lstrip().rstrip() != "":
2397                self.smear_slit_width.SetBackgroundColour("pink")
2398                msg = "Wrong Fit value entered... "
2399            else:
2400                self.smear_slit_width.SetBackgroundColour(wx.WHITE)
2401             
2402        self.current_smearer = smear_selection(data, self.model)
2403        ## set smearing value whether or not the data contain the smearing info
2404        self._manager.set_smearer(smearer=self.current_smearer,
2405                                 fid=self.data.id,
2406                                 qmin=float(self.qmin_x),
2407                                 qmax=float(self.qmax_x),
2408                        enable_smearer=not self.disable_smearer.GetValue(),
2409                                 uid=self.uid)
2410        return msg
2411   
2412    def update_slit_smear(self):
2413        """
2414        called by kill_focus on pinhole TextCntrl
2415        to update the changes
2416       
2417        :return: False when wrong value was entered
2418       
2419        """
2420        # msg default
2421        msg = None
2422        # check if any value is changed
2423        if self._is_changed_slit():
2424            msg = self._set_slit_smear()
2425        #self._undo.Enable(True)
2426        self.save_current_state()
2427
2428        if msg != None:
2429            return False
2430        else:
2431            return True
2432                           
2433    def onSmear(self, event):
2434        """
2435        Create a smear object that will change the way residuals
2436        are compute when fitting
2437        """
2438        if event != None:
2439            event.Skip()
2440        if self.data is None:
2441            return
2442
2443        if self.model == None:
2444            self.disable_smearer.SetValue(True)
2445            if event == None:
2446                return
2447            msg = "Please select a Model first..."
2448            wx.MessageBox(msg, 'Info')
2449            wx.PostEvent(self._manager.parent,
2450                         StatusEvent(status="Smear: %s" % msg))
2451            return
2452        # Need update param values
2453        self._update_paramv_on_fit()
2454        if self.model != None:
2455            if self.data.is_data:
2456                self._manager.page_finder[self.uid].add_data(data=self.data)
2457        temp_smearer = self.on_smear_helper()
2458       
2459        self.sizer_set_smearer.Layout()
2460        self.Layout()
2461        self._set_weight()
2462       
2463        ## set smearing value whether or not the data contain the smearing info
2464        wx.CallAfter(self._manager.set_smearer, uid=self.uid,
2465                     smearer=temp_smearer,
2466                     fid=self.data.id,
2467                     qmin=float(self.qmin_x),
2468                     qmax=float(self.qmax_x),
2469                     enable_smearer=not self.disable_smearer.GetValue(),
2470                     draw=True)
2471       
2472        self.state.enable_smearer = self.enable_smearer.GetValue()
2473        self.state.disable_smearer = self.disable_smearer.GetValue()
2474        self.state.pinhole_smearer = self.pinhole_smearer.GetValue()
2475        self.state.slit_smearer = self.slit_smearer.GetValue()
2476       
2477    def on_smear_helper(self, update=False):
2478        """
2479        Help for onSmear
2480       
2481        :param update: force or not to update
2482        """
2483        self._get_smear_info()
2484        #renew smear sizer
2485        if self.smear_type != None:
2486            self.smear_description_smear_type.SetValue(str(self.smear_type))
2487            self.smear_data_left.SetValue(str(self.dq_l))
2488            self.smear_data_right.SetValue(str(self.dq_r))
2489
2490        self._hide_all_smear_info()
2491        data = copy.deepcopy(self.data)
2492       
2493        # make sure once more if it is smearer
2494        temp_smearer = smear_selection(data, self.model)
2495        if self.current_smearer != temp_smearer or update:
2496            self.current_smearer = temp_smearer
2497        if self.enable_smearer.GetValue():
2498            if self.current_smearer == None:
2499                wx.PostEvent(self._manager.parent,
2500                    StatusEvent(status="Data contains no smearing information"))
2501            else:
2502                wx.PostEvent(self._manager.parent,
2503                    StatusEvent(status="Data contains smearing information"))
2504
2505            self.smear_data_left.Show(True)
2506            self.smear_data_right.Show(True)
2507            temp_smearer = self.current_smearer
2508        elif self.disable_smearer.GetValue():
2509            self.smear_description_none.Show(True)
2510        elif self.pinhole_smearer.GetValue():
2511            self.onPinholeSmear(None)
2512        elif self.slit_smearer.GetValue():
2513            self.onSlitSmear(None)
2514        self._show_smear_sizer()
2515       
2516        return temp_smearer
2517   
2518    def on_complete_chisqr(self, event):
2519        """
2520        Display result chisqr on the panel
2521        :event: activated by fitting/ complete after draw
2522        """
2523        try:
2524            if event == None:
2525                output = "-"
2526            elif not numpy.isfinite(event.output):
2527                output = "-"
2528            else:
2529                output = event.output
2530            self.tcChi.SetValue(str(format_number(output, True)))
2531            self.state.tcChi = self.tcChi.GetValue()
2532        except:
2533            pass
2534           
2535    def get_all_checked_params(self):
2536        """
2537        Found all parameters current check and add them to list of parameters
2538        to fit
2539        """
2540        self.param_toFit = []
2541        for item in self.parameters:
2542            if item[0].GetValue() and item not in self.param_toFit:
2543                if item[0].IsShown():
2544                    self.param_toFit.append(item)
2545        for item in self.fittable_param:
2546            if item[0].GetValue() and item not in self.param_toFit:
2547                if item[0].IsShown():
2548                    self.param_toFit.append(item)
2549        self.save_current_state_fit()
2550       
2551        event = PageInfoEvent(page=self)
2552        wx.PostEvent(self.parent, event)
2553        param2fit = []
2554        for item in self.param_toFit:
2555            if item[0] and item[0].IsShown():
2556                param2fit.append(item[1])
2557        self.parent._manager.set_param2fit(self.uid, param2fit)
2558               
2559    def select_all_param(self, event):
2560        """
2561        set to true or false all checkBox given the main checkbox value cb1
2562        """
2563        self.param_toFit = []
2564        if  self.parameters != []:
2565            if  self.cb1.GetValue():
2566                for item in self.parameters:
2567                    if item[0].IsShown():
2568                        ## for data2D select all to fit
2569                        if self.data.__class__.__name__ == "Data2D" or \
2570                                self.enable2D:
2571                            item[0].SetValue(True)
2572                            self.param_toFit.append(item)
2573                        else:
2574                            ## for 1D all parameters except orientation
2575                            if not item in self.orientation_params:
2576                                item[0].SetValue(True)
2577                                self.param_toFit.append(item)
2578                    else:
2579                        item[0].SetValue(False)
2580                #if len(self.fittable_param)>0:
2581                for item in self.fittable_param:
2582                    if item[0].IsShown():
2583                        if self.data.__class__.__name__ == "Data2D" or \
2584                                self.enable2D:
2585                            item[0].SetValue(True)
2586                            self.param_toFit.append(item)
2587                            try:
2588                                if len(self.values[item[1]]) > 0:
2589                                    item[0].SetValue(False)
2590                            except:
2591                                pass
2592   
2593                        else:
2594                            ## for 1D all parameters except orientation
2595                            if not item in self.orientation_params_disp:
2596                                item[0].SetValue(True)
2597                                self.param_toFit.append(item)
2598                                try:
2599                                    if len(self.values[item[1]]) > 0:
2600                                        item[0].SetValue(False)
2601                                except:
2602                                    pass
2603                    else:
2604                        item[0].SetValue(False)
2605
2606            else:
2607                for item in self.parameters:
2608                    item[0].SetValue(False)
2609                for item in self.fittable_param:
2610                    item[0].SetValue(False)
2611                self.param_toFit = []
2612           
2613        self.save_current_state_fit()
2614       
2615        if event != None:
2616            #self._undo.Enable(True)
2617            ## post state to fit panel
2618            event = PageInfoEvent(page=self)
2619            wx.PostEvent(self.parent, event)
2620        param2fit = []
2621        for item in self.param_toFit:
2622            if item[0] and item[0].IsShown():
2623                param2fit.append(item[1])
2624        self.parent._manager.set_param2fit(self.uid, param2fit)
2625
2626    def select_param(self, event):
2627        """
2628        Select TextCtrl  checked for fitting purpose and stores them
2629        in  self.param_toFit=[] list
2630        """
2631        self.param_toFit = []
2632        for item in self.parameters:
2633            #Skip t ifhe angle parameters if 1D data
2634            if self.data.__class__.__name__ != "Data2D" and\
2635                        not self.enable2D:
2636                if item in self.orientation_params:
2637                    continue
2638            #Select parameters to fit for list of primary parameters
2639            if item[0].GetValue() and item[0].IsShown():
2640                if not (item in self.param_toFit):
2641                    self.param_toFit.append(item)
2642            else:
2643                #remove parameters from the fitting list
2644                if item in self.param_toFit:
2645                    self.param_toFit.remove(item)
2646
2647        #Select parameters to fit for list of fittable parameters
2648        #        with dispersion
2649        for item in self.fittable_param:
2650            #Skip t ifhe angle parameters if 1D data
2651            if self.data.__class__.__name__ != "Data2D" and\
2652                        not self.enable2D:
2653                if item in self.orientation_params:
2654                    continue
2655            if item[0].GetValue() and item[0].IsShown():
2656                if not (item in self.param_toFit):
2657                    self.param_toFit.append(item)
2658            else:
2659                #remove parameters from the fitting list
2660                if item in self.param_toFit:
2661                    self.param_toFit.remove(item)
2662
2663        #Calculate num. of angle parameters
2664        if self.data.__class__.__name__ == "Data2D" or \
2665                       self.enable2D:
2666            len_orient_para = 0
2667        else:
2668            len_orient_para = len(self.orientation_params)  # assume even len
2669        #Total num. of angle parameters
2670        if len(self.fittable_param) > 0:
2671            len_orient_para *= 2
2672        #Set the value of checkbox that selected every checkbox or not
2673        if len(self.parameters) + len(self.fittable_param) - len_orient_para \
2674            == len(self.param_toFit):
2675            self.cb1.SetValue(True)
2676        else:
2677            self.cb1.SetValue(False)
2678       
2679        self.save_current_state_fit()
2680        if event != None:
2681            ## post state to fit panel
2682            event = PageInfoEvent(page=self)
2683            wx.PostEvent(self.parent, event)
2684       
2685        param2fit = []
2686        for item in self.param_toFit:
2687            if item[0] and item[0].IsShown():
2688                param2fit.append(item[1])
2689        self.parent._manager.set_param2fit(self.uid, param2fit)
2690       
2691    def set_model_param_sizer(self, model):
2692        """
2693        Build the panel from the model content
2694       
2695        :param model: the model selected in combo box for fitting purpose
2696       
2697        """
2698        self.sizer3.Clear(True)
2699        self.parameters = []
2700        self.str_parameters = []
2701        self.param_toFit = []
2702        self.fittable_param = []
2703        self.fixed_param = []
2704        self.orientation_params = []
2705        self.orientation_params_disp = []
2706       
2707        if model == None:
2708            self.sizer3.Layout()
2709            self.SetupScrolling()
2710            return
2711        ## the panel is drawn using the current value of the fit engine
2712        if self.engine_type == None and self._manager != None:
2713            self.engine_type = self._manager._return_engine_type()
2714
2715        box_description = wx.StaticBox(self, -1, str("Model Parameters"))
2716        boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
2717        sizer = wx.GridBagSizer(5, 5)
2718        ## save the current model
2719        self.model = model
2720           
2721        keys = self.model.getParamList()
2722        #list of dispersion paramaters
2723        self.disp_list = self.model.getDispParamList()
2724
2725        def custom_compare(a, b):
2726            """
2727            Custom compare to order, first by alphabets then second by number.
2728            """
2729            # number at the last digit
2730            a_last = a[len(a) - 1]
2731            b_last = b[len(b) - 1]
2732            # default
2733            num_a = None
2734            num_b = None
2735            # split the names
2736            a2 = a.lower().split('_')
2737            b2 = b.lower().split('_')
2738            # check length of a2, b2
2739            len_a2 = len(a2)
2740            len_b2 = len(b2)
2741            # check if it contains a int number(<10)
2742            try:
2743                num_a = int(a_last)
2744            except:
2745                pass
2746            try:
2747                num_b = int(b_last)
2748            except:
2749                pass
2750            # Put 'scale' near the top; happens
2751            # when numbered param name exists
2752            if a == 'scale':
2753                return -1
2754            # both have a number
2755            if num_a != None and num_b != None:
2756                if num_a > num_b:
2757                    return -1
2758                # same number
2759                elif num_a == num_b:
2760                    # different last names
2761                    if a2[len_a2 - 1] != b2[len_b2 - 1] and num_a != 0:
2762                        return -cmp(a2[len_a2 - 1], b2[len_b2 - 1])
2763                    else:
2764                        return cmp(a, b)
2765                else:
2766                    return 1
2767            # one of them has a number
2768            elif num_a != None:
2769                return 1
2770            elif num_b != None:
2771                return -1
2772            # no numbers
2773            else:
2774                return cmp(a.lower(), b.lower())
2775
2776        keys.sort(custom_compare)
2777   
2778        iy = 0
2779        ix = 0
2780        select_text = "Select All"
2781        self.cb1 = wx.CheckBox(self, -1, str(select_text), (10, 10))
2782        wx.EVT_CHECKBOX(self, self.cb1.GetId(), self.select_all_param)
2783        self.cb1.SetToolTipString("To check/uncheck all the boxes below.")
2784        self.cb1.SetValue(True)
2785       
2786        sizer.Add(self.cb1, (iy, ix), (1, 1), \
2787                             wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 5)
2788        ix += 1
2789        self.text2_2 = wx.StaticText(self, -1, 'Value')
2790        sizer.Add(self.text2_2, (iy, ix), (1, 1), \
2791                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2792        ix += 2
2793        self.text2_3 = wx.StaticText(self, -1, 'Error')
2794        sizer.Add(self.text2_3, (iy, ix), (1, 1), \
2795                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2796        if not self.is_mac:
2797            self.text2_3.Hide()
2798        ix += 1
2799        self.text2_min = wx.StaticText(self, -1, 'Min')
2800        sizer.Add(self.text2_min, (iy, ix), (1, 1), \
2801                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2802        #self.text2_min.Hide()
2803        ix += 1
2804        self.text2_max = wx.StaticText(self, -1, 'Max')
2805        sizer.Add(self.text2_max, (iy, ix), (1, 1), \
2806                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2807        #self.text2_max.Hide()
2808        ix += 1
2809        self.text2_4 = wx.StaticText(self, -1, '[Units]')
2810        sizer.Add(self.text2_4, (iy, ix), (1, 1), \
2811                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2812        self.text2_4.Hide()
2813       
2814        CHECK_STATE = self.cb1.GetValue()
2815        for item in keys:
2816            if not item in self.disp_list and not item in \
2817                    self.model.orientation_params:
2818               
2819                ##prepare a spot to store errors
2820                if not item in self.model.details:
2821                    self.model.details[item] = ["", None, None]
2822         
2823                iy += 1
2824                ix = 0
2825                if (self.model.__class__ in \
2826                    self.model_list_box["Multi-Functions"] or \
2827                    self.temp_multi_functional)\
2828                    and (item in self.model.non_fittable):
2829                    non_fittable_name = wx.StaticText(self, -1, item)
2830                    sizer.Add(non_fittable_name, (iy, ix), (1, 1), \
2831                            wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 21)
2832                    ## add parameter value
2833                    ix += 1
2834                    value = self.model.getParam(item)
2835                    if len(self.model.fun_list) > 0:
2836                        #num = item.split('_')[1][5:7]
2837                        fun_box = wx.ComboBox(self, -1, size=(100, -1),
2838                                    style=wx.CB_READONLY, name='%s' % item)
2839                        self._set_fun_box_list(fun_box)
2840                        fun_box.SetSelection(0)
2841                        #self.fun_box.SetToolTipString("A function
2842                        #    describing the interface")
2843                        wx.EVT_COMBOBOX(fun_box, -1, self._on_fun_box)
2844                    else:
2845                        fun_box = self.ModelTextCtrl(self, -1,
2846                                                     size=(_BOX_WIDTH, 20),
2847                                style=wx.TE_PROCESS_ENTER, name='%s' % item)
2848                        fun_box.SetToolTipString(\
2849                                "Hit 'Enter' after typing to update the plot.")
2850                        fun_box.SetValue(format_number(value, True))
2851                    sizer.Add(fun_box, (iy, ix), (1, 1), wx.EXPAND)
2852                    self.str_parameters.append([None, item, fun_box,
2853                                                None, None, None,
2854                                                None, None])
2855                else:
2856                    ## add parameters name with checkbox for selecting to fit
2857                    cb = wx.CheckBox(self, -1, item)
2858                    cb.SetValue(CHECK_STATE)
2859                    cb.SetToolTipString(" Check mark to fit.")
2860                    #cb.SetValue(True)
2861                    wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
2862                   
2863                    sizer.Add(cb, (iy, ix), (1, 1),
2864                              wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 5)
2865
2866                    ## add parameter value
2867                    ix += 1
2868                    value = self.model.getParam(item)
2869                    ctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
2870                                        style=wx.TE_PROCESS_ENTER)
2871                    ctl1.SetToolTipString(\
2872                                "Hit 'Enter' after typing to update the plot.")
2873                    ctl1.SetValue(format_number(value, True))
2874                    sizer.Add(ctl1, (iy, ix), (1, 1), wx.EXPAND)
2875                    ## text to show error sign
2876                    ix += 1
2877                    text2 = wx.StaticText(self, -1, '+/-')
2878                    sizer.Add(text2, (iy, ix), (1, 1), \
2879                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2880                    if not self.is_mac:
2881                        text2.Hide()
2882                    ix += 1
2883                    ctl2 = wx.TextCtrl(self, -1,
2884                                       size=(_BOX_WIDTH / 1.2, 20), style=0)
2885                    sizer.Add(ctl2, (iy, ix), (1, 1),
2886                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2887                    if not self.is_mac:
2888                        ctl2.Hide()
2889                   
2890                    ix += 1
2891                    ctl3 = self.ModelTextCtrl(self, -1,
2892                                              size=(_BOX_WIDTH / 1.9, 20),
2893                                              style=wx.TE_PROCESS_ENTER,
2894                                text_enter_callback=self._onparamRangeEnter)
2895         
2896                    sizer.Add(ctl3, (iy, ix), (1, 1),
2897                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2898           
2899                    ix += 1
2900                    ctl4 = self.ModelTextCtrl(self, -1,
2901                                              size=(_BOX_WIDTH / 1.9, 20),
2902                                              style=wx.TE_PROCESS_ENTER,
2903                                text_enter_callback=self._onparamRangeEnter)
2904                    sizer.Add(ctl4, (iy, ix), (1, 1),
2905                              wx.EXPAND | wx.FIXED_MINSIZE, 0)
2906   
2907                    ix += 1
2908                    # Units
2909                    if item in self.model.details:
2910                        units = wx.StaticText(self, -1,
2911                            self.model.details[item][0], style=wx.ALIGN_LEFT)
2912                    else:
2913                        units = wx.StaticText(self, -1, "",
2914                                              style=wx.ALIGN_LEFT)
2915                    sizer.Add(units, (iy, ix), (1, 1),
2916                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2917                       
2918                    self.parameters.append([cb, item, ctl1,
2919                                            text2, ctl2, ctl3, ctl4, units])
2920                                 
2921        iy += 1
2922        sizer.Add((10, 10), (iy, ix), (1, 1),
2923                  wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
2924       
2925        # type can be either Guassian or Array
2926        if len(self.model.dispersion.values()) > 0:
2927            type = self.model.dispersion.values()[0]["type"]
2928        else:
2929            type = "Gaussian"
2930           
2931        iy += 1
2932        ix = 0
2933        #Add tile for orientational angle
2934        for item in keys:
2935            if item in self.model.orientation_params:
2936                orient_angle = wx.StaticText(self, -1, '[For 2D only]:')
2937                sizer.Add(orient_angle, (iy, ix), (1, 1),
2938                          wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
2939                if not self.data.__class__.__name__ == "Data2D" and \
2940                        not self.enable2D:
2941                    orient_angle.Hide()
2942                else:
2943                    orient_angle.Show(True)
2944                break
2945     
2946        #For Gaussian only
2947        if type.lower() != "array":
2948            for item in self.model.orientation_params:
2949                if not item in self.disp_list:
2950                    ##prepare a spot to store min max
2951                    if not item in self.model.details:
2952                        self.model.details[item] = ["", None, None]
2953                         
2954                    iy += 1
2955                    ix = 0
2956                    ## add parameters name with checkbox for selecting to fit
2957                    cb = wx.CheckBox(self, -1, item)
2958                    cb.SetValue(CHECK_STATE)
2959                    cb.SetToolTipString("Check mark to fit")
2960                    wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
2961                    if self.data.__class__.__name__ == "Data2D" or \
2962                            self.enable2D:
2963                        cb.Show(True)
2964                    else:
2965                        cb.Hide()
2966                    sizer.Add(cb, (iy, ix), (1, 1),
2967                              wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 5)
2968   
2969                    ## add parameter value
2970                    ix += 1
2971                    value = self.model.getParam(item)
2972                    ctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
2973                                        style=wx.TE_PROCESS_ENTER)
2974                    ctl1.SetToolTipString(\
2975                                "Hit 'Enter' after typing to update the plot.")
2976                    ctl1.SetValue(format_number(value, True))
2977                    if self.data.__class__.__name__ == "Data2D" or \
2978                            self.enable2D:
2979                        ctl1.Show(True)
2980                    else:
2981                        ctl1.Hide()
2982                    sizer.Add(ctl1, (iy, ix), (1, 1), wx.EXPAND)
2983                    ## text to show error sign
2984                    ix += 1
2985                    text2 = wx.StaticText(self, -1, '+/-')
2986                    sizer.Add(text2, (iy, ix), (1, 1), \
2987                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2988
2989                    text2.Hide()
2990                    ix += 1
2991                    ctl2 = wx.TextCtrl(self, -1,
2992                                       size=(_BOX_WIDTH / 1.2, 20), style=0)
2993                    sizer.Add(ctl2, (iy, ix), (1, 1),
2994                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2995
2996                    ctl2.Hide()
2997                   
2998                    ix += 1
2999                    ctl3 = self.ModelTextCtrl(self, -1,
3000                                              size=(_BOX_WIDTH / 1.8, 20),
3001                                              style=wx.TE_PROCESS_ENTER,
3002                                text_enter_callback=self._onparamRangeEnter)
3003                   
3004                    sizer.Add(ctl3, (iy, ix), (1, 1),
3005                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
3006                    ctl3.Hide()
3007                 
3008                    ix += 1
3009                    ctl4 = self.ModelTextCtrl(self, -1,
3010                                              size=(_BOX_WIDTH / 1.8, 20),
3011                                              style=wx.TE_PROCESS_ENTER,
3012                            text_enter_callback=self._onparamRangeEnter)
3013                    sizer.Add(ctl4, (iy, ix), (1, 1),
3014                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
3015                   
3016                    ctl4.Hide()
3017                   
3018                    if self.data.__class__.__name__ == "Data2D" or \
3019                            self.enable2D:
3020                        if self.is_mac:
3021                            text2.Show(True)
3022                            ctl2.Show(True)
3023                        ctl3.Show(True)
3024                        ctl4.Show(True)
3025                   
3026                    ix += 1
3027                    # Units
3028                    if item in self.model.details:
3029                        units = wx.StaticText(self, -1,
3030                                              self.model.details[item][0],
3031                                              style=wx.ALIGN_LEFT)
3032                    else:
3033                        units = wx.StaticText(self, -1, "",
3034                                              style=wx.ALIGN_LEFT)
3035                    if self.data.__class__.__name__ == "Data2D" or \
3036                            self.enable2D:
3037                        units.Show(True)
3038                    else:
3039                        units.Hide()
3040                   
3041                    sizer.Add(units, (iy, ix), (1, 1),
3042                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
3043                                         
3044                    self.parameters.append([cb, item, ctl1,
3045                                            text2, ctl2, ctl3, ctl4, units])
3046                    self.orientation_params.append([cb, item, ctl1,
3047                                            text2, ctl2, ctl3, ctl4, units])
3048             
3049        iy += 1
3050        box_description.SetForegroundColour(wx.BLUE)
3051        #Display units text on panel
3052        for item in keys:
3053            if item in self.model.details:
3054                self.text2_4.Show()
3055        #Fill the list of fittable parameters
3056        self.get_all_checked_params()
3057        self.save_current_state_fit()
3058        boxsizer1.Add(sizer)
3059        self.sizer3.Add(boxsizer1, 0, wx.EXPAND | wx.ALL, 10)
3060        self.sizer3.Layout()
3061        self.Layout()
3062
3063    def on_right_down(self, event):
3064        """
3065        Get key stroke event
3066        """
3067        if self.data == None:
3068            return
3069        # Figuring out key combo: Cmd for copy, Alt for paste
3070        if event.AltDown() and event.ShiftDown():
3071            self._manager.show_ftol_dialog()
3072            flag = True
3073        elif event.AltDown() or event.ShiftDown():
3074            flag = False
3075        else:
3076            return
3077        # make event free
3078        event.Skip()
3079        # messages depending on the flag
3080        if not flag:
3081            msg = " Could not open ftol dialog;"
3082            msg += " Check if the Scipy fit engine is selected in the menubar."
3083            infor = 'warning'
3084            # inform msg to wx
3085            wx.PostEvent(self.parent.parent,
3086                        StatusEvent(status=msg, info=infor))
3087       
3088    def _onModel2D(self, event):
3089        """
3090        toggle view of model from 1D to 2D  or 2D from 1D
3091        """
3092        if self.model_view.GetLabelText() == "Show 2D":
3093            self.model_view.SetLabel("Show 1D")
3094            self.enable2D = True
3095             
3096        else:
3097            self.model_view.SetLabel("Show 2D")
3098            self.enable2D = False
3099        self.Show(False)
3100        self.create_default_data()
3101        self._manager.store_data(self.uid, data_list=[self.data])
3102
3103        self.set_model_param_sizer(self.model)
3104        self._set_sizer_dispersion()
3105        self._set_weight(is_2D=self.enable2D)
3106        self._set_smear_buttons()
3107        self.Show(True)
3108        self.SetupScrolling()
3109        self._draw_model()
3110       
3111        self.state.enable2D = copy.deepcopy(self.enable2D)
3112   
3113    def _set_smear_buttons(self):
3114        """
3115        Set semarer radio buttons
3116        """
3117        # more disables for 2D
3118        if self.data.__class__.__name__ == "Data2D" or \
3119                    self.enable2D:
3120            self.slit_smearer.Disable()
3121            self.pinhole_smearer.Enable(True)
3122            self.default_mask = copy.deepcopy(self.data.mask)
3123        else:
3124            self.slit_smearer.Enable(True)
3125            self.pinhole_smearer.Enable(True)
3126           
3127           
3128class BGTextCtrl(wx.TextCtrl):
3129    """
3130    Text control used to display outputs.
3131    No editing allowed. The background is
3132    grayed out. User can't select text.
3133    """
3134    def __init__(self, *args, **kwds):
3135        wx.TextCtrl.__init__(self, *args, **kwds)
3136        self.SetEditable(False)
3137        self.SetBackgroundColour(self.GetParent().parent.GetBackgroundColour())
3138       
3139        # Bind to mouse event to avoid text highlighting
3140        # The event will be skipped once the call-back
3141        # is called.
3142        self.Bind(wx.EVT_MOUSE_EVENTS, self._click)
3143       
3144    def _click(self, event):
3145        """
3146        Prevent further handling of the mouse event
3147        by not calling Skip().
3148        """
3149        pass
Note: See TracBrowser for help on using the repository browser.