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

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

Moving things around. Will definitely not build.

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