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

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

more fix on 2D smear + mask

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