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

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

Added polarization and magnetic stuffs

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