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

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 69ebe91 was e4cd34c, checked in by Mathieu Doucet <doucetm@…>, 12 years ago

Remove Stop button when not on Windows (crashes the application on RHEL6)

  • Property mode set to 100644
File size: 128.6 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            if self.plugin_rbutton.GetValue():
1178                temp = self.parent.update_model_list()
1179                if temp:
1180                    self.model_list_box = temp
1181                    current_val = self.formfactorbox.GetLabel()
1182                    pos = self.formfactorbox.GetSelection()
1183                    self._show_combox_helper()
1184                    self.formfactorbox.SetSelection(pos)
1185                    self.formfactorbox.SetValue(current_val)
1186            # when select a model only from guictr/button
1187            if is_poly_enabled != None:
1188                self.enable_disp.SetValue(is_poly_enabled)
1189                self.disable_disp.SetValue(not is_poly_enabled)
1190                self._set_dipers_Param(event=None)
1191                self.state.enable_disp = self.enable_disp.GetValue()
1192                self.state.disable_disp = self.disable_disp.GetValue()
1193
1194            # Keep the previous param values
1195            if copy_flag:
1196                self.get_paste_params(copy_flag)
1197                wx.CallAfter(self._onDraw, None)
1198               
1199        else:
1200            self._draw_model()
1201           
1202        if self.batch_on:
1203            self.slit_smearer.Enable(False)
1204            self.pinhole_smearer.Enable(False)
1205            self.btEditMask.Disable()
1206            self.EditMask_title.Disable()
1207           
1208        self.Show(True)
1209        self.SetupScrolling()
1210         
1211    def _onparamEnter(self, event):
1212        """
1213        when enter value on panel redraw model according to changed
1214        """
1215        if self.model == None:
1216            msg = "Please select a Model first..."
1217            wx.MessageBox(msg, 'Info')
1218            return
1219
1220        #default flag
1221        flag = False
1222        self.fitrange = True
1223        #get event object
1224        tcrtl = event.GetEventObject()
1225        #Clear msg if previously shown.
1226        msg = ""
1227        wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
1228
1229        if check_float(tcrtl):
1230            flag = self._onparamEnter_helper()
1231            self.set_npts2fit()
1232            if self.fitrange:
1233                temp_smearer = None
1234                if not self.disable_smearer.GetValue():
1235                    temp_smearer = self.current_smearer
1236                    ## set smearing value whether or not
1237                    #        the data contain the smearing info
1238                    if self.slit_smearer.GetValue():
1239                        flag1 = self.update_slit_smear()
1240                        flag = flag or flag1
1241                    elif self.pinhole_smearer.GetValue():
1242                        flag1 = self.update_pinhole_smear()
1243                        flag = flag or flag1
1244                elif self.data.__class__.__name__ != "Data2D" and \
1245                        not self.enable2D:
1246                    self._manager.set_smearer(smearer=temp_smearer,
1247                                              fid=self.data.id,
1248                                              uid=self.uid,
1249                                              qmin=float(self.qmin_x),
1250                                              qmax=float(self.qmax_x),
1251                            enable_smearer=not self.disable_smearer.GetValue(),
1252                                            draw=True)
1253                if flag:
1254                    #self.compute_chisqr(smearer= temp_smearer)
1255       
1256                    ## new state posted
1257                    if self.state_change:
1258                        #self._undo.Enable(True)
1259                        event = PageInfoEvent(page=self)
1260                        wx.PostEvent(self.parent, event)
1261                    self.state_change = False
1262            else:
1263                # invalid fit range: do nothing here:
1264                # msg already displayed in validate
1265                return
1266        else:
1267            self.save_current_state()
1268            msg = "Cannot Plot :Must enter a number!!!  "
1269            wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
1270             
1271        self.save_current_state()
1272        return
1273   
1274    def _onparamRangeEnter(self, event):
1275        """
1276        Check validity of value enter in the parameters range field
1277        """
1278        tcrtl = event.GetEventObject()
1279        #Clear msg if previously shown.
1280        msg = ""
1281        wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
1282        # Flag to register when a parameter has changed.
1283        is_modified = False
1284        if tcrtl.GetValue().lstrip().rstrip() != "":
1285            try:
1286                tcrtl.SetBackgroundColour(wx.WHITE)
1287                self._check_value_enter(self.fittable_param, is_modified)
1288                self._check_value_enter(self.parameters, is_modified)
1289            except:
1290                tcrtl.SetBackgroundColour("pink")
1291                msg = "Model Error:wrong value entered : %s" % sys.exc_value
1292                wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
1293                return
1294        else:
1295            tcrtl.SetBackgroundColour(wx.WHITE)
1296           
1297        #self._undo.Enable(True)
1298        self.save_current_state()
1299        event = PageInfoEvent(page=self)
1300        wx.PostEvent(self.parent, event)
1301        self.state_change = False
1302         
1303    def _onQrangeEnter(self, event):
1304        """
1305        Check validity of value enter in the Q range field
1306        """
1307        tcrtl = event.GetEventObject()
1308        #Clear msg if previously shown.
1309        msg = ""
1310        wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
1311        # For theory mode
1312        if not self.data.is_data:
1313            self.npts_x = self.Npts_total.GetValue()
1314            self.Npts_fit.SetValue(self.npts_x)
1315            self.create_default_data()
1316        # Flag to register when a parameter has changed.
1317        if tcrtl.GetValue().lstrip().rstrip() != "":
1318            try:
1319                tcrtl.SetBackgroundColour(wx.WHITE)
1320                # If qmin and qmax have been modified, update qmin and qmax
1321                if self._validate_qrange(self.qmin, self.qmax):
1322                    tempmin = float(self.qmin.GetValue())
1323                    if tempmin != self.qmin_x:
1324                        self.qmin_x = tempmin
1325                    tempmax = float(self.qmax.GetValue())
1326                    if tempmax != self.qmax_x:
1327                        self.qmax_x = tempmax
1328                else:
1329                    tcrtl.SetBackgroundColour("pink")
1330                    msg = "Model Error:wrong value entered : %s" % sys.exc_value
1331                    wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
1332                    return
1333            except:
1334                tcrtl.SetBackgroundColour("pink")
1335                msg = "Model Error:wrong value entered : %s" % sys.exc_value
1336                wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
1337                return
1338            #Check if # of points for theory model are valid(>0).
1339            # check for 2d
1340            if self.data.__class__.__name__ == "Data2D" or \
1341                    self.enable2D:
1342                # set mask
1343                radius = numpy.sqrt(self.data.qx_data * self.data.qx_data +
1344                                    self.data.qy_data * self.data.qy_data)
1345                index_data = ((self.qmin_x <= radius) & \
1346                                (radius <= self.qmax_x))
1347                index_data = (index_data) & (self.data.mask)
1348                index_data = (index_data) & (numpy.isfinite(self.data.data))
1349                if len(index_data[index_data]) < 10:
1350                    msg = "Cannot Plot :No or too little npts in"
1351                    msg += " that data range!!!  "
1352                    wx.PostEvent(self.parent.parent,
1353                                 StatusEvent(status=msg))
1354                    return
1355                else:
1356                    #self.data.mask = index_data
1357                    #self.Npts_fit.SetValue(str(len(self.data.mask)))
1358                    self.set_npts2fit()
1359            else:
1360                index_data = ((self.qmin_x <= self.data.x) & \
1361                              (self.data.x <= self.qmax_x))
1362                self.Npts_fit.SetValue(str(len(self.data.x[index_data])))
1363           
1364            self.npts_x = self.Npts_total.GetValue()
1365            self.create_default_data()
1366            self._save_plotting_range()
1367        else:
1368            tcrtl.SetBackgroundColour("pink")
1369            msg = "Model Error:wrong value entered!!!"
1370            wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
1371       
1372        self._draw_model()
1373        self.save_current_state()
1374        event = PageInfoEvent(page=self)
1375        wx.PostEvent(self.parent, event)
1376        self.state_change = False
1377        return
1378   
1379    def _clear_Err_on_Fit(self):
1380        """
1381        hide the error text control shown
1382        after fitting
1383        """
1384        if self.is_mac:
1385            return
1386        if hasattr(self, "text2_3"):
1387            self.text2_3.Hide()
1388
1389        if len(self.parameters) > 0:
1390            for item in self.parameters:
1391                if item[0].IsShown():
1392                    #Skip t ifhe angle parameters if 1D data
1393                    if self.data.__class__.__name__ != "Data2D" and \
1394                            not self.enable2D:
1395                        if item in self.orientation_params:
1396                            continue
1397                    if item in self.param_toFit:
1398                        continue
1399                    ## hide statictext +/-
1400                    if len(item) < 4:
1401                        continue
1402                    if item[3] != None and item[3].IsShown():
1403                        item[3].Hide()
1404                    ## hide textcrtl  for error after fit
1405                    if item[4] != None and item[4].IsShown():
1406                        item[4].Hide()
1407 
1408        if len(self.fittable_param) > 0:
1409            for item in self.fittable_param:
1410                if item[0].IsShown():
1411                    #Skip t ifhe angle parameters if 1D data
1412                    if self.data.__class__.__name__ != "Data2D" and \
1413                            not self.enable2D:
1414                        if item in self.orientation_params:
1415                            continue
1416                    if item in self.param_toFit:
1417                        continue
1418                    if len(item) < 4:
1419                        continue
1420                    ## hide statictext +/-
1421                    if item[3] != None and item[3].IsShown():
1422                        item[3].Hide()
1423                    ## hide textcrtl  for error after fit
1424                    if item[4] != None and item[4].IsShown():
1425                        item[4].Hide()
1426        return
1427               
1428    def _get_defult_custom_smear(self):
1429        """
1430        Get the defult values for custum smearing.
1431        """
1432        # get the default values
1433        if self.dxl == None:
1434            self.dxl = 0.0
1435        if self.dxw == None:
1436            self.dxw = ""
1437        if self.dx_min == None:
1438            self.dx_min = SMEAR_SIZE_L
1439        if self.dx_max == None:
1440            self.dx_max = SMEAR_SIZE_H
1441       
1442    def _get_smear_info(self):
1443        """
1444        Get the smear info from data.
1445       
1446        :return: self.smear_type, self.dq_l and self.dq_r,
1447            respectively the type of the smear, dq_min and
1448            dq_max for pinhole smear data
1449            while dxl and dxw for slit smear
1450        """
1451        # default
1452        self.smear_type = None
1453        self.dq_l = None
1454        self.dq_r = None
1455        data = self.data
1456        if self.data is None:
1457            return
1458        elif self.data.__class__.__name__ == "Data2D" or \
1459            self.enable2D:
1460            if data.dqx_data == None or  data.dqy_data == None:
1461                return
1462            elif self.current_smearer != None \
1463                and data.dqx_data.any() != 0 \
1464                and data.dqx_data.any() != 0:
1465                self.smear_type = "Pinhole2d"
1466                self.dq_l = format_number(numpy.average(data.dqx_data))
1467                self.dq_r = format_number(numpy.average(data.dqy_data))
1468                return
1469            else:
1470                return
1471        # check if it is pinhole smear and get min max if it is.
1472        if data.dx != None and all(data.dx != 0):
1473            self.smear_type = "Pinhole"
1474            self.dq_l = data.dx[0]
1475            self.dq_r = data.dx[-1]
1476           
1477        # check if it is slit smear and get min max if it is.
1478        elif data.dxl != None or data.dxw != None:
1479            self.smear_type = "Slit"
1480            if data.dxl != None and all(data.dxl != 0):
1481                self.dq_l = data.dxl[0]
1482            if data.dxw != None and all(data.dxw != 0):
1483                self.dq_r = data.dxw[0]
1484        #return self.smear_type,self.dq_l,self.dq_r
1485   
1486    def _show_smear_sizer(self):
1487        """
1488        Show only the sizers depending on smear selection
1489        """
1490        # smear disabled
1491        if self.disable_smearer.GetValue():
1492            self.smear_description_none.Show(True)
1493        # 2Dsmear
1494        elif self._is_2D():
1495            self.smear_description_accuracy_type.Show(True)
1496            self.smear_accuracy.Show(True)
1497            self.smear_description_accuracy_type.Show(True)
1498            self.smear_description_2d.Show(True)
1499            self.smear_description_2d_x.Show(True)
1500            self.smear_description_2d_y.Show(True)
1501            if self.pinhole_smearer.GetValue():
1502                self.smear_pinhole_min.Show(True)
1503                self.smear_pinhole_max.Show(True)
1504        # smear from data
1505        elif self.enable_smearer.GetValue():
1506
1507            self.smear_description_dqdata.Show(True)
1508            if self.smear_type != None:
1509                self.smear_description_smear_type.Show(True)
1510                if self.smear_type == 'Slit':
1511                    self.smear_description_slit_height.Show(True)
1512                    self.smear_description_slit_width.Show(True)
1513                elif self.smear_type == 'Pinhole':
1514                    self.smear_description_pin_min.Show(True)
1515                    self.smear_description_pin_max.Show(True)
1516                self.smear_description_smear_type.Show(True)
1517                self.smear_description_type.Show(True)
1518                self.smear_data_left.Show(True)
1519                self.smear_data_right.Show(True)
1520        # custom pinhole smear
1521        elif self.pinhole_smearer.GetValue():
1522            if self.smear_type == 'Pinhole':
1523                self.smear_message_new_p.Show(True)
1524                self.smear_description_pin_min.Show(True)
1525                self.smear_description_pin_max.Show(True)
1526
1527            self.smear_pinhole_min.Show(True)
1528            self.smear_pinhole_max.Show(True)
1529        # custom slit smear
1530        elif self.slit_smearer.GetValue():
1531            self.smear_message_new_s.Show(True)
1532            self.smear_description_slit_height.Show(True)
1533            self.smear_slit_height.Show(True)
1534            self.smear_description_slit_width.Show(True)
1535            self.smear_slit_width.Show(True)
1536
1537    def _hide_all_smear_info(self):
1538        """
1539        Hide all smearing messages in the set_smearer sizer
1540        """
1541        self.smear_description_none.Hide()
1542        self.smear_description_dqdata.Hide()
1543        self.smear_description_type.Hide()
1544        self.smear_description_smear_type.Hide()
1545        self.smear_description_accuracy_type.Hide()
1546        self.smear_description_2d_x.Hide()
1547        self.smear_description_2d_y.Hide()
1548        self.smear_description_2d.Hide()
1549       
1550        self.smear_accuracy.Hide()
1551        self.smear_data_left.Hide()
1552        self.smear_data_right.Hide()
1553        self.smear_description_pin_min.Hide()
1554        self.smear_pinhole_min.Hide()
1555        self.smear_description_pin_max.Hide()
1556        self.smear_pinhole_max.Hide()
1557        self.smear_description_slit_height.Hide()
1558        self.smear_slit_height.Hide()
1559        self.smear_description_slit_width.Hide()
1560        self.smear_slit_width.Hide()
1561        self.smear_message_new_p.Hide()
1562        self.smear_message_new_s.Hide()
1563   
1564    def _set_accuracy_list(self):
1565        """
1566        Set the list of an accuracy in 2D custum smear:
1567                Xhigh, High, Med, or Low
1568        """
1569        # list of accuracy choices
1570        list = ['Low', 'Med', 'High', 'Xhigh']
1571        for idx in range(len(list)):
1572            self.smear_accuracy.Append(list[idx], idx)
1573           
1574    def _set_fun_box_list(self, fun_box):
1575        """
1576        Set the list of func for multifunctional models
1577        """
1578        # Check if it is multi_functional model
1579        if self.model.__class__ not in self.model_list_box["Multi-Functions"] \
1580                and not self.temp_multi_functional:
1581            return None
1582        # Get the func name list
1583        list = self.model.fun_list
1584        if len(list) == 0:
1585            return None
1586        # build function (combo)box
1587        ind = 0
1588        while(ind < len(list)):
1589            for key, val in list.iteritems():
1590                if (val == ind):
1591                    fun_box.Append(key, val)
1592                    break
1593            ind += 1
1594       
1595    def _on_select_accuracy(self, event):
1596        """
1597        Select an accuracy in 2D custom smear: Xhigh, High, Med, or Low
1598        """
1599        #event.Skip()
1600        # Check if the accuracy is same as before
1601        #self.smear2d_accuracy = event.GetEventObject().GetValue()
1602        self.smear2d_accuracy = self.smear_accuracy.GetValue()
1603        if self.pinhole_smearer.GetValue():
1604            self.onPinholeSmear(event=None)
1605        else:
1606            self.onSmear(event=None)
1607            if self.current_smearer != None:
1608                self.current_smearer.set_accuracy(accuracy=\
1609                                                  self.smear2d_accuracy) 
1610        event.Skip()
1611
1612    def _on_fun_box(self, event):
1613        """
1614        Select an func: Erf,Rparabola,LParabola
1615        """
1616        fun_val = None
1617        fun_box = event.GetEventObject()
1618        name = fun_box.Name
1619        value = fun_box.GetValue()
1620        if value in self.model.fun_list:
1621            fun_val = self.model.fun_list[value]
1622
1623        self.model.setParam(name, fun_val)
1624        # save state
1625        self._copy_parameters_state(self.str_parameters,
1626                                    self.state.str_parameters)
1627        # update params
1628        self._update_paramv_on_fit()
1629        # draw
1630        self._draw_model()
1631        self.Refresh()
1632        # get ready for new event
1633        event.Skip()
1634       
1635    def _onMask(self, event):
1636        """
1637        Build a panel to allow to edit Mask
1638        """
1639        from sans.guiframe.local_perspectives.plotting.masking \
1640        import MaskPanel as MaskDialog
1641       
1642        self.panel = MaskDialog(base=self, data=self.data, id=wx.NewId())
1643        self.panel.ShowModal()
1644       
1645    def _draw_masked_model(self, event):
1646        """
1647        Draw model image w/mask
1648        """
1649        is_valid_qrange = self._update_paramv_on_fit()
1650
1651        if is_valid_qrange and self.model != None:
1652            self.panel.MakeModal(False)
1653            event.Skip()
1654            # try re draw the model plot if it exists
1655            self._draw_model()
1656            self.set_npts2fit()
1657        elif self.model == None:
1658            self.panel.MakeModal(False)
1659            event.Skip()
1660            self.set_npts2fit()
1661            msg = "No model is found on updating MASK in the model plot... "
1662            wx.PostEvent(self.parent.parent, StatusEvent(status=msg))
1663        else:
1664            event.Skip()
1665            msg = ' Please consider your Q range, too.'
1666            self.panel.ShowMessage(msg)
1667
1668    def _set_smear(self, data):
1669        """
1670        Set_smear
1671        """
1672        if data is None:
1673            return
1674        self.current_smearer = smear_selection(data, self.model)
1675        flag = self.disable_smearer.GetValue()
1676        self.disable_smearer.SetValue(flag)
1677        if self.current_smearer == None:
1678            self.enable_smearer.Disable()
1679        else:
1680            self.enable_smearer.Enable()
1681        if not flag:
1682            self.onSmear(None)
1683
1684    def _mac_sleep(self, sec=0.2):
1685        """
1686        Give sleep to MAC
1687        """
1688        if self.is_mac:
1689            time.sleep(sec)
1690
1691    def get_view_mode(self):
1692        """
1693        return True if the panel allow 2D or False if 1D
1694        """
1695        return self.enable2D
1696   
1697    def compute_data_set_range(self, data_list):
1698        """
1699        find the range that include all data  in the set
1700        return the minimum and the maximum values
1701        """
1702        if data_list is not None and data_list != []:
1703            for data in data_list:
1704                qmin, qmax, npts = self.compute_data_range(data)
1705                self.qmin_data_set = min(self.qmin_data_set, qmin)
1706                self.qmax_data_set = max(self.qmax_data_set, qmax)
1707                self.npts_data_set += npts
1708        return self.qmin_data_set, self.qmax_data_set, self.npts_data_set
1709       
1710    def compute_data_range(self, data):
1711        """
1712        compute the minimum and the maximum range of the data
1713        return the npts contains in data
1714        :param data:
1715        """
1716        qmin, qmax, npts = None, None, None
1717        if data is not None:
1718            if not hasattr(data, "data"):
1719                try:
1720                    qmin = min(data.x)
1721                    # Maximum value of data
1722                    qmax = max(data.x)
1723                    npts = len(data.x)
1724                except:
1725                    msg = "Unable to find min/max/length of \n data named %s"% \
1726                                data.filename 
1727                    wx.PostEvent(self._manager.parent, StatusEvent(status=msg,
1728                                               info="error"))
1729                    raise ValueError, msg
1730                   
1731            else:
1732                qmin = 0
1733                try:
1734                    x = max(math.fabs(data.xmin), math.fabs(data.xmax))
1735                    y = max(math.fabs(data.ymin), math.fabs(data.ymax))
1736                except:
1737                    msg = "Unable to find min/max of \n data named %s"% \
1738                                data.filename 
1739                    wx.PostEvent(self._manager.parent, StatusEvent(status=msg,
1740                                               info="error"))
1741                    raise ValueError, msg
1742                ## Maximum value of data
1743                qmax = math.sqrt(x * x + y * y)
1744                npts = len(data.data)
1745        return qmin, qmax, npts
1746           
1747    def set_data(self, data):
1748        """
1749        reset the current data
1750        """
1751        id = None
1752        flag = False
1753        is_data = False
1754        if self.data is not None:
1755            is_data = check_data_validity(self.data)
1756        if not is_data and data is not None:
1757                flag = True
1758        if data is not None:
1759            id = data.id
1760            if is_data:
1761                self.graph_id = self.data.group_id
1762                flag = (data.id != self.data.id)
1763        self.data = data
1764        if check_data_validity(data):
1765            self.graph_id = data.group_id
1766        self.data.group_id = self.graph_id
1767       
1768        if self.data is None:
1769            data_name = ""
1770            self._set_bookmark_flag(False)
1771            self._keep.Enable(False)
1772            self._set_save_flag(False)
1773        else:
1774            if self.model != None:
1775                self._set_bookmark_flag(not self.batch_on)
1776                self._keep.Enable(not self.batch_on)
1777               
1778            self._set_save_flag(True)
1779            self._set_preview_flag(True)
1780
1781            self._set_smear(data)
1782            # more disables for 2D
1783            if self.data.__class__.__name__ == "Data2D" or \
1784                        self.enable2D:
1785                self.slit_smearer.Disable()
1786                self.pinhole_smearer.Enable(True)
1787                self.default_mask = copy.deepcopy(self.data.mask)
1788                if self.data.err_data == None or\
1789                        (self.data.err_data == 1).all() or\
1790                        (self.data.err_data == 0).all():
1791                    self.dI_didata.Enable(False)
1792                    self.dI_noweight.SetValue(True)
1793                    self.weightbt_string = self.dI_noweight.GetLabelText()
1794                else:
1795                    self.dI_didata.Enable(True)
1796                    self.dI_didata.SetValue(True)
1797                    self.weightbt_string = self.dI_didata.GetLabelText()
1798            else:
1799                self.slit_smearer.Enable(True)
1800                self.pinhole_smearer.Enable(True)
1801                if self.data.dy == None or\
1802                     (self.data.dy == 1).all() or\
1803                     (self.data.dy == 0).all():
1804                    self.dI_didata.Enable(False)
1805                    self.dI_noweight.SetValue(True)
1806                    self.weightbt_string = self.dI_noweight.GetLabelText()
1807                else:
1808                    self.dI_didata.Enable(True)
1809                    self.dI_didata.SetValue(True)
1810                    self.weightbt_string = self.dI_didata.GetLabelText()
1811            # Enable weighting radio uttons
1812            self.dI_noweight.Enable(True)
1813            self.dI_sqrdata.Enable(True)
1814            self.dI_idata.Enable(True)
1815             
1816            self.formfactorbox.Enable()
1817            self.structurebox.Enable()
1818            data_name = self.data.name
1819            _, _, npts = self.compute_data_range(self.data)
1820            #set maximum range for x in linear scale
1821            if not hasattr(self.data, "data"):  # Display only for 1D data fit
1822                self.btEditMask.Disable()
1823                self.EditMask_title.Disable()
1824            else:
1825                self.btEditMask.Enable()
1826                self.EditMask_title.Enable()
1827   
1828        self.Npts_total.SetValue(str(npts))
1829        #default:number of data points selected to fit
1830        self.Npts_fit.SetValue(str(npts))
1831        self.Npts_total.SetEditable(False)
1832        self.Npts_total.SetBackgroundColour(\
1833                                    self.GetParent().GetBackgroundColour())
1834       
1835        self.Npts_total.Bind(wx.EVT_MOUSE_EVENTS, self._npts_click)
1836        self.dataSource.SetValue(data_name)
1837        self.state.data = data
1838        self.enable_fit_button()
1839        # send graph_id to page_finder
1840        self._manager.set_graph_id(uid=self.uid, graph_id=self.graph_id)
1841        #focus the page
1842        if check_data_validity(data):
1843            self.data_box_description.SetForegroundColour(wx.BLUE)
1844       
1845        if self.batch_on:
1846            self.slit_smearer.Enable(False)
1847            self.pinhole_smearer.Enable(False)
1848            self.btEditMask.Disable()
1849            self.EditMask_title.Disable()
1850
1851        self.on_set_focus(None)
1852        self.Refresh()
1853        #update model plot with new data information
1854        if flag:
1855            #set model view button
1856            if not self.enable_smearer.GetValue():
1857                    self.disable_smearer.SetValue(True)
1858            self.onSmear(None)
1859
1860            if self.data.__class__.__name__ == "Data2D":
1861                self.enable2D = True
1862                self.model_view.SetLabel("2D Mode")
1863            else:
1864                self.enable2D = False
1865                self.model_view.SetLabel("1D Mode")
1866            self.model_view.Disable()
1867            #replace data plot on combo box selection
1868            #by removing the previous selected data
1869            #wx.PostEvent(self._manager.parent,
1870            #             NewPlotEvent(action="remove",
1871            #                          group_id=self.graph_id, id=id))
1872            #plot the current selected data
1873            wx.PostEvent(self._manager.parent,
1874                         NewPlotEvent(action="check", plot=self.data,
1875                                      title=str(self.data.title)))
1876            self._draw_model()
1877   
1878    def _npts_click(self, event):
1879        """
1880        Prevent further handling of the mouse event on Npts_total
1881        by not calling Skip().
1882        """
1883        pass
1884   
1885    def reset_page(self, state, first=False):
1886        """
1887        reset the state
1888        """
1889        self.reset_page_helper(state)
1890
1891        self.select_param(event=None)
1892        #Save state_fit
1893        self.save_current_state_fit()
1894        self._lay_out()
1895        self.Refresh()
1896       
1897    def get_range(self):
1898        """
1899        return the fitting range
1900        """
1901        return float(self.qmin_x), float(self.qmax_x)
1902   
1903    def get_npts2fit(self):
1904        """
1905        return numbers of data points within qrange
1906       
1907        :Note: This is for Park where chi2 is not normalized by Npts of fit
1908       
1909        """
1910        if self.data is None:
1911            return
1912        npts2fit = 0
1913        qmin, qmax = self.get_range()
1914        if self.data.__class__.__name__ == "Data2D" or \
1915                        self.enable2D:
1916            radius = numpy.sqrt(self.data.qx_data * self.data.qx_data +
1917                                self.data.qy_data * self.data.qy_data)
1918            index_data = (self.qmin_x <= radius) & (radius <= self.qmax_x)
1919            index_data = (index_data) & (self.data.mask)
1920            index_data = (index_data) & (numpy.isfinite(self.data.data))
1921            npts2fit = len(self.data.data[index_data])
1922        else:
1923            for qx in self.data.x:
1924                if qx >= qmin and qx <= qmax:
1925                    npts2fit += 1
1926        return npts2fit
1927
1928    def set_npts2fit(self):
1929        """
1930        setValue Npts for fitting
1931        """
1932        self.Npts_fit.SetValue(str(self.get_npts2fit()))
1933       
1934    def get_chi2(self):
1935        """
1936        return the current chi2
1937        """
1938        return self.tcChi.GetValue()
1939       
1940    def get_param_list(self):
1941        """
1942        :return self.param_toFit: list containing  references to TextCtrl
1943            checked.Theses TextCtrl will allow reference to parameters to fit.
1944       
1945        :raise: if return an empty list of parameter fit will nnote work
1946            properly so raise ValueError,"missing parameter to fit"
1947        """
1948        if self.param_toFit != []:
1949            return self.param_toFit
1950        else:
1951            msg = "missing parameters to fit"
1952            wx.MessageBox(msg, 'warning')
1953            return False
1954     
1955    def onsetValues(self, chisqr, p_name, out, cov):
1956        """
1957        Build the panel from the fit result
1958       
1959        :param chisqr: Value of the goodness of fit metric
1960        :param p_name: the name of parameters
1961        :param out: list of parameter with the best value found during fitting
1962        :param cov: Covariance matrix
1963   
1964        """
1965        # make sure stop button to fit button all the time
1966        self._on_fit_complete()
1967        if out == None or not numpy.isfinite(chisqr):
1968            raise ValueError, "Fit error occured..."
1969       
1970        is_modified = False
1971        has_error = False
1972        dispersity = ''
1973       
1974        #Hide textctrl boxes of errors.
1975        self._clear_Err_on_Fit()
1976       
1977        #Check if chi2 is finite
1978        if chisqr != None and numpy.isfinite(chisqr):
1979            #format chi2
1980            if self.engine_type == "park":
1981                npt_fit = float(self.get_npts2fit())
1982            chi2 = format_number(chisqr, True)
1983            self.tcChi.SetValue(chi2)
1984            self.tcChi.Refresh()
1985        else:
1986            self.tcChi.SetValue("-")
1987       
1988        #Hide error title
1989        if self.text2_3.IsShown() and not self.is_mac:
1990            self.text2_3.Hide()
1991     
1992        try:
1993            if self.enable_disp.GetValue():
1994                if hasattr(self, "text_disp_1"):
1995                    if self.text_disp_1 != None and not self.is_mac:
1996                        self.text_disp_1.Hide()
1997        except:
1998            dispersity = None
1999            pass
2000     
2001        i = 0
2002        #Set the panel when fit result are list
2003        for item in self.param_toFit:
2004            if len(item) > 5 and item != None:
2005                if item[0].IsShown():
2006                    ## reset error value to initial state
2007                    if not self.is_mac:
2008                        item[3].Hide()
2009                        item[4].Hide()
2010                    for ind in range(len(out)):
2011                        if item[1] == p_name[ind]:
2012                            break
2013                    if len(out) > 0 and out[ind] != None:
2014                        val_out = format_number(out[ind], True)
2015                        item[2].SetValue(val_out)
2016   
2017                    if(cov != None and len(cov) == len(out)):
2018                        try:
2019                            if dispersity != None:
2020                                if self.enable_disp.GetValue():
2021                                    if hasattr(self, "text_disp_1"):
2022                                        if self.text_disp_1 != None:
2023                                            if not self.text_disp_1.IsShown()\
2024                                                and not self.is_mac:
2025                                                self.text_disp_1.Show(True)
2026                        except:
2027                            pass
2028                       
2029                        if cov[ind] != None:
2030                            if numpy.isfinite(float(cov[ind])):
2031                                val_err = format_number(cov[ind], True)
2032                                if not self.is_mac:
2033                                    item[3].Show(True)
2034                                    item[4].Show(True)
2035                                item[4].SetValue(val_err)
2036                                has_error = True
2037                i += 1
2038            else:
2039                raise ValueError, "onsetValues: Invalid parameters..."
2040        #Show error title when any errors displayed
2041        if has_error:
2042            if not self.text2_3.IsShown():
2043                self.text2_3.Show(True)
2044        ## save current state
2045        self.save_current_state()
2046       
2047        if not self.is_mac:
2048            self.Layout()
2049            self.Refresh()
2050        self._mac_sleep(0.1)
2051        #plot model ( when drawing, do not update chisqr value again)
2052        self._draw_model(update_chisqr=False, source='fit')
2053   
2054    def onWeighting(self, event):
2055        """
2056        On Weighting radio button event, sets the weightbt_string
2057        """
2058        self.weightbt_string = event.GetEventObject().GetLabelText()
2059        self._set_weight()
2060       
2061    def _set_weight(self, is_2D=None):
2062        """
2063        Set weight in fit problem
2064        """
2065        # compute weight for the current data
2066        from .utils import get_weight
2067        flag_weight = self.get_weight_flag()
2068        if is_2D == None:
2069            is_2D = self._is_2D()
2070        weight = get_weight(data=self.data,
2071                            is2d=is_2D,
2072                            flag=flag_weight)
2073        self._manager.set_fit_weight(uid=self.uid,
2074                                     flag=flag_weight,
2075                                     is2d=is_2D,
2076                                     fid=None)
2077   
2078    def onPinholeSmear(self, event):
2079        """
2080        Create a custom pinhole smear object that will change the way residuals
2081        are compute when fitting
2082       
2083        :Note: accuracy is given by strings'High','Med', 'Low' FOR 2d,
2084                     None for 1D
2085                     
2086        """
2087        if self.model == None:
2088            self.disable_smearer.SetValue(True)
2089            if event == None:
2090                return
2091            msg = "Please select a Model first..."
2092            wx.MessageBox(msg, 'Info')
2093            wx.PostEvent(self._manager.parent,
2094                         StatusEvent(status="Smear: %s" % msg))
2095            return
2096
2097        # Need update param values
2098        self._update_paramv_on_fit()
2099
2100        # msg default
2101        msg = None
2102        if event != None:
2103            tcrtl = event.GetEventObject()
2104            # event case of radio button
2105            if tcrtl.GetValue() == True:
2106                self.dx_min = 0.0
2107                self.dx_max = 0.0
2108                is_new_pinhole = True
2109            else:
2110                is_new_pinhole = self._is_changed_pinhole()
2111        else:
2112            is_new_pinhole = True
2113        # if any value is changed
2114        if is_new_pinhole:
2115            msg = self._set_pinhole_smear()
2116        # hide all silt sizer
2117        self._hide_all_smear_info()
2118       
2119        # show relevant slit sizers
2120        self._show_smear_sizer()
2121
2122        self.sizer_set_smearer.Layout()
2123        self.Layout()
2124       
2125        if event != None:
2126            event.Skip()
2127        #self._undo.Enable(True)
2128        self.save_current_state()
2129        event = PageInfoEvent(page=self)
2130        wx.PostEvent(self.parent, event)
2131       
2132    def _is_changed_pinhole(self):
2133        """
2134        check if any of pinhole smear is changed
2135       
2136        :return: True or False
2137       
2138        """
2139        # get the values
2140        pin_min = self.smear_pinhole_min.GetValue()
2141        pin_max = self.smear_pinhole_max.GetValue()
2142                   
2143        # Check changes in slit width
2144        try:
2145            dx_min = float(pin_min)
2146        except:
2147            return True
2148        if self.dx_min != dx_min:
2149            return True
2150       
2151        # Check changes in slit heigth
2152        try:
2153            dx_max = float(pin_max)
2154        except:
2155            return True
2156        if self.dx_max != dx_max:
2157            return True
2158        return False
2159   
2160    def _set_pinhole_smear(self):
2161        """
2162        Set custom pinhole smear
2163       
2164        :return: msg
2165       
2166        """
2167        # copy data
2168        data = copy.deepcopy(self.data)
2169        if self._is_2D():
2170            self.smear_type = 'Pinhole2d'
2171            len_data = len(data.data)
2172            data.dqx_data = numpy.zeros(len_data)
2173            data.dqy_data = numpy.zeros(len_data)
2174        else:
2175            self.smear_type = 'Pinhole'
2176            len_data = len(data.x)
2177            data.dx = numpy.zeros(len_data)
2178            data.dxl = None
2179            data.dxw = None
2180        msg = None
2181   
2182        get_pin_min = self.smear_pinhole_min
2183        get_pin_max = self.smear_pinhole_max
2184
2185        if not check_float(get_pin_min):
2186            get_pin_min.SetBackgroundColour("pink")
2187            msg = "Model Error:wrong value entered!!!"
2188        elif not check_float(get_pin_max):
2189            get_pin_max.SetBackgroundColour("pink")
2190            msg = "Model Error:wrong value entered!!!"
2191        else:
2192            if len_data < 2:
2193                len_data = 2
2194            self.dx_min = float(get_pin_min.GetValue())
2195            self.dx_max = float(get_pin_max.GetValue())
2196            if self.dx_min < 0:
2197                get_pin_min.SetBackgroundColour("pink")
2198                msg = "Model Error:This value can not be negative!!!"
2199            elif self.dx_max < 0:
2200                get_pin_max.SetBackgroundColour("pink")
2201                msg = "Model Error:This value can not be negative!!!"
2202            elif self.dx_min != None and self.dx_max != None:
2203                if self._is_2D():
2204                    data.dqx_data[data.dqx_data == 0] = self.dx_min
2205                    data.dqy_data[data.dqy_data == 0] = self.dx_max
2206                elif self.dx_min == self.dx_max:
2207                    data.dx[data.dx == 0] = self.dx_min
2208                else:
2209                    step = (self.dx_max - self.dx_min) / (len_data - 1)
2210                    data.dx = numpy.arange(self.dx_min,
2211                                           self.dx_max + step / 1.1,
2212                                           step)
2213            elif self.dx_min != None:
2214                if self._is_2D():
2215                    data.dqx_data[data.dqx_data == 0] = self.dx_min
2216                else:
2217                    data.dx[data.dx == 0] = self.dx_min
2218            elif self.dx_max != None:
2219                if self._is_2D():
2220                    data.dqy_data[data.dqy_data == 0] = self.dx_max
2221                else:
2222                    data.dx[data.dx == 0] = self.dx_max
2223            self.current_smearer = smear_selection(data, self.model)
2224            # 2D need to set accuracy
2225            if self._is_2D():
2226                self.current_smearer.set_accuracy(accuracy=\
2227                                                  self.smear2d_accuracy)
2228
2229        if msg != None:
2230            wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
2231        else:
2232            get_pin_min.SetBackgroundColour("white")
2233            get_pin_max.SetBackgroundColour("white")
2234        ## set smearing value whether or not the data contain the smearing info
2235       
2236        self._manager.set_smearer(smearer=self.current_smearer,
2237                            fid=self.data.id,
2238                            qmin=float(self.qmin_x),
2239                            qmax=float(self.qmax_x),
2240                            enable_smearer=not self.disable_smearer.GetValue(),
2241                            uid=self.uid)
2242        return msg
2243       
2244    def update_pinhole_smear(self):
2245        """
2246        called by kill_focus on pinhole TextCntrl
2247        to update the changes
2248       
2249        :return: False when wrong value was entered
2250       
2251        """
2252        # msg default
2253        msg = None
2254        # check if any value is changed
2255        if self._is_changed_pinhole():
2256            msg = self._set_pinhole_smear()
2257        wx.CallAfter(self.save_current_state)
2258
2259        if msg != None:
2260            return False
2261        else:
2262            return True
2263                     
2264    def onSlitSmear(self, event):
2265        """
2266        Create a custom slit smear object that will change the way residuals
2267        are compute when fitting
2268        """
2269        if self.model == None:
2270            self.disable_smearer.SetValue(True)
2271            if event == None:
2272                return
2273            msg = "Please select a Model first..."
2274            wx.MessageBox(msg, 'Info')
2275            wx.PostEvent(self._manager.parent,
2276                         StatusEvent(status="Smear: %s" % msg))
2277            return
2278
2279        # Need update param values
2280        self._update_paramv_on_fit()
2281
2282        # msg default
2283        msg = None
2284        # for event given
2285        if event != None:
2286            tcrtl = event.GetEventObject()
2287            # event case of radio button
2288            if tcrtl.GetValue():
2289                self.dxl = 0.0
2290                self.dxw = 0.0
2291                is_new_slit = True
2292            else:
2293                is_new_slit = self._is_changed_slit()
2294        else:
2295            is_new_slit = True
2296       
2297        # if any value is changed
2298        if is_new_slit:
2299            msg = self._set_slit_smear()
2300           
2301        # hide all silt sizer
2302        self._hide_all_smear_info()
2303        # show relevant slit sizers
2304        self._show_smear_sizer()
2305        self.sizer_set_smearer.Layout()
2306        self.Layout()
2307
2308        if event != None:
2309            event.Skip()
2310        self.save_current_state()
2311        event = PageInfoEvent(page=self)
2312        wx.PostEvent(self.parent, event)
2313        if msg != None:
2314            wx.PostEvent(self._manager.parent, StatusEvent(status=msg))
2315
2316    def _is_changed_slit(self):
2317        """
2318        check if any of slit lengths is changed
2319       
2320        :return: True or False
2321       
2322        """
2323        # get the values
2324        width = self.smear_slit_width.GetValue()
2325        height = self.smear_slit_height.GetValue()
2326       
2327        # check and change the box bg color if it was pink
2328        #    but it should be white now
2329        # because this is the case that _set_slit_smear() will not handle
2330        if height.lstrip().rstrip() == "":
2331            self.smear_slit_height.SetBackgroundColour(wx.WHITE)
2332        if width.lstrip().rstrip() == "":
2333            self.smear_slit_width.SetBackgroundColour(wx.WHITE)
2334           
2335        # Check changes in slit width
2336        if width == "":
2337            dxw = 0.0
2338        else:
2339            try:
2340                dxw = float(width)
2341            except:
2342                return True
2343        if self.dxw != dxw:
2344            return True
2345       
2346        # Check changes in slit heigth
2347        if height == "":
2348            dxl = 0.0
2349        else:
2350            try:
2351                dxl = float(height)
2352            except:
2353                return True
2354        if self.dxl != dxl:
2355            return True
2356
2357        return False
2358   
2359    def _set_slit_smear(self):
2360        """
2361        Set custom slit smear
2362       
2363        :return: message to inform the user about the validity
2364            of the values entered for slit smear
2365        """
2366        if self.data.__class__.__name__ == "Data2D" or \
2367                        self.enable2D:
2368            return
2369        # make sure once more if it is smearer
2370        data = copy.deepcopy(self.data)
2371        data_len = len(data.x)
2372        data.dx = None
2373        data.dxl = None
2374        data.dxw = None
2375        msg = None
2376   
2377        try:
2378            self.dxl = float(self.smear_slit_height.GetValue())
2379            data.dxl = self.dxl * numpy.ones(data_len)
2380            self.smear_slit_height.SetBackgroundColour(wx.WHITE)
2381        except:
2382            data.dxl = numpy.zeros(data_len)
2383            if self.smear_slit_height.GetValue().lstrip().rstrip() != "":
2384                self.smear_slit_height.SetBackgroundColour("pink")
2385                msg = "Wrong value entered... "
2386            else:
2387                self.smear_slit_height.SetBackgroundColour(wx.WHITE)
2388        try:
2389            self.dxw = float(self.smear_slit_width.GetValue())
2390            self.smear_slit_width.SetBackgroundColour(wx.WHITE)
2391            data.dxw = self.dxw * numpy.ones(data_len)
2392        except:
2393            data.dxw = numpy.zeros(data_len)
2394            if self.smear_slit_width.GetValue().lstrip().rstrip() != "":
2395                self.smear_slit_width.SetBackgroundColour("pink")
2396                msg = "Wrong Fit value entered... "
2397            else:
2398                self.smear_slit_width.SetBackgroundColour(wx.WHITE)
2399             
2400        self.current_smearer = smear_selection(data, self.model)
2401        ## set smearing value whether or not the data contain the smearing info
2402        self._manager.set_smearer(smearer=self.current_smearer,
2403                                 fid=self.data.id,
2404                                 qmin=float(self.qmin_x),
2405                                 qmax=float(self.qmax_x),
2406                        enable_smearer=not self.disable_smearer.GetValue(),
2407                                 uid=self.uid)
2408        return msg
2409   
2410    def update_slit_smear(self):
2411        """
2412        called by kill_focus on pinhole TextCntrl
2413        to update the changes
2414       
2415        :return: False when wrong value was entered
2416       
2417        """
2418        # msg default
2419        msg = None
2420        # check if any value is changed
2421        if self._is_changed_slit():
2422            msg = self._set_slit_smear()
2423        #self._undo.Enable(True)
2424        self.save_current_state()
2425
2426        if msg != None:
2427            return False
2428        else:
2429            return True
2430                           
2431    def onSmear(self, event):
2432        """
2433        Create a smear object that will change the way residuals
2434        are compute when fitting
2435        """
2436        if event != None:
2437            event.Skip()
2438        if self.data is None:
2439            return
2440
2441        if self.model == None:
2442            self.disable_smearer.SetValue(True)
2443            if event == None:
2444                return
2445            msg = "Please select a Model first..."
2446            wx.MessageBox(msg, 'Info')
2447            wx.PostEvent(self._manager.parent,
2448                         StatusEvent(status="Smear: %s" % msg))
2449            return
2450        # Need update param values
2451        self._update_paramv_on_fit()
2452        if self.model != None:
2453            if self.data.is_data:
2454                self._manager.page_finder[self.uid].add_data(data=self.data)
2455        temp_smearer = self.on_smear_helper()
2456       
2457        self.sizer_set_smearer.Layout()
2458        self.Layout()
2459        self._set_weight()
2460       
2461        ## set smearing value whether or not the data contain the smearing info
2462        wx.CallAfter(self._manager.set_smearer, uid=self.uid,
2463                     smearer=temp_smearer,
2464                     fid=self.data.id,
2465                     qmin=float(self.qmin_x),
2466                     qmax=float(self.qmax_x),
2467                     enable_smearer=not self.disable_smearer.GetValue(),
2468                     draw=True)
2469       
2470        self.state.enable_smearer = self.enable_smearer.GetValue()
2471        self.state.disable_smearer = self.disable_smearer.GetValue()
2472        self.state.pinhole_smearer = self.pinhole_smearer.GetValue()
2473        self.state.slit_smearer = self.slit_smearer.GetValue()
2474       
2475    def on_smear_helper(self, update=False):
2476        """
2477        Help for onSmear
2478       
2479        :param update: force or not to update
2480        """
2481        self._get_smear_info()
2482        #renew smear sizer
2483        if self.smear_type != None:
2484            self.smear_description_smear_type.SetValue(str(self.smear_type))
2485            self.smear_data_left.SetValue(str(self.dq_l))
2486            self.smear_data_right.SetValue(str(self.dq_r))
2487
2488        self._hide_all_smear_info()
2489        data = copy.deepcopy(self.data)
2490       
2491        # make sure once more if it is smearer
2492        temp_smearer = smear_selection(data, self.model)
2493        if self.current_smearer != temp_smearer or update:
2494            self.current_smearer = temp_smearer
2495        if self.enable_smearer.GetValue():
2496            if self.current_smearer == None:
2497                wx.PostEvent(self._manager.parent,
2498                    StatusEvent(status="Data contains no smearing information"))
2499            else:
2500                wx.PostEvent(self._manager.parent,
2501                    StatusEvent(status="Data contains smearing information"))
2502
2503            self.smear_data_left.Show(True)
2504            self.smear_data_right.Show(True)
2505            temp_smearer = self.current_smearer
2506        elif self.disable_smearer.GetValue():
2507            self.smear_description_none.Show(True)
2508        elif self.pinhole_smearer.GetValue():
2509            self.onPinholeSmear(None)
2510        elif self.slit_smearer.GetValue():
2511            self.onSlitSmear(None)
2512        self._show_smear_sizer()
2513       
2514        return temp_smearer
2515   
2516    def on_complete_chisqr(self, event):
2517        """
2518        Display result chisqr on the panel
2519        :event: activated by fitting/ complete after draw
2520        """
2521        try:
2522            if event == None:
2523                output = "-"
2524            elif not numpy.isfinite(event.output):
2525                output = "-"
2526            else:
2527                output = event.output
2528            self.tcChi.SetValue(str(format_number(output, True)))
2529            self.state.tcChi = self.tcChi.GetValue()
2530        except:
2531            pass
2532           
2533    def get_all_checked_params(self):
2534        """
2535        Found all parameters current check and add them to list of parameters
2536        to fit
2537        """
2538        self.param_toFit = []
2539        for item in self.parameters:
2540            if item[0].GetValue() and item not in self.param_toFit:
2541                if item[0].IsShown():
2542                    self.param_toFit.append(item)
2543        for item in self.fittable_param:
2544            if item[0].GetValue() and item not in self.param_toFit:
2545                if item[0].IsShown():
2546                    self.param_toFit.append(item)
2547        self.save_current_state_fit()
2548       
2549        event = PageInfoEvent(page=self)
2550        wx.PostEvent(self.parent, event)
2551        param2fit = []
2552        for item in self.param_toFit:
2553            if item[0] and item[0].IsShown():
2554                param2fit.append(item[1])
2555        self.parent._manager.set_param2fit(self.uid, param2fit)
2556               
2557    def select_all_param(self, event):
2558        """
2559        set to true or false all checkBox given the main checkbox value cb1
2560        """
2561        self.param_toFit = []
2562        if  self.parameters != []:
2563            if  self.cb1.GetValue():
2564                for item in self.parameters:
2565                    if item[0].IsShown():
2566                        ## for data2D select all to fit
2567                        if self.data.__class__.__name__ == "Data2D" or \
2568                                self.enable2D:
2569                            item[0].SetValue(True)
2570                            self.param_toFit.append(item)
2571                        else:
2572                            ## for 1D all parameters except orientation
2573                            if not item in self.orientation_params:
2574                                item[0].SetValue(True)
2575                                self.param_toFit.append(item)
2576                    else:
2577                        item[0].SetValue(False)
2578                #if len(self.fittable_param)>0:
2579                for item in self.fittable_param:
2580                    if item[0].IsShown():
2581                        if self.data.__class__.__name__ == "Data2D" or \
2582                                self.enable2D:
2583                            item[0].SetValue(True)
2584                            self.param_toFit.append(item)
2585                            try:
2586                                if len(self.values[item[1]]) > 0:
2587                                    item[0].SetValue(False)
2588                            except:
2589                                pass
2590   
2591                        else:
2592                            ## for 1D all parameters except orientation
2593                            if not item in self.orientation_params_disp:
2594                                item[0].SetValue(True)
2595                                self.param_toFit.append(item)
2596                                try:
2597                                    if len(self.values[item[1]]) > 0:
2598                                        item[0].SetValue(False)
2599                                except:
2600                                    pass
2601                    else:
2602                        item[0].SetValue(False)
2603
2604            else:
2605                for item in self.parameters:
2606                    item[0].SetValue(False)
2607                for item in self.fittable_param:
2608                    item[0].SetValue(False)
2609                self.param_toFit = []
2610           
2611        self.save_current_state_fit()
2612       
2613        if event != None:
2614            #self._undo.Enable(True)
2615            ## post state to fit panel
2616            event = PageInfoEvent(page=self)
2617            wx.PostEvent(self.parent, event)
2618        param2fit = []
2619        for item in self.param_toFit:
2620            if item[0] and item[0].IsShown():
2621                param2fit.append(item[1])
2622        self.parent._manager.set_param2fit(self.uid, param2fit)
2623
2624    def select_param(self, event):
2625        """
2626        Select TextCtrl  checked for fitting purpose and stores them
2627        in  self.param_toFit=[] list
2628        """
2629        self.param_toFit = []
2630        for item in self.parameters:
2631            #Skip t ifhe angle parameters if 1D data
2632            if self.data.__class__.__name__ != "Data2D" and\
2633                        not self.enable2D:
2634                if item in self.orientation_params:
2635                    continue
2636            #Select parameters to fit for list of primary parameters
2637            if item[0].GetValue() and item[0].IsShown():
2638                if not (item in self.param_toFit):
2639                    self.param_toFit.append(item)
2640            else:
2641                #remove parameters from the fitting list
2642                if item in self.param_toFit:
2643                    self.param_toFit.remove(item)
2644
2645        #Select parameters to fit for list of fittable parameters
2646        #        with dispersion
2647        for item in self.fittable_param:
2648            #Skip t ifhe angle parameters if 1D data
2649            if self.data.__class__.__name__ != "Data2D" and\
2650                        not self.enable2D:
2651                if item in self.orientation_params:
2652                    continue
2653            if item[0].GetValue() and item[0].IsShown():
2654                if not (item in self.param_toFit):
2655                    self.param_toFit.append(item)
2656            else:
2657                #remove parameters from the fitting list
2658                if item in self.param_toFit:
2659                    self.param_toFit.remove(item)
2660
2661        #Calculate num. of angle parameters
2662        if self.data.__class__.__name__ == "Data2D" or \
2663                       self.enable2D:
2664            len_orient_para = 0
2665        else:
2666            len_orient_para = len(self.orientation_params)  # assume even len
2667        #Total num. of angle parameters
2668        if len(self.fittable_param) > 0:
2669            len_orient_para *= 2
2670        #Set the value of checkbox that selected every checkbox or not
2671        if len(self.parameters) + len(self.fittable_param) - len_orient_para \
2672            == len(self.param_toFit):
2673            self.cb1.SetValue(True)
2674        else:
2675            self.cb1.SetValue(False)
2676       
2677        self.save_current_state_fit()
2678        if event != None:
2679            ## post state to fit panel
2680            event = PageInfoEvent(page=self)
2681            wx.PostEvent(self.parent, event)
2682       
2683        param2fit = []
2684        for item in self.param_toFit:
2685            if item[0] and item[0].IsShown():
2686                param2fit.append(item[1])
2687        self.parent._manager.set_param2fit(self.uid, param2fit)
2688       
2689    def set_model_param_sizer(self, model):
2690        """
2691        Build the panel from the model content
2692       
2693        :param model: the model selected in combo box for fitting purpose
2694       
2695        """
2696        self.sizer3.Clear(True)
2697        self.parameters = []
2698        self.str_parameters = []
2699        self.param_toFit = []
2700        self.fittable_param = []
2701        self.fixed_param = []
2702        self.orientation_params = []
2703        self.orientation_params_disp = []
2704       
2705        if model == None:
2706            self.sizer3.Layout()
2707            self.SetupScrolling()
2708            return
2709        ## the panel is drawn using the current value of the fit engine
2710        if self.engine_type == None and self._manager != None:
2711            self.engine_type = self._manager._return_engine_type()
2712
2713        box_description = wx.StaticBox(self, -1, str("Model Parameters"))
2714        boxsizer1 = wx.StaticBoxSizer(box_description, wx.VERTICAL)
2715        sizer = wx.GridBagSizer(5, 5)
2716        ## save the current model
2717        self.model = model
2718           
2719        keys = self.model.getParamList()
2720        #list of dispersion paramaters
2721        self.disp_list = self.model.getDispParamList()
2722
2723        def custom_compare(a, b):
2724            """
2725            Custom compare to order, first by alphabets then second by number.
2726            """
2727            # number at the last digit
2728            a_last = a[len(a) - 1]
2729            b_last = b[len(b) - 1]
2730            # default
2731            num_a = None
2732            num_b = None
2733            # split the names
2734            a2 = a.lower().split('_')
2735            b2 = b.lower().split('_')
2736            # check length of a2, b2
2737            len_a2 = len(a2)
2738            len_b2 = len(b2)
2739            # check if it contains a int number(<10)
2740            try:
2741                num_a = int(a_last)
2742            except:
2743                pass
2744            try:
2745                num_b = int(b_last)
2746            except:
2747                pass
2748            # Put 'scale' near the top; happens
2749            # when numbered param name exists
2750            if a == 'scale':
2751                return -1
2752            # both have a number
2753            if num_a != None and num_b != None:
2754                if num_a > num_b:
2755                    return -1
2756                # same number
2757                elif num_a == num_b:
2758                    # different last names
2759                    if a2[len_a2 - 1] != b2[len_b2 - 1] and num_a != 0:
2760                        return -cmp(a2[len_a2 - 1], b2[len_b2 - 1])
2761                    else:
2762                        return cmp(a, b)
2763                else:
2764                    return 1
2765            # one of them has a number
2766            elif num_a != None:
2767                return 1
2768            elif num_b != None:
2769                return -1
2770            # no numbers
2771            else:
2772                return cmp(a.lower(), b.lower())
2773
2774        keys.sort(custom_compare)
2775   
2776        iy = 0
2777        ix = 0
2778        select_text = "Select All"
2779        self.cb1 = wx.CheckBox(self, -1, str(select_text), (10, 10))
2780        wx.EVT_CHECKBOX(self, self.cb1.GetId(), self.select_all_param)
2781        self.cb1.SetToolTipString("To check/uncheck all the boxes below.")
2782        self.cb1.SetValue(True)
2783       
2784        sizer.Add(self.cb1, (iy, ix), (1, 1), \
2785                             wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 5)
2786        ix += 1
2787        self.text2_2 = wx.StaticText(self, -1, 'Value')
2788        sizer.Add(self.text2_2, (iy, ix), (1, 1), \
2789                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2790        ix += 2
2791        self.text2_3 = wx.StaticText(self, -1, 'Error')
2792        sizer.Add(self.text2_3, (iy, ix), (1, 1), \
2793                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2794        if not self.is_mac:
2795            self.text2_3.Hide()
2796        ix += 1
2797        self.text2_min = wx.StaticText(self, -1, 'Min')
2798        sizer.Add(self.text2_min, (iy, ix), (1, 1), \
2799                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2800        #self.text2_min.Hide()
2801        ix += 1
2802        self.text2_max = wx.StaticText(self, -1, 'Max')
2803        sizer.Add(self.text2_max, (iy, ix), (1, 1), \
2804                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2805        #self.text2_max.Hide()
2806        ix += 1
2807        self.text2_4 = wx.StaticText(self, -1, '[Units]')
2808        sizer.Add(self.text2_4, (iy, ix), (1, 1), \
2809                            wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2810        self.text2_4.Hide()
2811       
2812        CHECK_STATE = self.cb1.GetValue()
2813        for item in keys:
2814            if not item in self.disp_list and not item in \
2815                    self.model.orientation_params:
2816               
2817                ##prepare a spot to store errors
2818                if not item in self.model.details:
2819                    self.model.details[item] = ["", None, None]
2820         
2821                iy += 1
2822                ix = 0
2823                if (self.model.__class__ in \
2824                    self.model_list_box["Multi-Functions"] or \
2825                    self.temp_multi_functional)\
2826                    and (item in self.model.non_fittable):
2827                    non_fittable_name = wx.StaticText(self, -1, item)
2828                    sizer.Add(non_fittable_name, (iy, ix), (1, 1), \
2829                            wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 21)
2830                    ## add parameter value
2831                    ix += 1
2832                    value = self.model.getParam(item)
2833                    if len(self.model.fun_list) > 0:
2834                        #num = item.split('_')[1][5:7]
2835                        fun_box = wx.ComboBox(self, -1, size=(100, -1),
2836                                    style=wx.CB_READONLY, name='%s' % item)
2837                        self._set_fun_box_list(fun_box)
2838                        fun_box.SetSelection(0)
2839                        #self.fun_box.SetToolTipString("A function
2840                        #    describing the interface")
2841                        wx.EVT_COMBOBOX(fun_box, -1, self._on_fun_box)
2842                    else:
2843                        fun_box = self.ModelTextCtrl(self, -1,
2844                                                     size=(_BOX_WIDTH, 20),
2845                                style=wx.TE_PROCESS_ENTER, name='%s' % item)
2846                        fun_box.SetToolTipString(\
2847                                "Hit 'Enter' after typing to update the plot.")
2848                        fun_box.SetValue(format_number(value, True))
2849                    sizer.Add(fun_box, (iy, ix), (1, 1), wx.EXPAND)
2850                    self.str_parameters.append([None, item, fun_box,
2851                                                None, None, None,
2852                                                None, None])
2853                else:
2854                    ## add parameters name with checkbox for selecting to fit
2855                    cb = wx.CheckBox(self, -1, item)
2856                    cb.SetValue(CHECK_STATE)
2857                    cb.SetToolTipString(" Check mark to fit.")
2858                    #cb.SetValue(True)
2859                    wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
2860                   
2861                    sizer.Add(cb, (iy, ix), (1, 1),
2862                              wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 5)
2863
2864                    ## add parameter value
2865                    ix += 1
2866                    value = self.model.getParam(item)
2867                    ctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
2868                                        style=wx.TE_PROCESS_ENTER)
2869                    ctl1.SetToolTipString(\
2870                                "Hit 'Enter' after typing to update the plot.")
2871                    ctl1.SetValue(format_number(value, True))
2872                    sizer.Add(ctl1, (iy, ix), (1, 1), wx.EXPAND)
2873                    ## text to show error sign
2874                    ix += 1
2875                    text2 = wx.StaticText(self, -1, '+/-')
2876                    sizer.Add(text2, (iy, ix), (1, 1), \
2877                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2878                    if not self.is_mac:
2879                        text2.Hide()
2880                    ix += 1
2881                    ctl2 = wx.TextCtrl(self, -1,
2882                                       size=(_BOX_WIDTH / 1.2, 20), style=0)
2883                    sizer.Add(ctl2, (iy, ix), (1, 1),
2884                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2885                    if not self.is_mac:
2886                        ctl2.Hide()
2887                   
2888                    ix += 1
2889                    ctl3 = self.ModelTextCtrl(self, -1,
2890                                              size=(_BOX_WIDTH / 1.9, 20),
2891                                              style=wx.TE_PROCESS_ENTER,
2892                                text_enter_callback=self._onparamRangeEnter)
2893         
2894                    sizer.Add(ctl3, (iy, ix), (1, 1),
2895                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2896           
2897                    ix += 1
2898                    ctl4 = self.ModelTextCtrl(self, -1,
2899                                              size=(_BOX_WIDTH / 1.9, 20),
2900                                              style=wx.TE_PROCESS_ENTER,
2901                                text_enter_callback=self._onparamRangeEnter)
2902                    sizer.Add(ctl4, (iy, ix), (1, 1),
2903                              wx.EXPAND | wx.FIXED_MINSIZE, 0)
2904   
2905                    ix += 1
2906                    # Units
2907                    if item in self.model.details:
2908                        units = wx.StaticText(self, -1,
2909                            self.model.details[item][0], style=wx.ALIGN_LEFT)
2910                    else:
2911                        units = wx.StaticText(self, -1, "",
2912                                              style=wx.ALIGN_LEFT)
2913                    sizer.Add(units, (iy, ix), (1, 1),
2914                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2915                       
2916                    self.parameters.append([cb, item, ctl1,
2917                                            text2, ctl2, ctl3, ctl4, units])
2918                                 
2919        iy += 1
2920        sizer.Add((10, 10), (iy, ix), (1, 1),
2921                  wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
2922       
2923        # type can be either Guassian or Array
2924        if len(self.model.dispersion.values()) > 0:
2925            type = self.model.dispersion.values()[0]["type"]
2926        else:
2927            type = "Gaussian"
2928           
2929        iy += 1
2930        ix = 0
2931        #Add tile for orientational angle
2932        for item in keys:
2933            if item in self.model.orientation_params:
2934                orient_angle = wx.StaticText(self, -1, '[For 2D only]:')
2935                sizer.Add(orient_angle, (iy, ix), (1, 1),
2936                          wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
2937                if not self.data.__class__.__name__ == "Data2D" and \
2938                        not self.enable2D:
2939                    orient_angle.Hide()
2940                else:
2941                    orient_angle.Show(True)
2942                break
2943     
2944        #For Gaussian only
2945        if type.lower() != "array":
2946            for item in self.model.orientation_params:
2947                if not item in self.disp_list:
2948                    ##prepare a spot to store min max
2949                    if not item in self.model.details:
2950                        self.model.details[item] = ["", None, None]
2951                         
2952                    iy += 1
2953                    ix = 0
2954                    ## add parameters name with checkbox for selecting to fit
2955                    cb = wx.CheckBox(self, -1, item)
2956                    cb.SetValue(CHECK_STATE)
2957                    cb.SetToolTipString("Check mark to fit")
2958                    wx.EVT_CHECKBOX(self, cb.GetId(), self.select_param)
2959                    if self.data.__class__.__name__ == "Data2D" or \
2960                            self.enable2D:
2961                        cb.Show(True)
2962                    else:
2963                        cb.Hide()
2964                    sizer.Add(cb, (iy, ix), (1, 1),
2965                              wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 5)
2966   
2967                    ## add parameter value
2968                    ix += 1
2969                    value = self.model.getParam(item)
2970                    ctl1 = self.ModelTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
2971                                        style=wx.TE_PROCESS_ENTER)
2972                    ctl1.SetToolTipString(\
2973                                "Hit 'Enter' after typing to update the plot.")
2974                    ctl1.SetValue(format_number(value, True))
2975                    if self.data.__class__.__name__ == "Data2D" or \
2976                            self.enable2D:
2977                        ctl1.Show(True)
2978                    else:
2979                        ctl1.Hide()
2980                    sizer.Add(ctl1, (iy, ix), (1, 1), wx.EXPAND)
2981                    ## text to show error sign
2982                    ix += 1
2983                    text2 = wx.StaticText(self, -1, '+/-')
2984                    sizer.Add(text2, (iy, ix), (1, 1), \
2985                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2986
2987                    text2.Hide()
2988                    ix += 1
2989                    ctl2 = wx.TextCtrl(self, -1,
2990                                       size=(_BOX_WIDTH / 1.2, 20), style=0)
2991                    sizer.Add(ctl2, (iy, ix), (1, 1),
2992                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
2993
2994                    ctl2.Hide()
2995                   
2996                    ix += 1
2997                    ctl3 = self.ModelTextCtrl(self, -1,
2998                                              size=(_BOX_WIDTH / 1.8, 20),
2999                                              style=wx.TE_PROCESS_ENTER,
3000                                text_enter_callback=self._onparamRangeEnter)
3001                   
3002                    sizer.Add(ctl3, (iy, ix), (1, 1),
3003                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
3004                    ctl3.Hide()
3005                 
3006                    ix += 1
3007                    ctl4 = self.ModelTextCtrl(self, -1,
3008                                              size=(_BOX_WIDTH / 1.8, 20),
3009                                              style=wx.TE_PROCESS_ENTER,
3010                            text_enter_callback=self._onparamRangeEnter)
3011                    sizer.Add(ctl4, (iy, ix), (1, 1),
3012                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
3013                   
3014                    ctl4.Hide()
3015                   
3016                    if self.data.__class__.__name__ == "Data2D" or \
3017                            self.enable2D:
3018                        if self.is_mac:
3019                            text2.Show(True)
3020                            ctl2.Show(True)
3021                        ctl3.Show(True)
3022                        ctl4.Show(True)
3023                   
3024                    ix += 1
3025                    # Units
3026                    if item in self.model.details:
3027                        units = wx.StaticText(self, -1,
3028                                              self.model.details[item][0],
3029                                              style=wx.ALIGN_LEFT)
3030                    else:
3031                        units = wx.StaticText(self, -1, "",
3032                                              style=wx.ALIGN_LEFT)
3033                    if self.data.__class__.__name__ == "Data2D" or \
3034                            self.enable2D:
3035                        units.Show(True)
3036                    else:
3037                        units.Hide()
3038                   
3039                    sizer.Add(units, (iy, ix), (1, 1),
3040                              wx.EXPAND | wx.ADJUST_MINSIZE, 0)
3041                                         
3042                    self.parameters.append([cb, item, ctl1,
3043                                            text2, ctl2, ctl3, ctl4, units])
3044                    self.orientation_params.append([cb, item, ctl1,
3045                                            text2, ctl2, ctl3, ctl4, units])
3046             
3047        iy += 1
3048        box_description.SetForegroundColour(wx.BLUE)
3049        #Display units text on panel
3050        for item in keys:
3051            if item in self.model.details:
3052                self.text2_4.Show()
3053        #Fill the list of fittable parameters
3054        self.get_all_checked_params()
3055        self.save_current_state_fit()
3056        boxsizer1.Add(sizer)
3057        self.sizer3.Add(boxsizer1, 0, wx.EXPAND | wx.ALL, 10)
3058        self.sizer3.Layout()
3059        self.Layout()
3060
3061    def on_right_down(self, event):
3062        """
3063        Get key stroke event
3064        """
3065        if self.data == None:
3066            return
3067        # Figuring out key combo: Cmd for copy, Alt for paste
3068        if event.AltDown() and event.ShiftDown():
3069            self._manager.show_ftol_dialog()
3070            flag = True
3071        elif event.AltDown() or event.ShiftDown():
3072            flag = False
3073        else:
3074            return
3075        # make event free
3076        event.Skip()
3077        # messages depending on the flag
3078        if not flag:
3079            msg = " Could not open ftol dialog;"
3080            msg += " Check if the Scipy fit engine is selected in the menubar."
3081            infor = 'warning'
3082            # inform msg to wx
3083            wx.PostEvent(self.parent.parent,
3084                        StatusEvent(status=msg, info=infor))
3085       
3086    def _onModel2D(self, event):
3087        """
3088        toggle view of model from 1D to 2D  or 2D from 1D
3089        """
3090        if self.model_view.GetLabelText() == "Show 2D":
3091            self.model_view.SetLabel("Show 1D")
3092            self.enable2D = True
3093             
3094        else:
3095            self.model_view.SetLabel("Show 2D")
3096            self.enable2D = False
3097        self.Show(False)
3098        self.create_default_data()
3099        self._manager.store_data(self.uid, data_list=[self.data])
3100
3101        self.set_model_param_sizer(self.model)
3102        self._set_sizer_dispersion()
3103        self._set_weight(is_2D=self.enable2D)
3104        self._set_smear_buttons()
3105        self.Show(True)
3106        self.SetupScrolling()
3107        self._draw_model()
3108       
3109        self.state.enable2D = copy.deepcopy(self.enable2D)
3110   
3111    def _set_smear_buttons(self):
3112        """
3113        Set semarer radio buttons
3114        """
3115        # more disables for 2D
3116        if self.data.__class__.__name__ == "Data2D" or \
3117                    self.enable2D:
3118            self.slit_smearer.Disable()
3119            self.pinhole_smearer.Enable(True)
3120            self.default_mask = copy.deepcopy(self.data.mask)
3121        else:
3122            self.slit_smearer.Enable(True)
3123            self.pinhole_smearer.Enable(True)
3124           
3125           
3126class BGTextCtrl(wx.TextCtrl):
3127    """
3128    Text control used to display outputs.
3129    No editing allowed. The background is
3130    grayed out. User can't select text.
3131    """
3132    def __init__(self, *args, **kwds):
3133        wx.TextCtrl.__init__(self, *args, **kwds)
3134        self.SetEditable(False)
3135        self.SetBackgroundColour(self.GetParent().parent.GetBackgroundColour())
3136       
3137        # Bind to mouse event to avoid text highlighting
3138        # The event will be skipped once the call-back
3139        # is called.
3140        self.Bind(wx.EVT_MOUSE_EVENTS, self._click)
3141       
3142    def _click(self, event):
3143        """
3144        Prevent further handling of the mouse event
3145        by not calling Skip().
3146        """
3147        pass
Note: See TracBrowser for help on using the repository browser.