source: sasview/invariantview/perspectives/invariant/invariant_panel.py @ 07c8630

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 07c8630 was 37e0e5d, checked in by Jae Cho <jhjcho@…>, 13 years ago

removed setfocusignoringchild

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