source: sasview/src/sas/perspectives/invariant/invariant_panel.py @ efa5e44

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 efa5e44 was d838715, checked in by Mathieu Doucet <doucetm@…>, 10 years ago

The report dialog can't be modal if the print preview is to be used.

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