source: sasview/invariantview/perspectives/invariant/invariant_panel.py @ b5a21aa

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since b5a21aa was 4e1c362, checked in by Jae Cho <jhjcho@…>, 14 years ago

Invariant: undo, redo, bookmark, and saving works now: needs plottool fix for making right order on plotting from file: also need some cleaning-up and doc.

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