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

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 79492222 was 79492222, checked in by krzywon, 9 years ago

Changed the file and folder names to remove all SANS references.

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