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

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

working on invariant save state

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