source: sasview/invariantview/src/sans/perspectives/invariant/invariant_panel.py @ c4f79f0

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 c4f79f0 was 0d417ac8, checked in by Jae Cho <jhjcho@…>, 13 years ago

fixing pylint warnings

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