source: sasview/src/sans/perspectives/fitting/fitpage.py @ 1ce36f37

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 1ce36f37 was 5777106, checked in by Mathieu Doucet <doucetm@…>, 11 years ago

Moving things around. Will definitely not build.

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