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

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.2.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since f2940c4 was 463e7ffc, checked in by Ricardo Ferraz Leal <ricleal@…>, 8 years ago

getLogger with module name

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