source: sasview/invariantview/perspectives/invariant/invariant_panel.py @ 9fb814a

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 9fb814a was aa5617d, checked in by Gervaise Alina <gervyh@…>, 14 years ago

remove print

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