source: sasview/invariantview/perspectives/invariant/invariant_panel.py @ b5a21aa

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 b5a21aa was 4e1c362, checked in by Jae Cho <jhjcho@…>, 14 years ago

Invariant: undo, redo, bookmark, and saving works now: needs plottool fix for making right order on plotting from file: also need some cleaning-up and doc.

  • Property mode set to 100644
File size: 72.4 KB
RevLine 
[c128284]1"""
[d7a39e5]2This module provide GUI for the neutron scattering length density calculator
3
[c128284]4"""
5
6import wx
7
[4e1c362]8import sys,os
[9abec44]9from wx.lib.scrolledpanel import ScrolledPanel
[272d91e]10from sans.invariant import invariant
[c128284]11from sans.guiframe.utils import format_number, check_float
12from sans.guicomm.events import NewPlotEvent, StatusEvent
[d0cc0bbc]13from invariant_details import InvariantDetailsPanel, InvariantContainer
[518d35d]14from invariant_widgets import OutputTextCtrl, InvTextCtrl
[4e1c362]15from invariant_state import InvariantState as IState
16import copy,time
[c128284]17# The minimum q-value to be used when extrapolating
18Q_MINIMUM  = 1e-5
19# The maximum q-value to be used when extrapolating
20Q_MAXIMUM  = 10
[90b9a17]21# the ratio of maximum q value/(qmax of data) to plot the theory data
22Q_MAXIMUM_PLOT = 3
[c128284]23# the number of points to consider during fit
24NPTS = 10
25#Default value for background
26BACKGROUND = 0.0
27#default value for the scale
28SCALE = 1.0
[9ce7641c]29#default value of the contrast
30CONTRAST = 1.0
[d0cc0bbc]31#default value of the power used for power law
32POWER = 4.0
[c128284]33#Invariant panel size
34_BOX_WIDTH = 76
35
[4e1c362]36
[c128284]37if sys.platform.count("win32")>0:
38    _STATICBOX_WIDTH = 450
[355b684]39    PANEL_WIDTH = 500 
[c128284]40    PANEL_HEIGHT = 700
41    FONT_VARIANT = 0
42else:
43    _STATICBOX_WIDTH = 480
44    PANEL_WIDTH = 530
45    PANEL_HEIGHT = 700
46    FONT_VARIANT = 1
[d0cc0bbc]47
48
[9abec44]49class InvariantPanel(ScrolledPanel):
[c128284]50    """
[d7a39e5]51    Provides the Invariant GUI.
[c128284]52    """
53    ## Internal nickname for the window, used by the AUI manager
54    window_name = "Invariant"
55    ## Name to appear on the window title bar
56    window_caption = "Invariant"
57    ## Flag to tell the AUI manager to put this panel in the center pane
58    CENTER_PANE = True
[355b684]59    def __init__(self, parent, data=None, manager=None,*args, **kwds):
[e825f72]60        kwds["size"]= (PANEL_WIDTH, PANEL_HEIGHT)
[f1b0f70]61        kwds["style"]= wx.FULL_REPAINT_ON_RESIZE
[355b684]62        ScrolledPanel.__init__(self, parent=parent, *args, **kwds)
[3de66c1]63        self.SetupScrolling()
[c128284]64        #Font size
65        self.SetWindowVariant(variant=FONT_VARIANT)
66        #Object that receive status event
67        self.parent = parent
[272d91e]68        #plug-in using this panel
69        self._manager = manager
70        #Data uses for computation
71        self._data = data
[6d55d81]72        self._scale = SCALE
73        self._background = BACKGROUND
[4e1c362]74        self._bmark = None
75        self.bookmark_num = 0
76       
77        self._set_bookmark_menu()
78        #Init state
79        self.set_state()
80        # default flags for state
81        self.new_state = False
82        self.is_power_out = False
83       
[9ce7641c]84        #container of invariant value
85        self.inv_container = None
[c128284]86        #Draw the panel
87        self._do_layout()
[d0cc0bbc]88        self.reset_panel()
[4e1c362]89        self._reset_state_list()
90       
[a0a4486]91        if self.parent is not None:
92            msg = ""
[e3f721e4]93            wx.PostEvent(self.parent,StatusEvent(status=msg, info="info"))
[4e1c362]94           
95        ## Default file location for save
96        self._default_save_location = os.getcwd()
97 
[a0a4486]98    def err_check_on_data(self):
99        """
[d7a39e5]100        Check if data is valid for further computation
[a0a4486]101        """
102        flag = False
[e3f721e4]103        self.hint_msg_txt.SetLabel('')
[a0a4486]104        #edit the panel
105        if self._data is not None:
106            if len(self._data.x[self._data.x==0]) > 0:
107                flag = True
108                msg = "Invariant: one of your q-values is zero. Delete that entry before proceeding"
[f1b0f70]109                self.hint_msg_txt.SetLabel(msg)
[e3f721e4]110                wx.PostEvent(self.parent, StatusEvent(status=msg,
111                                                      info="warning",
112                                                      type="stop")) 
[a0a4486]113        return flag
114   
[272d91e]115    def set_data(self, data):
[c128284]116        """
[d7a39e5]117        Set the data
[4e1c362]118       
119        : return: True/False; if False, it will not set_data
[c128284]120        """
[4e1c362]121        # warn the users
122        if self._data != None and data != None:
123            if not self._show_message():
124                return False
125           
[272d91e]126        self._data = data
[4e1c362]127        # reset popUpMenu
128        self._set_bookmark_menu()
[272d91e]129        #edit the panel
130        if self._data is not None:
[4e1c362]131           
[a0a4486]132            self.err_check_on_data()
[4e1c362]133            self.get_state_by_num(0)
[272d91e]134            data_name = self._data.name
135            data_qmin = min (self._data.x)
136            data_qmax = max (self._data.x)
[4e1c362]137            self.data_name_tcl.SetValue(str(data_name))     
[9ce7641c]138            self.data_min_tcl.SetLabel(str(data_qmin))
139            self.data_max_tcl.SetLabel(str(data_qmax))
[4e1c362]140            self.button_save.Enable(True) 
[d0cc0bbc]141            self.reset_panel()
142            self.compute_invariant(event=None)
[4e1c362]143            #Reset the list of states
144            self.state.data = copy.deepcopy(data)
145            self._reset_state_list()
146           
147        return True     
148
[d0cc0bbc]149    def set_message(self):
150        """
[d7a39e5]151        Display warning message if available
[d0cc0bbc]152        """
153        if self.inv_container is not None:
154            if self.inv_container.existing_warning:
155                msg = "Warning! Computations on invariant require your "
156                msg += "attention.\n Please click on Details button."
157                self.hint_msg_txt.SetForegroundColour("red")
[1c271f2]158   
159                wx.PostEvent(self.parent,StatusEvent(status=msg,info="warning"))
[d0cc0bbc]160            else:
161                msg = "For more information, click on Details button."
162                self.hint_msg_txt.SetForegroundColour("black")
[1c271f2]163                wx.PostEvent(self.parent,StatusEvent(status=msg,info="info"))
[d0cc0bbc]164            self.hint_msg_txt.SetLabel(msg)
165        self.data_name_boxsizer.Layout()
166       
[c128284]167    def set_manager(self, manager):
168        """
[d7a39e5]169        set value for the manager
[c128284]170        """
[272d91e]171        self._manager = manager
[4e1c362]172       
173    def set_state(self,state=None,data=None):
174        """
175        set state when loading it from a .inv file
176        """
177        if state == None or data == None:
178            self.state = IState()
179        else:
180            if not self.set_data(data):
181                return
182            self.new_state = True
183            self.state = state   
184
185            num = self.state.saved_state['state_num']
186            self.get_state_by_num(state_num=num)
187           
188            if num >0 :
189                self._undo_enable()
190            if num < len(state.state_list)-1:
191                self._redo_enable()
192               
193           
194            # get bookmarks
195            self.bookmark_num = len(self.state.bookmark_list)
196            total_bookmark_num = self.bookmark_num+1
197            for ind in range(1,total_bookmark_num):
198                #bookmark_num = ind
199                value = self.state.bookmark_list[ind]
200                name = "%d] bookmarked at %s on %s"% (ind,value[0], value[1])
201                # append it to menu
202                id = wx.NewId()
203                self.popUpMenu.Append(id,name,str(''))
204                wx.EVT_MENU(self, id, self._back_to_bookmark)   
205            self.new_state = False 
206
207
[9ce7641c]208    def get_background(self):
[c128284]209        """
[d7a39e5]210        return the background textcrtl value as a float
[c128284]211        """
[9ce7641c]212        background = self.background_tcl.GetValue().lstrip().rstrip()
[c128284]213        if background == "":
[9ce7641c]214            raise ValueError, "Need a background"
215        if check_float(self.background_tcl):
216            return float(background)
217        else:
218            raise ValueError, "Receive invalid value for background : %s"%(background)
219   
220    def get_scale(self):
221        """
[d7a39e5]222        return the scale textcrtl value as a float
[9ce7641c]223        """
224        scale = self.scale_tcl.GetValue().lstrip().rstrip()
[c128284]225        if scale == "":
[9ce7641c]226            raise ValueError, "Need a background"
227        if check_float(self.scale_tcl):
[6d55d81]228            if float(scale)<= 0.0:
229                self.scale_tcl.SetBackgroundColour("pink")
230                self.scale_tcl.Refresh()
231                raise ValueError, "Receive invalid value for scale: %s"%(scale)
[9ce7641c]232            return float(scale)
233        else:
[6d55d81]234            raise ValueError, "Receive invalid value for scale : %s"%(scale)
[9ce7641c]235       
236    def get_contrast(self):
237        """
[d7a39e5]238        return the contrast textcrtl value as a float
[9ce7641c]239        """
240        par_str = self.contrast_tcl.GetValue().strip()
241        contrast = None
242        if par_str !="" and check_float(self.contrast_tcl):
243            contrast = float(par_str)
244        return contrast
245   
246    def get_extrapolation_type(self, low_q, high_q):
247        """
248        """
249        extrapolation = None
250        if low_q  and not high_q:
251            extrapolation = "low"
252        elif not low_q  and high_q:
253            extrapolation = "high"
254        elif low_q and high_q:
255            extrapolation = "both"
256        return extrapolation
[272d91e]257           
[9ce7641c]258    def get_porod_const(self):
259        """
[d7a39e5]260        return the porod constant textcrtl value as a float
[9ce7641c]261        """
262        par_str = self.porod_constant_tcl.GetValue().strip()
263        porod_const = None
264        if par_str !="" and check_float(self.porod_constant_tcl):
265            porod_const = float(par_str)
266        return porod_const
267   
268    def get_volume(self, inv, contrast, extrapolation):
269        """
270        """
271        if contrast is not None:
[c128284]272            try:
[9ce7641c]273                v, dv = inv.get_volume_fraction_with_error(contrast=contrast, 
274                                                           extrapolation=extrapolation)
275                self.volume_tcl.SetValue(format_number(v))
276                self.volume_err_tcl.SetValue(format_number(dv))
[c128284]277            except:
[0a8759f]278                self.volume_tcl.SetValue(format_number(None))
279                self.volume_err_tcl.SetValue(format_number(None))
[9ce7641c]280                msg= "Error occurred computing volume fraction: %s"%sys.exc_value
[e3f721e4]281                wx.PostEvent(self.parent, StatusEvent(status=msg,
282                                                      info="error",
283                                                      type="stop"))
[9ce7641c]284               
285    def get_surface(self, inv, contrast, porod_const, extrapolation):
286        """
287        """
288        if contrast is not None and porod_const is not None:
[c128284]289            try:
[9ce7641c]290                s, ds = inv.get_surface_with_error(contrast=contrast,
291                                        porod_const=porod_const,
292                                        extrapolation=extrapolation)
293                self.surface_tcl.SetValue(format_number(s))
294                self.surface_err_tcl.SetValue(format_number(ds))
[c128284]295            except:
[0a8759f]296                self.surface_tcl.SetValue(format_number(None))
297                self.surface_err_tcl.SetValue(format_number(None))
[4e74e13]298                msg = "Error occurred computing specific surface: %s"%sys.exc_value
[e3f721e4]299                wx.PostEvent(self.parent, StatusEvent(status=msg, info="error",
300                                                       type="stop"))
[53b6b74]301               
[9ce7641c]302    def get_total_qstar(self, inv, extrapolation):
303        """
304        """
305        try:
306            qstar_total, qstar_total_err = inv.get_qstar_with_error(extrapolation)
[0a8759f]307           
[9ce7641c]308            self.invariant_total_tcl.SetValue(format_number(qstar_total))
[518d35d]309            self.invariant_total_err_tcl.SetValue(format_number(qstar_total_err))
[9ce7641c]310            self.inv_container.qstar_total = qstar_total
311            self.inv_container.qstar_total_err = qstar_total_err
[518d35d]312         
[9ce7641c]313        except:
[0a8759f]314            self.inv_container.qstar_total = "Error"
315            self.inv_container.qstar_total_err = "Error"
316            self.invariant_total_tcl.SetValue(format_number(None))
317            self.invariant_total_err_tcl.SetValue(format_number(None))
[9ce7641c]318            msg= "Error occurred computing invariant using extrapolation: %s"%sys.exc_value
319            wx.PostEvent(self.parent, StatusEvent(status= msg, type="stop")) 
320           
321    def get_low_qstar(self, inv, npts_low, low_q=False):
322        """
323        """
324        if low_q:
325            try: 
326                qstar_low, qstar_low_err = inv.get_qstar_low()
327                self.inv_container.qstar_low = qstar_low
328                self.inv_container.qstar_low_err = qstar_low_err
329                extrapolated_data = inv.get_extra_data_low(npts_in=npts_low) 
330                power_low = inv.get_extrapolation_power(range='low') 
[518d35d]331                if self.power_law_low.GetValue():
[d0cc0bbc]332                    self.power_low_tcl.SetValue(format_number(power_low))
[9ce7641c]333                self._manager.plot_theory(data=extrapolated_data,
334                                           name="Low-Q extrapolation")
335            except:
[0a8759f]336                self.inv_container.qstar_low = "ERROR"
337                self.inv_container.qstar_low_err = "ERROR"
338                self._manager.plot_theory(name="Low-Q extrapolation")
[9ce7641c]339                msg= "Error occurred computing low-Q invariant: %s"%sys.exc_value
340                wx.PostEvent(self.parent, StatusEvent(status= msg, type="stop"))
[c128284]341        else:
[4e1c362]342            try:
343                self._manager.plot_theory(name="Low-Q extrapolation")
344            except: pass
[9ce7641c]345           
346    def get_high_qstar(self, inv, high_q=False):
347        """
348        """
349        if high_q:
350            try: 
[90b9a17]351                qmax_plot = Q_MAXIMUM_PLOT * max(self._data.x)
352                if qmax_plot > Q_MAXIMUM: qmax_plot = Q_MAXIMUM
[9ce7641c]353                qstar_high, qstar_high_err = inv.get_qstar_high()
354                self.inv_container.qstar_high = qstar_high
355                self.inv_container.qstar_high_err = qstar_high_err
[518d35d]356                power_high = inv.get_extrapolation_power(range='high') 
[d0cc0bbc]357                self.power_high_tcl.SetValue(format_number(power_high))
[90b9a17]358                high_out_data = inv.get_extra_data_high(q_end=qmax_plot,npts=500)
[9ce7641c]359                self._manager.plot_theory(data=high_out_data,
360                                           name="High-Q extrapolation")
361            except:
[0a8759f]362                self.inv_container.qstar_high = "ERROR"
363                self.inv_container.qstar_high_err = "ERROR"
364                self._manager.plot_theory(name="High-Q extrapolation")
[9ce7641c]365                msg= "Error occurred computing high-Q invariant: %s"%sys.exc_value
366                wx.PostEvent(self.parent, StatusEvent(status= msg, type="stop"))
367        else:
[4e1c362]368            try:
369                self._manager.plot_theory(name="High-Q extrapolation")
370            except: pass
371
[9ce7641c]372    def get_qstar(self, inv):
373        """
374        """
375        qstar, qstar_err = inv.get_qstar_with_error()
376        self.inv_container.qstar = qstar
377        self.inv_container.qstar_err = qstar_err
378             
379    def set_extrapolation_low(self, inv, low_q=False):
380        """
[d7a39e5]381        return float value necessary to compute invariant a low q
[9ce7641c]382        """
383        #get funtion
384        if self.guinier.GetValue():
385            function_low = "guinier"
386        # get the function
[518d35d]387        power_low = None #2.0/3.0
[9ce7641c]388        if self.power_law_low.GetValue():
389            function_low = "power_law"
[518d35d]390            if self.fit_enable_low.GetValue():
[9ce7641c]391                #set value of power_low to none to allow fitting
392                power_low = None
393            else:
394                power_low = self.power_low_tcl.GetValue().lstrip().rstrip()
395                if check_float(self.power_low_tcl):
396                    power_low = float(power_low)
397                else:
398                    if low_q :
399                        #Raise error only when qstar at low q is requested
400                        msg = "Expect float for power at low q , got %s"%(power_low)
401                        raise ValueError, msg
[518d35d]402       
[9ce7641c]403        #Get the number of points to extrapolated
404        npts_low = self.npts_low_tcl.GetValue().lstrip().rstrip()   
405        if check_float(self.npts_low_tcl):
406            npts_low = float(npts_low)
407        else:
408            if low_q:
409                msg = "Expect float for number of points at low q , got %s"%(npts_low)
410                raise ValueError, msg
411        #Set the invariant calculator
412        inv.set_extrapolation(range="low", npts=npts_low,
413                                   function=function_low, power=power_low)   
414        return inv, npts_low 
[4e1c362]415   
416
[9ce7641c]417    def set_extrapolation_high(self, inv, high_q=False):
418        """
[d7a39e5]419        return float value necessary to compute invariant a high q
[9ce7641c]420        """
421        power_high = None
[277fad8]422        #if self.power_law_high.GetValue():
423        function_high = "power_law"
424        if self.fit_enable_high.GetValue():
425            #set value of power_high to none to allow fitting
426            power_high = None
427        else:
428            power_high = self.power_high_tcl.GetValue().lstrip().rstrip()
429            if check_float(self.power_high_tcl):
430                power_high = float(power_high)
[9ce7641c]431            else:
[277fad8]432                if high_q :
433                    #Raise error only when qstar at high q is requested
434                    msg = "Expect float for power at high q , got %s"%(power_high)
435                    raise ValueError, msg
[9ce7641c]436                         
437        npts_high = self.npts_high_tcl.GetValue().lstrip().rstrip()   
438        if check_float(self.npts_high_tcl):
439            npts_high = float(npts_high)
440        else:
441            if high_q:
442                msg = "Expect float for number of points at high q , got %s"%(npts_high)
443                raise ValueError, msg
444        inv.set_extrapolation(range="high", npts=npts_high,
445                                   function=function_high, power=power_high)
446        return inv, npts_high
447   
448    def display_details(self, event):
449        """
[d7a39e5]450        open another panel for more details on invariant calculation
[9ce7641c]451        """
[d3fac18]452        panel = InvariantDetailsPanel(parent=self, 
453                                           qstar_container=self.inv_container)
454        panel.ShowModal()
455        panel.Destroy()
[d0cc0bbc]456        self.button_calculate.SetFocus()
[9ce7641c]457       
[d0cc0bbc]458    def compute_invariant(self, event=None):
[9ce7641c]459        """
[d7a39e5]460        compute invariant
[9ce7641c]461        """
[4e1c362]462        if self._data == None:
463            msg = "\n\nData must be loaded first in order to perform a compution..."
464            wx.PostEvent(self.parent, StatusEvent(status=msg))
465        # set a state for this computation for saving
466        elif event != None: 
467            self._set_compute_state(state='compute')
468            msg= "\n\nStarting a new invariant computation..."           
469            wx.PostEvent(self.parent, StatusEvent(status=msg))
470
[a0a4486]471        if self._data is None or self.err_check_on_data():
[9ce7641c]472            return
[4e1c362]473       
[9ce7641c]474        #clear outputs textctrl
475        self._reset_output()
476        try:
477            background = self.get_background()
478            scale = self.get_scale()
479        except:
480            msg= "Invariant Error: %s"%(sys.exc_value)
481            wx.PostEvent(self.parent, StatusEvent(status= msg, type="stop"))
482            return
483       
484        low_q = self.enable_low_cbox.GetValue()
485        high_q = self.enable_high_cbox.GetValue() 
486        #set invariant calculator
487        inv = invariant.InvariantCalculator(data=self._data,
488                                            background=background,
489                                            scale=scale)
[437e639]490        try:
491            inv, npts_low = self.set_extrapolation_low(inv=inv, low_q=low_q)
492            inv, npts_high = self.set_extrapolation_high(inv=inv, high_q=high_q)
493        except:
[e3f721e4]494            msg = "Error occurred computing invariant: %s"%sys.exc_value
495            wx.PostEvent(self.parent, StatusEvent(status=msg,
496                                                 info="warning",type="stop"))
[437e639]497            return
[9ce7641c]498        #check the type of extrapolation
499        extrapolation = self.get_extrapolation_type(low_q=low_q, high_q=high_q)
[a0a4486]500       
[9ce7641c]501        #Compute invariant
[6d55d81]502        bkg_changed = False
503        scale_changed = False
[9ce7641c]504        try:
505            self.get_qstar(inv=inv)
[6d55d81]506            #if scale_changed or bkg_changed:
[353f467]507            #self._manager.plot_data(data=inv.get_data())
[6d55d81]508           
[9ce7641c]509        except:
510            msg= "Error occurred computing invariant: %s"%sys.exc_value
[e3f721e4]511            wx.PostEvent(self.parent, StatusEvent(status=msg, 
512                                                  info="warning",type="stop"))
[c128284]513            return
[0a8759f]514       
[9ce7641c]515        #Compute qstar extrapolated to low q range
516        self.get_low_qstar(inv=inv, npts_low=npts_low, low_q=low_q)
517        #Compute qstar extrapolated to high q range
518        self.get_high_qstar(inv=inv, high_q=high_q)
519        #Compute qstar extrapolated to total q range and set value to txtcrtl
520        self.get_total_qstar(inv=inv, extrapolation=extrapolation)
521        # Parse additional parameters
522        porod_const = self.get_porod_const()       
523        contrast = self.get_contrast()
[4e1c362]524       
[f43827cc]525        try:
526            #Compute volume and set value to txtcrtl
527            self.get_volume(inv=inv, contrast=contrast, extrapolation=extrapolation)
528            #compute surface and set value to txtcrtl
529        except:
[4e74e13]530            msg = "Error occurred computing invariant: %s"%sys.exc_value
[e3f721e4]531            wx.PostEvent(self.parent, StatusEvent(status=msg,
532                                                  info="warning",type="stop"))
[f43827cc]533        try:
534            self.get_surface(inv=inv, contrast=contrast, porod_const=porod_const, 
[9ce7641c]535                                    extrapolation=extrapolation)
[4e1c362]536           
[f43827cc]537        except:
[4e74e13]538            msg = "Error occurred computing invariant: %s"%sys.exc_value
[e3f721e4]539            wx.PostEvent(self.parent, StatusEvent(status=msg,
540                                                  info="warning",type="stop"))
[d0cc0bbc]541           
542        #compute percentage of each invariant
543        self.inv_container.compute_percentage()
[4e1c362]544       
[d0cc0bbc]545        #display a message
546        self.set_message()
[4e1c362]547       
548        # reset power_out to default to get ready for another '_on_text'
549        if self.is_power_out == True:
550            self.state.container = copy.deepcopy(self.inv_container)
551            self.state.timestamp= self._get_time_stamp()
552            msg = self.state.__str__()
553            self.is_power_out = False
554            wx.PostEvent(self.parent, StatusEvent(status = msg ))
555       
[9ce7641c]556        #enable the button_ok for more details
[d0cc0bbc]557        self.button_details.Enable()
[4e1c362]558       
[d0cc0bbc]559        self.button_details.SetFocus()
[4e1c362]560        if event != None: 
561            wx.PostEvent(self.parent, StatusEvent(status = '\nFinished invariant computation...'))
562   
563    def undo(self,event=None):
564        """
565        Go back to the previous state
566       
567        : param event: undo button event
[9abec44]568       
[4e1c362]569        """
570        if event != None: event.Skip()
571        if self.state.state_num <0: return
572        self.is_power_out = True
573        # get the previous state_num
574        pre_state_num = int(self.state.saved_state['state_num']) - 1
575        self.get_state_by_num(state_num=str(pre_state_num))
576       
577        if float(pre_state_num) <=0:
578            self.button_undo.Disable()
579        elif not self.button_undo.Enabled:
580            self.button_undo.Enable(True)
581
582        self._redo_enable()
583        self.is_power_out = False 
584        self._info_state_num()
585       
586
587       
588    def redo(self,event=None):
589        """
590        Go forward to the previous state
591       
592        : param event: redo button event
593       
594        """
595        if event != None: event.Skip()
596        self.is_power_out = True
597        next_state_num = int(self.state.saved_state['state_num']) + 1
598
599        self.get_state_by_num(state_num=str(next_state_num))
600       
601        if float(next_state_num)+2 > len(self.state.state_list):
602            self.button_redo.Disable()
603        elif not self.button_redo.Enabled:
604            self.button_redo.Enable(True)
605       
606        self._undo_enable()
607        self.is_power_out = False
608        self._info_state_num()
609       
610    def get_state_by_num(self,state_num=None):
611        """
612        Get the state given by number
613       
614        : param state_num: the given state number
615       
616        """
617       
618        if state_num == None:
619            return
620
621        backup_state_list = copy.deepcopy(self.state.state_list)
622
623        # get the previous state
624        try:
625            current_state = copy.deepcopy(self.state.state_list[str(state_num)])
626            # get the previously computed state number (computation before the state changes happened)
627            current_compute_num = str(current_state['compute_num'])
628        except :
629            raise ValueError,  "No such state exists in history"
630
631        # get the state at pre_compute_num
632        comp_state = copy.deepcopy(self.state.state_list[current_compute_num])
633
634        # set the parameters
635        for key in comp_state:
636            value = comp_state[key]
637            try:
638                exec "self.%s.SetValue(str(%s))" % (key, value)
639            except TypeError:
640                exec "self.%s.SetValue(%s)" % (key, value)
641            except:
642                pass
643           
644        self.compute_invariant(event=None)
645        # set the input params at the state at pre_state_num
646        for key in current_state:
647            # Do not reset set some outputs
648            #key_split = key.split('_')
649            #if key_split[0] == 'surface' or key_split[0] == 'volume':
650            #    continue
651            # set the inputs and boxes
652            value = current_state[key]
653
654            try:
655                exec 'self.%s.SetValue(str(%s))' % (key, value)
656            except TypeError:
657                exec 'self.%s.SetValue(%s)' % (key, value)
658            except:
659                pass
660
661       
662        self._enable_high_q_section(event=None)
663        self._enable_low_q_section(event=None)
664        self.state.state_list = backup_state_list
665        self.state.saved_state = current_state
666        self.state.state_num = state_num
667
668       
669    def get_bookmark_by_num(self, num=None):
670        """
671        Get the bookmark state given by number
672       
673        : param num: the given bookmark number
674       
675        """
676        current_state = {}
677        comp_state = {}
678        backup_state_list = copy.deepcopy(self.state.state_list)
679
680        # get the previous state
681        try:
682            time,date,current_state,comp_state = self.state.bookmark_list[int(num)] 
683        except :
684            raise ValueError,  "No such bookmark exists"
685
686        # set the parameters
687        for key in comp_state:
688            value = comp_state[key]
689            try:
690                exec "self.%s.SetValue(str(%s))" % (key, value)
691            except TypeError:
692                exec "self.%s.SetValue(%s)" % (key, value)
693            except:
694                pass
695
696        self.compute_invariant(event=None)
697        # set the input params at the state of pre_state_num
698        for key in current_state:
699            value = current_state[key]
700            try:
701                exec 'self.%s.SetValue(str(%s))' % (key, value)
702            except TypeError:
703                exec 'self.%s.SetValue(%s)' % (key, value)
704            except:
705                pass
706        self.state.saved_state = copy.deepcopy(current_state)
707
708        self._enable_high_q_section(event=None)
709        self._enable_low_q_section(event=None)
710        self.state.state_list = backup_state_list
711        #self.state.saved_state = current_state
712        #self.state.state_num = state_num
713
[f338d3b]714    def reset_panel(self):
715        """
[d7a39e5]716        set the panel at its initial state.
[f338d3b]717        """
[d0cc0bbc]718        self.background_tcl.SetValue(str(BACKGROUND))
719        self.scale_tcl.SetValue(str(SCALE)) 
[4e74e13]720        self.contrast_tcl.SetValue(str(CONTRAST))
721        self.porod_constant_tcl.SetValue('') 
[d0cc0bbc]722        self.npts_low_tcl.SetValue(str(NPTS))
723        self.enable_low_cbox.SetValue(False)
724        self.fix_enable_low.SetValue(True)
725        self.power_low_tcl.SetValue(str(POWER))
726        self.guinier.SetValue(True)
727        self.power_low_tcl.Disable()
728        self.enable_high_cbox.SetValue(False)
729        self.fix_enable_high.SetValue(True)
730        self.power_high_tcl.SetValue(str(POWER))
731        self.npts_high_tcl.SetValue(str(NPTS))
732        self.button_details.Disable()
733        #Change the state of txtcrtl to enable/disable
734        self._enable_low_q_section()
735        #Change the state of txtcrtl to enable/disable
736        self._enable_high_q_section()
737        self._reset_output()
[4e1c362]738        self.button_undo.Disable()
739        self.button_redo.Disable()
[d0cc0bbc]740        self.button_calculate.SetFocus()
[4e1c362]741        #self.SetupScrolling()
742       
743    def _set_state(self, event):
744        """
745        Set the state list
746       
747        :param event: rb/cb event
748       
749        """
750        if event == None:
751            return
752        obj = event.GetEventObject()
753        name = str(obj.GetName())
754        value = str(obj.GetValue())
755        rb_list = [['power_law_low','guinier'],['fit_enable_low','fix_enable_low'],['fit_enable_high','fix_enable_high']]
756
757        try:
758            if value == None or value.lstrip().rstrip() =='':
759                value = 'None'
760            exec 'self.state.%s = %s' % (name, value)
761            exec "self.state.saved_state['%s'] = %s" %  (name, value)
762           
763            # set the count part of radio button clicked False for the saved_state
764            for title,content in rb_list:
765                if name ==  title:
766                    name = content
767                    value = False     
768                elif name == content:
769                    name = title
770                    value = False 
771            exec "self.state.saved_state['%s'] = %s" %  (name, value)     
772           
773            # Instead of changing the future, create a new future.
774            max_state_num = len(self.state.state_list)-1   
775            self.state.saved_state['state_num'] = max_state_num   
776           
777            self.state.saved_state['state_num'] +=1
778            self.state.state_num = self.state.saved_state['state_num']
779            self.state.state_list[str(self.state.state_num)] = self.state.clone_state()#copy.deepcopy(self.state.saved_state)
780
781        except:           
782            pass
783
784        event.Skip()
785        self._undo_enable()
786        self._redo_disable()
787           
788    def _set_compute_state(self,state=None):
789        """
790        Notify the compute_invariant state to self.state
791       
792        : param state: set 'compute' when the computation is activated by the 'compute' button, else None
793       
794        """
795        # reset the default
796        if state != 'compute':
797            self.new_state = False
798            self.is_power_out = False
799        else:
800            self.is_power_out = True
801        # Instead of changing the future, create a new future.
802        max_state_num = len(self.state.state_list)-1   
803        self.state.saved_state['state_num'] = max_state_num       
804        # A new computation is also A state
805        temp_saved_states = self.state.clone_state()#copy.deepcopy(self.state.saved_state)
806        temp_saved_states['state_num'] +=1
807        self.state.state_num = temp_saved_states['state_num']
808
809               
810        # set the state number of the computation
811        if state == 'compute':
812            temp_saved_states['compute_num'] = self.state.state_num
813        self.state.saved_state= copy.deepcopy(temp_saved_states)
814        self.state.state_list[str(self.state.state_num)] = self.state.clone_state()#copy.deepcopy(self.state.saved_state)
815       
816        # A computation is a new state, so delete the states with any higher state numbers
817        for i in range(self.state.state_num+1,len(self.state.state_list)):
818            try:
819                del (self.state.state_list[str(i)])
820            except: 
821                pass
822        # Enable the undo button if it was not
823        self._undo_enable()
824        self._redo_disable()
825       
826    def _reset_state_list(self,data=None):
827        """
828        Reset the state_list just before data was loading: Used in 'set_data()'
829        """
830        #if data == None: return
831        #temp_state = self.state.clone_state()#copy.deepcopy(self.state.saved_state)
832        # Clear the list
833        self.state.state_list.clear()
834        self.state.bookmark_list.clear()
835        # Set defaults
836        self.state.saved_state['state_num'] = 0
837        self.state.saved_state['compute_num'] = 0
838        if self._data != None:
839            self.state.saved_state['file'] = str(self._data.name)
840        else:
841            self.state.saved_state['file'] = 'None'
842        self.state.file = self.state.saved_state['file']
843
844        self.state.state_num = self.state.saved_state['state_num']
845        # Put only the current state in the list
846        self.state.state_list[str(self.state.state_num)] = self.state.clone_state()#copy.deepcopy(self.state.saved_state)
847        self._undo_disable()
848       
849    def _on_text(self, event):
850        """
851        Catch text change event to add the state to the state_list
852       
853        :param event: txtctr event ; assumes not None
854       
855        """
856        if self._data == None: 
857            return
858        # check if this event is from do/undo button
859        if self.state.saved_state['is_time_machine'] or self.new_state:
860            event.Skip()
861            return
862       
863        # get the object
864        obj = event.GetEventObject()
865        name = str(obj.GetName())
866        value = str(obj.GetValue())
867        state_num = self.state.saved_state['state_num']
868
869        # text event is a new state, so delete the states with higher state_num
870        # i.e., change the future
871        for i in range(int(state_num)+1,len(self.state.state_list)):
872            try:
873                del (self.state.state_list[str(i)])
874            except: 
875                pass
876       
877        # Instead of changing the future, create a new future.
878        #max_state_num = len(self.state.state_list)-1   
879        #self.state.saved_state['state_num'] = max_state_num
880
881        # try to add new state of the text changes in the state_list
882        try:
883            if value.strip() == None: value = ''
884            exec "self.state.%s = '%s'" % (name, value)
885            exec "self.state.saved_state['%s'] = '%s'" %  (name, value)
886            exec "self.state.input_list['%s'] = '%s'" % (name, value)
887            if not self.is_power_out:
888                if name != 'power_low_tcl' and name !='power_high_tcl':
889                    self.state.saved_state['state_num'] += 1
890            self.state.state_num = self.state.saved_state['state_num']
891            self.state.state_list[str(self.state.state_num)] = self.state.clone_state()#copy.deepcopy(self.state.saved_state)
892        except:
893            pass
894
895        event.Skip()
896        self._undo_enable()
897        self._redo_disable()
898       
899    def _on_out_text(self, event):     
900        """
901        Catch ouput text change to add the state
902       
903        :param event: txtctr event ; assumes not None
904       
905        """   
906        # get the object
907        obj = event.GetEventObject()
908        name = str(obj.GetName())
909        value = str(obj.GetValue())
910        try:
911            exec "self.state.saved_state['%s'] = '%s'" %  (name, value)
912            self.state.state_list[str(self.state.state_num)] = self.state.clone_state()
913        except:
914            pass
915        if event != None: event.Skip()\
916       
917    def _set_bookmark_menu(self):
918        """
919        Setup 'bookmark' context menu
920        """
921        ## Create context menu for page
922        self.popUpMenu = wx.Menu()
923        id = wx.NewId()
924        self._bmark = wx.MenuItem(self.popUpMenu,id,"BookMark"," Bookmark the panel to recall it later")
925        self.popUpMenu.AppendItem(self._bmark)
926        self._bmark.Enable(True)
927        wx.EVT_MENU(self, id, self._on_bookmark)
928        self.popUpMenu.AppendSeparator()
929        self.Bind(wx.EVT_CONTEXT_MENU, self._on_context_menu)
930       
931    def _on_bookmark(self,event):
932        """
933        Save the panel state in memory and add the list on the popup menu on bookmark context menu event
934        """ 
935        if self._data == None: return
936        if event == None: return
937        self.bookmark_num += 1
938        # date and time of the event
939        #year, month, day,hour,minute,second,tda,ty,tm_isdst= time.localtime()
940        #my_time= str(hour)+" : "+str(minute)+" : "+str(second)+" "
941        #date= str( month)+"/"+str(day)+"/"+str(year)
942        my_time, date = self._get_time_stamp()
943        state_num = self.state.state_num
944        compute_num = self.state.saved_state['compute_num']
945        # name and message of the bookmark list
946        msg=  "State saved at %s on %s"%(my_time, date)
947         ## post help message for the selected model
948        msg +=" Saved! right click on this page to retrieve this model"
949        #wx.PostEvent(self.parent.parent, StatusEvent(status = msg ))
950        name = "%d] bookmarked at %s on %s"%(self.bookmark_num,my_time, date)
951       
952        # append it to menu
953        id = wx.NewId()
954        self.popUpMenu.Append(id,name,str(msg))
955        wx.EVT_MENU(self, id, self._back_to_bookmark )
956        state = self.state.clone_state()
957        comp_state = copy.deepcopy(self.state.state_list[str(compute_num)])
958        self.state.bookmark_list[self.bookmark_num] = [my_time,date,state,comp_state]
959        self.state.toXML(self, doc=None, entry_node=None)
960
961    def _back_to_bookmark(self,event):
962        """
963        Bring the panel back to the state of bookmarked requested by context menu event
964        and set it as a new state
965        """
966        ## post help message for the selected model
967        msg = self.popUpMenu.GetHelpString(event.GetId())
968        msg +=" reloaded"
969        wx.PostEvent(self.parent, StatusEvent(status = msg ))
970       
971        name= self.popUpMenu.GetLabel(event.GetId())
972        num,time = name.split(']')
973        current_state_num = self.state.state_num 
974        self.get_bookmark_by_num(num)
975        state_num = int(current_state_num)+1
976       
977        self.state.saved_state['state_num'] = state_num
978        self.state.state_list[str(state_num)] = self.state.clone_state()#copy.deepcopy(self.state.saved_state)
979        self.state.state_num = state_num
980        self._undo_enable()
981        self._info_bookmark_num(event)
982       
983    def _info_bookmark_num(self,event=None):
984        """
985        print the bookmark number in info
986       
987        : event: popUpMenu event
988        """
989        if event == None: return
990        # get the object
991        item = self.popUpMenu.FindItemById(event.GetId())
992        text = item.GetText()
993        num = text.split(']')[0]
994        msg = "bookmark num = %s "% num
995       
996        wx.PostEvent(self.parent, StatusEvent(status = msg ))
997       
998    def _info_state_num(self):
999        """
1000        print the current state number in info
1001        """
1002        msg = "state num = "
1003        msg += self.state.state_num
1004       
1005        wx.PostEvent(self.parent, StatusEvent(status = msg))
1006                         
1007    def _get_time_stamp(self):
1008        """
1009        return time and date stings
1010        """
1011        # date and time
1012        year, month, day,hour,minute,second,tda,ty,tm_isdst= time.localtime()
1013        my_time= str(hour)+":"+str(minute)+":"+str(second)
1014        date= str( month)+"/"+str(day)+"/"+str(year)
1015        return my_time, date
1016   
1017    def _undo_enable(self):
1018        """
1019        Enable undo button
1020        """
1021        if not self.button_undo.IsEnabled():
1022            self.button_undo.Enable(True)
1023
1024    def _undo_disable(self):
1025        """
1026        Disable undo button
1027        """
1028        if self.button_undo.IsEnabled():
1029            self.button_undo.Disable()
1030
1031    def _redo_enable(self):
1032        """
1033        Enable redo button
1034        """
1035        if not self.button_redo.IsEnabled():
1036            self.button_redo.Enable(True)
1037
1038    def _redo_disable(self):
1039        """
1040        Disable redo button
1041        """
1042        if self.button_redo.IsEnabled():
1043            self.button_redo.Disable()
1044           
1045    def _on_save_button(self, evt=None): 
1046        """
1047        Save invariant state into a file
1048        """
1049        # Ask the user the location of the file to write to.
1050        path = None
1051        dlg = wx.FileDialog(self, "Choose a file", self._default_save_location, "", "*.inv", wx.SAVE)
1052        if dlg.ShowModal() == wx.ID_OK:
1053            path = dlg.GetPath()
1054            self._default_save_location = os.path.dirname(path)
1055        else:
1056            return None
1057       
1058        dlg.Destroy()
1059       
1060        self._manager.save_file(filepath=path, state=self.state)
1061       
1062    def _show_message(self, mssg='',msg='Warning'):
1063        """
1064        Show warning message when resetting data
1065        """
1066       
1067        mssg += 'Loading a new data set will reset all the work done in this panel. \n\r'
1068        mssg += 'Please make sure to save it first... \n\r'
1069        answer = wx.MessageBox(mssg, msg, wx.CANCEL|wx.OK|wx.ICON_EXCLAMATION)
1070
1071        if answer == wx.OK:
1072            return True
1073        else:
1074            return False
[9ce7641c]1075       
[c128284]1076    def _reset_output(self):
1077        """
[d7a39e5]1078        clear outputs textcrtl
[c128284]1079        """
[9ce7641c]1080        self.invariant_total_tcl.Clear()
1081        self.invariant_total_err_tcl.Clear()
1082        self.volume_tcl.Clear()
1083        self.volume_err_tcl.Clear()
1084        self.surface_tcl.Clear()
1085        self.surface_err_tcl.Clear()
[a0a4486]1086        #prepare a new container to put result of invariant
1087        self.inv_container = InvariantContainer()
[4e1c362]1088
1089   
1090    def _on_context_menu(self,event):
1091       
1092        pos = event.GetPosition()
1093        pos = self.ScreenToClient(pos)
[b7f29fc]1094       
[4e1c362]1095        self.PopupMenu(self.popUpMenu, pos) 
1096     
[9ce7641c]1097    def _define_structure(self):
[c128284]1098        """
[d7a39e5]1099        Define main sizers needed for this panel
[c128284]1100        """
[d5f0dcb9]1101        ## Box sizers must be defined first before defining buttons/textctrls (MAC).
[9ce7641c]1102        self.main_sizer = wx.BoxSizer(wx.VERTICAL)
1103        #Sizer related to outputs
1104        outputs_box = wx.StaticBox(self, -1, "Outputs")
1105        self.outputs_sizer = wx.StaticBoxSizer(outputs_box, wx.VERTICAL)
1106        self.outputs_sizer.SetMinSize((PANEL_WIDTH,-1))
1107        #Sizer related to data
1108        data_name_box = wx.StaticBox(self, -1, "I(q) Data Source")
1109        self.data_name_boxsizer = wx.StaticBoxSizer(data_name_box, wx.VERTICAL)
1110        self.data_name_boxsizer.SetMinSize((PANEL_WIDTH,-1))
1111        self.hint_msg_sizer = wx.BoxSizer(wx.HORIZONTAL)
1112        self.data_name_sizer = wx.BoxSizer(wx.HORIZONTAL)
1113        self.data_range_sizer = wx.BoxSizer(wx.HORIZONTAL)
[d0cc0bbc]1114        #Sizer related to background and scale
1115        self.bkg_scale_sizer = wx.BoxSizer(wx.HORIZONTAL) 
1116        #Sizer related to contrast and porod constant
1117        self.contrast_porod_sizer = wx.BoxSizer(wx.HORIZONTAL) 
1118        #Sizer related to inputs
1119        inputs_box = wx.StaticBox(self, -1, "Customized Inputs")
1120        self.inputs_sizer = wx.StaticBoxSizer(inputs_box, wx.VERTICAL)
1121        #Sizer related to extrapolation
[d5f0dcb9]1122        extrapolation_box = wx.StaticBox(self, -1, "Extrapolation")
[9ce7641c]1123        self.extrapolation_sizer = wx.StaticBoxSizer(extrapolation_box,
1124                                                        wx.VERTICAL)
1125        self.extrapolation_sizer.SetMinSize((PANEL_WIDTH,-1))
1126        self.extrapolation_range_sizer = wx.BoxSizer(wx.HORIZONTAL)
1127        self.extrapolation_low_high_sizer = wx.BoxSizer(wx.HORIZONTAL)
1128        #Sizer related to extrapolation at low q range
[d5f0dcb9]1129        low_q_box = wx.StaticBox(self, -1, "Low Q")
[9ce7641c]1130        self.low_extrapolation_sizer = wx.StaticBoxSizer(low_q_box, wx.VERTICAL)
1131        self.low_q_sizer = wx.GridBagSizer(5,5)
1132        #Sizer related to extrapolation at low q range
1133        high_q_box = wx.StaticBox(self, -1, "High Q")
1134        self.high_extrapolation_sizer = wx.StaticBoxSizer(high_q_box, wx.VERTICAL)
1135        self.high_q_sizer = wx.GridBagSizer(5,5)
1136        #sizer to define outputs
1137        self.volume_surface_sizer = wx.GridBagSizer(5,5)
1138        #Sizer related to invariant output
[277fad8]1139        self.invariant_sizer = wx.GridBagSizer(5, 5)
[9ce7641c]1140        #Sizer related to button
1141        self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
[4e1c362]1142        #Sizer related to save button
1143        self.save_button_sizer = wx.BoxSizer(wx.HORIZONTAL)
1144       
[9ce7641c]1145    def _layout_data_name(self):
1146        """
[d7a39e5]1147        Draw widgets related to data's name
[9ce7641c]1148        """
1149        #Sizer hint
[6848131]1150        hint_msg = "First open data file from 'File' menu.  Then Highlight and right click on the data plot. \n"
[4e1c362]1151        hint_msg += "Finally, select 'Compute Invariant'."
[277fad8]1152        self.hint_msg_txt = wx.StaticText(self, -1, hint_msg) 
1153        self.hint_msg_txt.SetForegroundColour("red")
[6848131]1154        msg = "Highlight = mouse the mouse's cursor on the data until the plot's color changes to yellow"
1155        self.hint_msg_txt.SetToolTipString(msg)
[277fad8]1156        self.hint_msg_sizer.Add(self.hint_msg_txt)
[9ce7641c]1157        #Data name [string]
1158        data_name_txt = wx.StaticText(self, -1, 'Data : ') 
1159       
[4e1c362]1160        self.data_name_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH*5, 20), style=0, name='data_name_tcl') 
[9ce7641c]1161        self.data_name_tcl.SetToolTipString("Data's name.")
1162        self.data_name_sizer.AddMany([(data_name_txt, 0, wx.LEFT|wx.RIGHT, 10),
1163                                       (self.data_name_tcl, 0, wx.EXPAND)])
1164        #Data range [string]
1165        data_range_txt = wx.StaticText(self, -1, 'Total Q Range (1/A): ') 
1166        data_min_txt = wx.StaticText(self, -1, 'Min : ') 
[4e1c362]1167        self.data_min_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0, name='data_min_tcl')
[9ce7641c]1168        self.data_min_tcl.SetToolTipString("The minimum value of q range.")
1169        data_max_txt = wx.StaticText(self, -1, 'Max : ') 
[4e1c362]1170        self.data_max_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0, name='data_max_tcl') 
[9ce7641c]1171        self.data_max_tcl.SetToolTipString("The maximum value of q range.")
1172        self.data_range_sizer.AddMany([(data_range_txt, 0, wx.RIGHT, 10),
1173                                       (data_min_txt, 0, wx.RIGHT, 10),
1174                                       (self.data_min_tcl, 0, wx.RIGHT, 10),
1175                                       (data_max_txt, 0, wx.RIGHT, 10),
1176                                       (self.data_max_tcl, 0, wx.RIGHT, 10)])
[4e1c362]1177        self.data_name_boxsizer.AddMany([(self.hint_msg_sizer, 0 , wx.ALL, 5),
[9ce7641c]1178                                         (self.data_name_sizer, 0 , wx.RIGHT, 10),
1179                                         (self.data_range_sizer, 0 , wx.ALL, 10)])
1180   
[d0cc0bbc]1181    def _layout_bkg_scale(self):
[9ce7641c]1182        """
[d7a39e5]1183        Draw widgets related to background and scale
[9ce7641c]1184        """
1185        background_txt = wx.StaticText(self, -1, 'Background : ') 
[4e1c362]1186        self.background_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0, name='background_tcl') 
1187        wx.EVT_TEXT(self, self.background_tcl.GetId(), self._on_text)
1188        background_hint_txt = "Background"
[518d35d]1189        self.background_tcl.SetToolTipString(background_hint_txt)
1190        background_unit_txt = wx.StaticText(self, -1, '[1/cm]') 
[9ce7641c]1191        scale_txt = wx.StaticText(self, -1, 'Scale : ') 
[4e1c362]1192        self.scale_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0, name='scale_tcl')
1193        wx.EVT_TEXT(self, self.scale_tcl.GetId(), self._on_text)
[518d35d]1194        scale_hint_txt = "Scale"
1195        self.scale_tcl.SetToolTipString(scale_hint_txt)
[d0cc0bbc]1196        self.bkg_scale_sizer.AddMany([(background_txt, 0, wx.LEFT, 10),
1197                                       (self.background_tcl, 0, wx.LEFT, 5),
1198                                       (background_unit_txt, 0, wx.LEFT, 10),
1199                                       (scale_txt, 0, wx.LEFT, 70),
1200                                       (self.scale_tcl, 0, wx.LEFT, 40)])
1201 
1202    def _layout_contrast_porod(self):
[9ce7641c]1203        """
[d7a39e5]1204        Draw widgets related to porod constant and contrast
[9ce7641c]1205        """
1206        contrast_txt = wx.StaticText(self, -1, 'Contrast : ') 
[4e1c362]1207        self.contrast_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0,name='contrast_tcl')
1208        wx.EVT_TEXT(self, self.contrast_tcl.GetId(), self._on_text)
[518d35d]1209        contrast_hint_txt = "Contrast"
1210        self.contrast_tcl.SetToolTipString(contrast_hint_txt)
1211        contrast_unit_txt = wx.StaticText(self, -1, '[1/A^(2)]') 
[9ce7641c]1212        porod_const_txt = wx.StaticText(self, -1, 'Porod Constant:') 
[518d35d]1213        self.porod_constant_tcl = InvTextCtrl(self, -1, 
[4e1c362]1214                                              size=(_BOX_WIDTH, 20), style=0,name='porod_constant_tcl') 
1215        wx.EVT_TEXT(self, self.porod_constant_tcl.GetId(), self._on_text)
[518d35d]1216        porod_const_hint_txt = "Porod Constant"
1217        self.porod_constant_tcl.SetToolTipString(porod_const_hint_txt)
[9ce7641c]1218        optional_txt = wx.StaticText(self, -1, '(Optional)') 
[d0cc0bbc]1219        self.contrast_porod_sizer.AddMany([(contrast_txt, 0, wx.LEFT, 10),
1220                                           (self.contrast_tcl, 0, wx.LEFT, 20),
1221                                           (contrast_unit_txt, 0, wx.LEFT, 10),
1222                                           (porod_const_txt, 0, wx.LEFT, 50),
[9ce7641c]1223                                       (self.porod_constant_tcl, 0, wx.LEFT, 0),
1224                                       (optional_txt, 0, wx.LEFT, 10)])
1225       
[518d35d]1226    def _enable_fit_power_law_low(self, event=None):
1227        """
[d7a39e5]1228        Enable and disable the power value editing
[518d35d]1229        """
[4e1c362]1230        if event != None: 
1231            print "enable fit==>event!=None"
1232
[518d35d]1233        if self.fix_enable_low.IsEnabled():
[4e1c362]1234           
[518d35d]1235            if self.fix_enable_low.GetValue():
[4e1c362]1236                self.fit_enable_low.SetValue(False)
[518d35d]1237                self.power_low_tcl.Enable()
1238            else:
[4e1c362]1239                self.fit_enable_low.SetValue(True)
[518d35d]1240                self.power_low_tcl.Disable()
[4e1c362]1241        self._set_state(event=event)
1242           
[518d35d]1243    def _enable_low_q_section(self, event=None):
1244        """
[d7a39e5]1245        Disable or enable some button if the user enable low q extrapolation
[518d35d]1246        """
[4e1c362]1247        #if event != None: self._set_compute_state()
[518d35d]1248        if self.enable_low_cbox.GetValue():
1249            self.npts_low_tcl.Enable()
1250            self.fix_enable_low.Enable()
1251            self.fit_enable_low.Enable()
1252            self.guinier.Enable()
1253            self.power_law_low.Enable()
1254
1255        else:
1256            self.npts_low_tcl.Disable()
1257            self.fix_enable_low.Disable()
1258            self.fit_enable_low.Disable()
1259            self.guinier.Disable()
1260            self.power_law_low.Disable()
[4e1c362]1261       
[518d35d]1262        self._enable_power_law_low()
1263        self._enable_fit_power_law_low()
[4e1c362]1264        self._set_state(event=event)
[d0cc0bbc]1265        self.button_calculate.SetFocus()
[4e1c362]1266       
[518d35d]1267    def _enable_power_law_low(self, event=None):
1268        """
[d7a39e5]1269        Enable editing power law section at low q range
[518d35d]1270        """
[4e1c362]1271        #if event != None: self._set_compute_state()
[518d35d]1272        if self.guinier.GetValue():
[4e1c362]1273            self.power_law_low.SetValue(False)
[518d35d]1274            self.fix_enable_low.Disable()
1275            self.fit_enable_low.Disable()
1276            self.power_low_tcl.Disable()
1277        else:
[4e1c362]1278            self.power_law_low.SetValue(True)
[518d35d]1279            self.fix_enable_low.Enable()
1280            self.fit_enable_low.Enable()
1281            self.power_low_tcl.Enable()
1282        self._enable_fit_power_law_low()
[4e1c362]1283        self._set_state(event=event)
[518d35d]1284           
[9ce7641c]1285    def _layout_extrapolation_low(self):
1286        """
[d7a39e5]1287        Draw widgets related to extrapolation at low q range
[9ce7641c]1288        """
[4e1c362]1289        self.enable_low_cbox = wx.CheckBox(self, -1, "Enable Extrapolate Low Q",name='enable_low_cbox')
[518d35d]1290        wx.EVT_CHECKBOX(self, self.enable_low_cbox.GetId(),
1291                                         self._enable_low_q_section)
1292        self.fix_enable_low = wx.RadioButton(self, -1, 'Fix',
[4e1c362]1293                                         (10, 10),style=wx.RB_GROUP,name='fix_enable_low')
[518d35d]1294        self.Bind(wx.EVT_RADIOBUTTON, self._enable_fit_power_law_low,
1295                                     id=self.fix_enable_low.GetId())
[4e1c362]1296        self.fit_enable_low = wx.RadioButton(self, -1, 'Fit', (10, 10),name='fit_enable_low')
[518d35d]1297        self.Bind(wx.EVT_RADIOBUTTON, self._enable_fit_power_law_low, 
1298                                        id=self.fit_enable_low.GetId())
[c128284]1299        self.guinier = wx.RadioButton(self, -1, 'Guinier',
[4e1c362]1300                                         (10, 10),style=wx.RB_GROUP, name='guinier')
[518d35d]1301        self.Bind(wx.EVT_RADIOBUTTON, self._enable_power_law_low,
[4e1c362]1302                                     id=self.guinier.GetId())       
1303        self.power_law_low = wx.RadioButton(self, -1, 'Power Law', (10, 10),name='power_law_low')
[518d35d]1304        self.Bind(wx.EVT_RADIOBUTTON, self._enable_power_law_low, 
1305                                        id=self.power_law_low.GetId())
1306       
[c128284]1307        npts_low_txt = wx.StaticText(self, -1, 'Npts')
[4e1c362]1308        self.npts_low_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH*2/3, -1),name='npts_low_tcl')
1309        wx.EVT_TEXT(self, self.npts_low_tcl.GetId(), self._on_text)
[2661d8b]1310        msg_hint = "Number of Q points to consider"
1311        msg_hint +="while extrapolating the low-Q region"
[9ce7641c]1312        self.npts_low_tcl.SetToolTipString(msg_hint)
1313        power_txt = wx.StaticText(self, -1, 'Power')
[4e1c362]1314        self.power_low_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH*2/3, -1),name='power_low_tcl')
1315        wx.EVT_TEXT(self, self.power_low_tcl.GetId(), self._on_text)
[d0cc0bbc]1316       
[9ce7641c]1317        power_hint_txt = "Exponent to apply to the Power_law function."
1318        self.power_low_tcl.SetToolTipString(power_hint_txt)
[c128284]1319        iy = 0
1320        ix = 0
[518d35d]1321        self.low_q_sizer.Add(self.enable_low_cbox,(iy, ix),(1,5),
1322                            wx.TOP|wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
1323        iy += 1
1324        ix = 0
1325        self.low_q_sizer.Add(npts_low_txt,(iy, ix),(1,1),
1326                            wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
1327        ix += 1
1328        self.low_q_sizer.Add(self.npts_low_tcl, (iy, ix), (1,1),
1329                            wx.EXPAND|wx.ADJUST_MINSIZE, 0)
1330        iy += 1
1331        ix = 0
[9ce7641c]1332        self.low_q_sizer.Add(self.guinier,(iy, ix),(1,2),
[c128284]1333                             wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
1334        iy += 1
1335        ix = 0
[9ce7641c]1336        self.low_q_sizer.Add(self.power_law_low,(iy, ix),(1,2),
[2661d8b]1337                            wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
[518d35d]1338       
[2661d8b]1339        # Parameter controls for power law
1340        ix = 1
1341        iy += 1
[518d35d]1342        self.low_q_sizer.Add(self.fix_enable_low,(iy, ix),(1,1),
1343                            wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 0)
1344        ix += 1
1345        self.low_q_sizer.Add(self.fit_enable_low,(iy, ix),(1,1),
1346                           wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[9ce7641c]1347        ix = 1
1348        iy += 1
1349        self.low_q_sizer.Add(power_txt,(iy, ix),(1,1),
[518d35d]1350                            wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[c128284]1351        ix += 1
[9ce7641c]1352        self.low_q_sizer.Add(self.power_low_tcl, (iy, ix), (1,1),
[c128284]1353                            wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[9ce7641c]1354        self.low_extrapolation_sizer.AddMany([(self.low_q_sizer, 0,
[d0cc0bbc]1355                                                wx.BOTTOM|wx.RIGHT, 15)])
1356       
[518d35d]1357    def _enable_fit_power_law_high(self, event=None):
1358        """
[d7a39e5]1359        Enable and disable the power value editing
[518d35d]1360        """
[4e1c362]1361        #if event != None: self._set_compute_state()
[518d35d]1362        if self.fix_enable_high.IsEnabled():
1363            if self.fix_enable_high.GetValue():
[4e1c362]1364                self.fit_enable_high.SetValue(False)
[518d35d]1365                self.power_high_tcl.Enable()
1366            else:
[4e1c362]1367                self.fit_enable_high.SetValue(True)
[518d35d]1368                self.power_high_tcl.Disable()
[4e1c362]1369        self._set_state(event=event)
[9ce7641c]1370       
[518d35d]1371    def _enable_high_q_section(self, event=None):
1372        """
[d7a39e5]1373        Disable or enable some button if the user enable high q extrapolation
[518d35d]1374        """
[4e1c362]1375        #if event != None: self._set_compute_state()
[518d35d]1376        if self.enable_high_cbox.GetValue():
1377            self.npts_high_tcl.Enable()
1378            self.power_law_high.Enable()
1379            self.power_high_tcl.Enable()
1380            self.fix_enable_high.Enable()
1381            self.fit_enable_high.Enable()
1382        else:
1383            self.npts_high_tcl.Disable()
1384            self.power_law_high.Disable()
1385            self.power_high_tcl.Disable()
1386            self.fix_enable_high.Disable()
1387            self.fit_enable_high.Disable()
1388        self._enable_fit_power_law_high()
[4e1c362]1389        self._set_state(event=event)
[d0cc0bbc]1390        self.button_calculate.SetFocus()
[b7f29fc]1391 
[9ce7641c]1392    def _layout_extrapolation_high(self):
1393        """
[d7a39e5]1394        Draw widgets related to extrapolation at high q range
[9ce7641c]1395        """
[4e1c362]1396        self.enable_high_cbox = wx.CheckBox(self, -1, "Enable Extrapolate high-Q", name='enable_high_cbox')
[518d35d]1397        wx.EVT_CHECKBOX(self, self.enable_high_cbox.GetId(),
1398                                         self._enable_high_q_section)
1399        self.fix_enable_high = wx.RadioButton(self, -1, 'Fix',
[4e1c362]1400                                         (10, 10),style=wx.RB_GROUP,name='fix_enable_high')
[518d35d]1401        self.Bind(wx.EVT_RADIOBUTTON, self._enable_fit_power_law_high,
1402                                     id=self.fix_enable_high.GetId())
[4e1c362]1403        self.fit_enable_high = wx.RadioButton(self, -1, 'Fit', (10, 10),name='fit_enable_high')     
[518d35d]1404        self.Bind(wx.EVT_RADIOBUTTON, self._enable_fit_power_law_high, 
1405                                        id=self.fit_enable_high.GetId())
1406       
[277fad8]1407        self.power_law_high = wx.StaticText(self, -1, 'Power Law')
[d0cc0bbc]1408        msg_hint ="Check to extrapolate data at high-Q"
1409        self.power_law_high.SetToolTipString(msg_hint)
[c128284]1410        npts_high_txt = wx.StaticText(self, -1, 'Npts')
[4e1c362]1411        self.npts_high_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH*2/3, -1),name='npts_high_tcl')
1412        wx.EVT_TEXT(self, self.npts_high_tcl.GetId(), self._on_text)
[2661d8b]1413        msg_hint = "Number of Q points to consider"
1414        msg_hint += "while extrapolating the high-Q region"
[9ce7641c]1415        self.npts_high_tcl.SetToolTipString(msg_hint)
1416        power_txt = wx.StaticText(self, -1, 'Power')
[4e1c362]1417        self.power_high_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH*2/3, -1),name='power_high_tcl')
1418        wx.EVT_TEXT(self, self.power_high_tcl.GetId(), self._on_text)
[9ce7641c]1419        power_hint_txt = "Exponent to apply to the Power_law function."
1420        self.power_high_tcl.SetToolTipString(power_hint_txt)
[518d35d]1421        iy = 0
1422        ix = 0
1423        self.high_q_sizer.Add(self.enable_high_cbox,(iy, ix),(1,5),
1424                            wx.TOP|wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
1425        iy += 1
1426        ix = 0
1427        self.high_q_sizer.Add(npts_high_txt,(iy, ix),(1,1),
1428                            wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
1429        ix += 1
1430        self.high_q_sizer.Add(self.npts_high_tcl, (iy, ix), (1,1),
1431                            wx.EXPAND|wx.ADJUST_MINSIZE, 0)
1432        iy += 2
[c128284]1433        ix = 0
[9ce7641c]1434        self.high_q_sizer.Add(self.power_law_high,(iy, ix),(1,2),
[2661d8b]1435                            wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
[518d35d]1436       
1437        # Parameter controls for power law
[2661d8b]1438        ix = 1
1439        iy += 1
[518d35d]1440        self.high_q_sizer.Add(self.fix_enable_high,(iy, ix),(1,1),
1441                            wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 0)
1442        ix += 1
1443        self.high_q_sizer.Add(self.fit_enable_high,(iy, ix),(1,1),
1444                           wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[9ce7641c]1445        ix = 1
1446        iy += 1
1447        self.high_q_sizer.Add(power_txt,(iy, ix),(1,1),
[c128284]1448                            wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
1449        ix += 1
[9ce7641c]1450        self.high_q_sizer.Add(self.power_high_tcl, (iy, ix), (1,1),
[c128284]1451                            wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[d0cc0bbc]1452        self.high_extrapolation_sizer.AddMany([(self.high_q_sizer, 0, 
1453                                                wx.BOTTOM|wx.RIGHT, 10)])
[c128284]1454       
[9ce7641c]1455    def _layout_extrapolation(self):
1456        """
[d7a39e5]1457        Draw widgets related to extrapolation
[9ce7641c]1458        """
[518d35d]1459        extra_hint = "Extrapolation Maximum Q Range [1/A]: "
[9ce7641c]1460        extra_hint_txt = wx.StaticText(self, -1, extra_hint)
1461        #Extrapolation range [string]
[4e1c362]1462        extrapolation_min_txt = wx.StaticText(self, -1, 'Min :') 
[518d35d]1463        self.extrapolation_min_tcl = OutputTextCtrl(self, -1, 
[4e1c362]1464                                                size=(_BOX_WIDTH, 20), style=0,name='extrapolation_min_tcl')
[9ce7641c]1465        self.extrapolation_min_tcl.SetValue(str(Q_MINIMUM))
1466        self.extrapolation_min_tcl.SetToolTipString("The minimum extrapolated q value.")
[4e1c362]1467        extrapolation_max_txt = wx.StaticText(self, -1, 'Max :') 
[518d35d]1468        self.extrapolation_max_tcl = OutputTextCtrl(self, -1,
[4e1c362]1469                                                  size=(_BOX_WIDTH, 20), style=0,name='extrapolation_max_tcl') 
[9ce7641c]1470        self.extrapolation_max_tcl.SetValue(str(Q_MAXIMUM))
1471        self.extrapolation_max_tcl.SetToolTipString("The maximum extrapolated q value.")
1472        self.extrapolation_range_sizer.AddMany([(extra_hint_txt, 0, wx.LEFT, 10),
1473                                                (extrapolation_min_txt, 0, wx.LEFT, 10),
1474                                                (self.extrapolation_min_tcl,
1475                                                            0, wx.LEFT, 10),
1476                                                (extrapolation_max_txt, 0, wx.LEFT, 10),
1477                                                (self.extrapolation_max_tcl,
1478                                                            0, wx.LEFT, 10),
1479                                                ])
1480        self._layout_extrapolation_low()
1481        self._layout_extrapolation_high()
1482        self.extrapolation_low_high_sizer.AddMany([(self.low_extrapolation_sizer,
[4e1c362]1483                                                     0, wx.ALL, 5),
[9ce7641c]1484                                                   (self.high_extrapolation_sizer,
[4e1c362]1485                                                    0, wx.ALL, 5)])
[9ce7641c]1486        self.extrapolation_sizer.AddMany([(self.extrapolation_range_sizer, 0,
[4e1c362]1487                                            wx.RIGHT, 5),
[9ce7641c]1488                                        (self.extrapolation_low_high_sizer, 0,
[4e1c362]1489                                           wx.ALL, 5)])
[9ce7641c]1490       
1491    def _layout_volume_surface_sizer(self):
1492        """
[d7a39e5]1493        Draw widgets related to volume and surface
[9ce7641c]1494        """
1495        unit_volume = ''
1496        unit_surface = ''
1497        uncertainty = "+/-" 
[dce0756]1498        volume_txt = wx.StaticText(self, -1, 'Volume Fraction      ')
[4e1c362]1499        self.volume_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH,-1),name='volume_tcl')
1500        wx.EVT_TEXT(self, self.volume_tcl.GetId(), self._on_out_text)
[9ce7641c]1501        self.volume_tcl.SetToolTipString("Volume fraction.")
[4e1c362]1502        self.volume_err_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH,-1),name='volume_err_tcl')
1503        wx.EVT_TEXT(self, self.volume_err_tcl.GetId(), self._on_out_text)
[9ce7641c]1504        self.volume_err_tcl.SetToolTipString("Uncertainty on the volume fraction.")
[c128284]1505        volume_units_txt = wx.StaticText(self, -1, unit_volume)
1506       
[277fad8]1507        surface_txt = wx.StaticText(self, -1, 'Specific Surface')
[4e1c362]1508        self.surface_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH,-1),name='surface_tcl')
1509        wx.EVT_TEXT(self, self.surface_tcl.GetId(), self._on_out_text)
[9ce7641c]1510        self.surface_tcl.SetToolTipString("Specific surface value.")
[4e1c362]1511        self.surface_err_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH,-1),name='surface_err_tcl')
1512        wx.EVT_TEXT(self, self.surface_err_tcl.GetId(), self._on_out_text)
[9ce7641c]1513        self.surface_err_tcl.SetToolTipString("Uncertainty on the specific surface.")
[c128284]1514        surface_units_txt = wx.StaticText(self, -1, unit_surface)
1515        iy = 0
1516        ix = 0
[9ce7641c]1517        self.volume_surface_sizer.Add(volume_txt, (iy, ix), (1,1),
[c128284]1518                             wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
[9ce7641c]1519        ix += 1
1520        self.volume_surface_sizer.Add(self.volume_tcl, (iy, ix), (1,1),
1521                            wx.EXPAND|wx.ADJUST_MINSIZE, 10)
1522        ix += 1
1523        self.volume_surface_sizer.Add(wx.StaticText(self, -1, uncertainty),
1524                         (iy, ix),(1,1),wx.EXPAND|wx.ADJUST_MINSIZE, 10) 
1525        ix += 1
1526        self.volume_surface_sizer.Add(self.volume_err_tcl, (iy, ix), (1,1),
1527                            wx.EXPAND|wx.ADJUST_MINSIZE, 10) 
1528        ix += 1
1529        self.volume_surface_sizer.Add(volume_units_txt, (iy, ix), (1,1),
1530                             wx.EXPAND|wx.ADJUST_MINSIZE, 10)
[c128284]1531        iy += 1
1532        ix = 0
[9ce7641c]1533        self.volume_surface_sizer.Add(surface_txt, (iy, ix), (1,1),
1534                             wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
[c128284]1535        ix += 1
[9ce7641c]1536        self.volume_surface_sizer.Add(self.surface_tcl, (iy, ix), (1,1),
1537                            wx.EXPAND|wx.ADJUST_MINSIZE, 0)
[c128284]1538        ix += 1
[9ce7641c]1539        self.volume_surface_sizer.Add(wx.StaticText(self, -1, uncertainty),
[c128284]1540                         (iy, ix),(1,1),wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
1541        ix += 1
[9ce7641c]1542        self.volume_surface_sizer.Add(self.surface_err_tcl, (iy, ix), (1,1),
[c128284]1543                            wx.EXPAND|wx.ADJUST_MINSIZE, 0) 
1544        ix += 1
[9ce7641c]1545        self.volume_surface_sizer.Add(surface_units_txt, (iy, ix), (1,1),
1546                            wx.EXPAND|wx.ADJUST_MINSIZE, 10)
1547       
1548    def _layout_invariant_sizer(self):
1549        """
[d7a39e5]1550        Draw widgets related to invariant
[9ce7641c]1551        """
1552        uncertainty = "+/-" 
[277fad8]1553        unit_invariant = '[1/(cm * A)]'
[eed601e]1554        invariant_total_txt = wx.StaticText(self, -1, 'Invariant Total [Q*]')
[4e1c362]1555        self.invariant_total_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH,-1),name='invariant_total_tcl')
[eed601e]1556        msg_hint = "Total invariant [Q*], including extrapolated regions."
[9ce7641c]1557        self.invariant_total_tcl.SetToolTipString(msg_hint)
[4e1c362]1558        self.invariant_total_err_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH,-1),name='invariant_total_err_tcl')
[9ce7641c]1559        self.invariant_total_err_tcl.SetToolTipString("Uncertainty on invariant.")
1560        invariant_total_units_txt = wx.StaticText(self, -1, unit_invariant)
1561   
1562        #Invariant total
1563        iy = 0
[c128284]1564        ix = 0
[9ce7641c]1565        self.invariant_sizer.Add(invariant_total_txt, (iy, ix), (1,1),
[c128284]1566                             wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 15)
[9ce7641c]1567        ix += 1
1568        self.invariant_sizer.Add(self.invariant_total_tcl, (iy, ix), (1,1),
[dce0756]1569                          wx.EXPAND|wx.ADJUST_MINSIZE, 10)
[c128284]1570        ix += 1
[9ce7641c]1571        self.invariant_sizer.Add( wx.StaticText(self, -1, uncertainty),
[277fad8]1572                         (iy, ix),(1,1),wx.EXPAND|wx.ADJUST_MINSIZE, 10) 
[c128284]1573        ix += 1
[9ce7641c]1574        self.invariant_sizer.Add(self.invariant_total_err_tcl, (iy, ix), (1,1),
[277fad8]1575                             wx.EXPAND|wx.ADJUST_MINSIZE, 10)
[c128284]1576        ix += 1
[277fad8]1577        self.invariant_sizer.Add(invariant_total_units_txt,(iy, ix), (1,1),
1578                          wx.EXPAND|wx.ADJUST_MINSIZE, 10)
[9ce7641c]1579 
[d0cc0bbc]1580    def _layout_inputs_sizer(self):
1581        """
[d7a39e5]1582        Draw widgets related to inputs
[d0cc0bbc]1583        """
1584        self._layout_bkg_scale()
1585        self._layout_contrast_porod()
1586        self.inputs_sizer.AddMany([(self.bkg_scale_sizer, 0, wx.ALL, 5),
1587                                    (self.contrast_porod_sizer, 0, wx.ALL, 5)])
1588       
[9ce7641c]1589    def _layout_outputs_sizer(self):
1590        """
[d7a39e5]1591        Draw widgets related to outputs
[9ce7641c]1592        """
1593        self._layout_volume_surface_sizer()
1594        self._layout_invariant_sizer()
1595        static_line = wx.StaticLine(self, -1)
1596        self.outputs_sizer.AddMany([(self.volume_surface_sizer, 0, wx.ALL, 10),
1597                                    (static_line, 0, wx.EXPAND, 0),
1598                                    (self.invariant_sizer, 0, wx.ALL, 10)])
1599    def _layout_button(self): 
1600        """
[d7a39e5]1601        Do the layout for the button widgets
[9ce7641c]1602        """ 
1603        #compute button
[c128284]1604        id = wx.NewId()
[4e1c362]1605        self.button_calculate = wx.Button(self, id, "Compute", name ='compute_invariant' )
[d0cc0bbc]1606        self.button_calculate.SetToolTipString("Compute invariant")
[9ce7641c]1607        self.Bind(wx.EVT_BUTTON, self.compute_invariant, id=id)   
1608        #detail button
1609        id = wx.NewId()
[d0cc0bbc]1610        self.button_details = wx.Button(self, id, "Details?")
[4e1c362]1611        self.button_details.SetToolTipString("Details about the results of the computation")
[9ce7641c]1612        self.Bind(wx.EVT_BUTTON, self.display_details, id=id)
1613        details = "Details on Invariant Total Calculations"
1614        details_txt = wx.StaticText(self, -1, details)
[4e1c362]1615        self.button_sizer.AddMany([((50,10), 0 , wx.LEFT,0),
[d0cc0bbc]1616                                   (details_txt, 0 , 
1617                                    wx.RIGHT|wx.BOTTOM|wx.TOP, 10),
1618                                   (self.button_details, 0 , wx.ALL, 10),
[4e1c362]1619                        (self.button_calculate, 0 , wx.RIGHT|wx.TOP|wx.BOTTOM, 10)])#,
1620                                   #(self.button_undo, 0 , wx.ALL, 10),
1621                                   #(self.button_redo, 0 , wx.ALL, 10)])
1622    def _layout_save_button(self): 
1623        """
1624        Do the layout for the save button widgets
1625        """ 
1626        import sans.perspectives.invariant as invariant
1627        path = invariant.get_data_path(media='media')
1628        self.undo_png = os.path.join(path,"undo.png")
1629        self.redo_png = os.path.join(path,"redo.png")
1630        self.save_png = os.path.join(path,"save.png")
1631        #undo button
1632        id = wx.NewId()
1633        self.button_undo = wx.BitmapButton(self, id,wx.Bitmap(self.undo_png))#wx.Button(self, id, "Undo",size=(50,20))
1634        self.button_undo.SetToolTipString("Undo")
1635        self.Bind(wx.EVT_BUTTON, self.undo, id=id)
1636        self.button_undo.Disable()
1637        #redo button
1638        id = wx.NewId()
1639        self.button_redo = wx.BitmapButton(self, id,wx.Bitmap(self.redo_png))#wx.Button(self, id, "Redo",size=(50,20))
1640        self.button_redo.SetToolTipString("Redo")
1641        self.Bind(wx.EVT_BUTTON, self.redo, id=id)
1642        self.button_redo.Disable()   
1643        #save button
1644        id = wx.NewId()
1645        self.button_save = wx.BitmapButton(self, id,wx.Bitmap(self.save_png), name ='Save_invariant')#wx.Button(self, id, "Save", name ='Save_invariant' )
1646        self.button_save.SetToolTipString("Save as a file")
1647        self.Bind(wx.EVT_BUTTON, self._on_save_button, id=id)   
1648        self.button_save.Disable() 
1649        self.save_button_sizer.AddMany([((PANEL_WIDTH/1.5,20), 1 , wx.EXPAND|wx.ADJUST_MINSIZE,0),
1650                                   (self.button_undo, 0 ,wx.LEFT|wx.ADJUST_MINSIZE, 10),
1651                                   (self.button_redo, 0 ,wx.LEFT|wx.ADJUST_MINSIZE, 10),
1652                                   (self.button_save, 0 ,wx.LEFT|wx.ADJUST_MINSIZE, 10)])       
[9ce7641c]1653    def _do_layout(self):
1654        """
[d7a39e5]1655        Draw window content
[9ce7641c]1656        """
1657        self._define_structure()
1658        self._layout_data_name()
1659        self._layout_extrapolation()
[d0cc0bbc]1660        self._layout_inputs_sizer()
[9ce7641c]1661        self._layout_outputs_sizer()
1662        self._layout_button()
[4e1c362]1663        self._layout_save_button()
[355b684]1664        self.main_sizer.AddMany([(self.data_name_boxsizer,0, wx.ALL, 10),
[9ce7641c]1665                                  (self.outputs_sizer, 0,
1666                                  wx.LEFT|wx.RIGHT|wx.BOTTOM, 10),
[355b684]1667                                  (self.button_sizer,0,
[d0cc0bbc]1668                                  wx.LEFT|wx.RIGHT|wx.BOTTOM, 10),
1669                                 (self.inputs_sizer, 0,
1670                                  wx.LEFT|wx.RIGHT|wx.BOTTOM, 10),
1671                                  (self.extrapolation_sizer, 0,
[4e1c362]1672                                  wx.LEFT|wx.RIGHT|wx.BOTTOM, 10),\
1673                                  (self.save_button_sizer,0,
[9ce7641c]1674                                  wx.LEFT|wx.RIGHT|wx.BOTTOM, 10)])
1675        self.SetSizer(self.main_sizer)
[355b684]1676        self.SetAutoLayout(True)
[c128284]1677   
1678class InvariantDialog(wx.Dialog):
[d7a39e5]1679    """
1680    """
[c128284]1681    def __init__(self, parent=None, id=1,graph=None,
[272d91e]1682                 data=None, title="Invariant",base=None):
1683        wx.Dialog.__init__(self, parent, id, title, size=(PANEL_WIDTH,
[c128284]1684                                                             PANEL_HEIGHT))
[272d91e]1685        self.panel = InvariantPanel(self)
[c128284]1686        self.Centre()
1687        self.Show(True)
1688       
1689class InvariantWindow(wx.Frame):
[d7a39e5]1690    """
1691    """
[272d91e]1692    def __init__(self, parent=None, id=1,graph=None, 
1693                 data=None, title="Invariant",base=None):
[c128284]1694       
[9ce7641c]1695        wx.Frame.__init__(self, parent, id, title, size=(PANEL_WIDTH +100,
1696                                                             PANEL_HEIGHT+100))
[4e1c362]1697        from DataLoader.loader import  Loader
1698        self.loader = Loader()
1699        import invariant
1700
1701        data= self.loader.load("C:/ECLPS/workspace/trunk/DataLoader/test/ascii_test_3.txt")
[272d91e]1702        self.panel = InvariantPanel(self)
[4e1c362]1703
1704        data.name = data.filename
1705        self.panel.set_data(data)
[c128284]1706        self.Centre()
1707        self.Show(True)
1708       
1709class MyApp(wx.App):
1710    def OnInit(self):
1711        wx.InitAllImageHandlers()
1712        frame = InvariantWindow()
1713        frame.Show(True)
1714        self.SetTopWindow(frame)
1715       
1716        return True
[272d91e]1717     
[c128284]1718# end of class MyApp
1719
1720if __name__ == "__main__":
1721    app = MyApp(0)
1722    app.MainLoop()
Note: See TracBrowser for help on using the repository browser.