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

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

Get rid of a bunch of bad exec

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