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

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

working on loading data to invariant panel

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