source: sasview/src/sas/perspectives/fitting/fitpage.py @ 682c432

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 682c432 was 682c432, checked in by krzywon, 9 years ago

Fixed the focus bug associated with #275 where focus wasn't being set on
the fitting pages. Made some cahnges to the cansas reader to be more
explicit and (attempt to) lower the pylint scores.

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