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

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 b9dbd6b was 1128bd31, checked in by Doucet, Mathieu <doucetm@…>, 10 years ago

pylint fixes

  • Property mode set to 100644
File size: 78.7 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
10import logging
11from wx.lib.scrolledpanel import ScrolledPanel
12from sas.invariant import invariant
13from sas.guiframe.utils import format_number
14from sas.guiframe.utils import check_float
15from sas.guiframe.events import StatusEvent
16from sas.guiframe.events import AppendBookmarkEvent
17from sas.perspectives.invariant.invariant_details import InvariantDetailsPanel
18from sas.perspectives.invariant.invariant_details import InvariantContainer
19from sas.perspectives.invariant.invariant_widgets import OutputTextCtrl
20from sas.perspectives.invariant.invariant_widgets import InvTextCtrl
21from sas.perspectives.invariant.invariant_state import InvariantState as IState
22from sas.guiframe.panel_base import PanelBase
23# The minimum q-value to be used when extrapolating
24Q_MINIMUM = 1e-5
25# The maximum q-value to be used when extrapolating
26Q_MAXIMUM = 10
27# the ratio of maximum q value/(qmax of data) to plot the theory data
28Q_MAXIMUM_PLOT = 3
29# the number of points to consider during fit
30NPTS = 10
31#Default value for background
32BACKGROUND = 0.0
33#default value for the scale
34SCALE = 1.0
35#default value of the contrast
36CONTRAST = 1.0
37#default value of the power used for power law
38POWER = 4.0
39#Invariant panel size
40_BOX_WIDTH = 76
41
42
43if sys.platform.count("win32") > 0:
44    _STATICBOX_WIDTH = 450
45    PANEL_WIDTH = 500
46    PANEL_HEIGHT = 700
47    FONT_VARIANT = 0
48else:
49    _STATICBOX_WIDTH = 490
50    PANEL_WIDTH = 530
51    PANEL_HEIGHT = 700
52    FONT_VARIANT = 1
53
54
55class InvariantPanel(ScrolledPanel, PanelBase):
56    """
57    Provides the Invariant GUI.
58    """
59    ## Internal nickname for the window, used by the AUI manager
60    window_name = "Invariant"
61    ## Name to appear on the window title bar
62    window_caption = "Invariant"
63    ## Flag to tell the AUI manager to put this panel in the center pane
64    CENTER_PANE = True
65    def __init__(self, parent, data=None, manager=None, *args, **kwds):
66        kwds["size"] = (PANEL_WIDTH, PANEL_HEIGHT)
67        kwds["style"] = wx.FULL_REPAINT_ON_RESIZE
68        ScrolledPanel.__init__(self, parent=parent, *args, **kwds)
69        PanelBase.__init__(self, parent)
70        self.SetupScrolling()
71        #Font size
72        self.SetWindowVariant(variant=FONT_VARIANT)
73        #Object that receive status event
74        self.parent = parent.parent
75        #plug-in using this panel
76        self._manager = manager
77        #Data uses for computation
78        self._data = data
79        self._scale = SCALE
80        self._background = BACKGROUND
81        self._bmark = None
82        self.bookmark_num = 0
83        self.state = None
84        self.popUpMenu = None
85        self._set_bookmark_menu()
86        #Init state
87        self.set_state()
88        # default flags for state
89        self.new_state = False
90        self.is_state_data = False
91        self.is_power_out = False
92
93        #container of invariant value
94        self.inv_container = None
95        #sizers
96        self.main_sizer = None
97        self.outputs_sizer = None
98        self.data_name_boxsizer = None
99        self.hint_msg_sizer = None
100        self.data_name_sizer = None
101        self.data_range_sizer = None
102        self.sizer_input = None
103        self.inputs_sizer = None
104        self.extrapolation_sizer = None
105        self.extrapolation_range_sizer = None
106        self.extrapolation_low_high_sizer = None
107        self.low_extrapolation_sizer = None
108        self.low_q_sizer = None
109        self.high_extrapolation_sizer = None
110        self.high_q_sizer = None
111        self.volume_surface_sizer = None
112        self.invariant_sizer = None
113        self.button_sizer = None
114        self.save_button_sizer = None
115        self.hint_msg_txt = None
116        self.data_name_tcl = None
117        self.data_min_tcl = None
118        self.data_max_tcl = None
119        #Draw the panel
120        self._do_layout()
121        self.reset_panel()
122        self._reset_state_list()
123        ## Default file location for save
124        self._default_save_location = os.getcwd()
125        if self.parent is not None:
126            msg = ""
127            wx.PostEvent(self.parent, StatusEvent(status=msg, info="info"))
128            self._default_save_location = \
129                        self.parent.get_save_location()
130
131        self._set_bookmark_flag(False)
132
133    def get_data(self):
134        """
135        """
136        return self._manager.get_data()
137
138    def get_state(self):
139        """
140        """
141        return self.state
142
143    def set_data(self, data):
144        """
145        Set the data
146        """
147        self._data = data
148        #edit the panel
149        if self._data is not None:
150            self._delete_bookmark_items()
151            self.get_state_by_num(0)
152            data_name = self._data.name
153            data_qmin = min(self._data.x)
154            data_qmax = max(self._data.x)
155            self.data_name_tcl.SetValue(str(data_name))
156            self.data_min_tcl.SetValue(str(data_qmin))
157            self.data_max_tcl.SetValue(str(data_qmax))
158            self.reset_panel()
159            self.compute_invariant(event=None)
160            self.state.file = self._data.name
161            #Reset the list of states
162            self.state.data = copy.deepcopy(data)
163            self._set_save_flag(True)
164            self._set_preview_flag(False)
165            self._reset_state_list()
166            self._set_bookmark_flag(True)
167        return True
168
169    def _delete_bookmark_items(self):
170        """
171        Delete bookmark menu items
172        """
173        # delete toolbar menu
174        self.parent.reset_bookmark_menu(self)
175        self.parent._update_toolbar_helper()
176        # delete popUpMenu items
177        pos = 0
178        for item in self.popUpMenu.GetMenuItems():
179            pos += 1
180            if pos < 3:
181                continue
182            self.popUpMenu.DestroyItem(item)
183
184    def set_message(self):
185        """
186        Display warning message if available
187        """
188        if self.inv_container is not None:
189            if self.inv_container.existing_warning:
190                msg = "Warning! Computations on invariant require your "
191                msg += "attention.\nPlease click on Details button."
192                self.hint_msg_txt.SetForegroundColour("red")
193
194                wx.PostEvent(self.parent,
195                             StatusEvent(status=msg, info="warning"))
196            else:
197                msg = "For more information, click on Details button."
198                self.hint_msg_txt.SetForegroundColour("black")
199                wx.PostEvent(self.parent,
200                             StatusEvent(status=msg, info="info"))
201            self.hint_msg_txt.SetLabel(msg)
202        self.Layout()
203
204    def set_manager(self, manager):
205        """
206        set value for the manager
207        """
208        self._manager = manager
209
210    def save_project(self, doc=None):
211        """
212        return an xml node containing state of the panel
213         that guiframe can write to file
214        """
215        data = self.get_data()
216        state = self.get_state()
217        if data is not None:
218            new_doc = self._manager.state_reader.write_toXML(data, state)
219            if new_doc is not None:
220                if doc is not None and hasattr(doc, "firstChild"):
221                    child = new_doc.getElementsByTagName("SASentry")
222                    for item in child:
223                        doc.firstChild.appendChild(item)
224                else:
225                    doc = new_doc
226        return doc
227
228    def set_state(self, state=None, data=None):
229        """
230        set state when loading it from a .inv/.svs file
231        """
232
233        if state == None and data == None:
234            self.state = IState()
235        elif state == None or data == None:
236            return
237        else:
238            new_state = copy.deepcopy(state)
239            self.new_state = True
240            if not self.set_data(data):
241                return
242
243            self.state = new_state
244            self.state.file = data.name
245
246            num = self.state.saved_state['state_num']
247            if num > 0:
248                self._set_undo_flag(True)
249            if num < len(state.state_list) - 1:
250                self._set_redo_flag(True)
251
252            # get bookmarks
253            self.bookmark_num = len(self.state.bookmark_list)
254            total_bookmark_num = self.bookmark_num + 1
255
256            for ind in range(1, total_bookmark_num):
257                #bookmark_num = ind
258                value = self.state.bookmark_list[ind]
259                name = "%d] bookmarked at %s on %s" % (ind, value[0], value[1])
260                # append it to menu
261                id = wx.NewId()
262                self.popUpMenu.Append(id, name, str(''))
263                wx.EVT_MENU(self, id, self._back_to_bookmark)
264                wx.PostEvent(self.parent,
265                             AppendBookmarkEvent(title=name,
266                                                 hint='',
267                                                 handler=self._back_to_bookmark))
268
269            self.get_state_by_num(state_num=str(num))
270
271            self._get_input_list()
272            #make sure that the data is reset (especially
273            # when loaded from a inv file)
274            self.state.data = self._data
275            self._set_preview_flag(False)
276            self.new_state = False
277            self.is_state_data = False
278
279    def clear_panel(self):
280        """
281        Clear panel to defaults, used by set_state of manager
282        """
283
284        self._data = None
285        # default data testctrl
286        self.hint_msg_txt.SetLabel('')
287        data_name = ''
288        data_qmin = ''
289        data_qmax = ''
290        self.data_name_tcl.SetValue(str(data_name))
291        self.data_min_tcl.SetValue(str(data_qmin))
292        self.data_max_tcl.SetValue(str(data_qmax))
293        #reset output textctrl
294        self._reset_output()
295        #reset panel
296        self.reset_panel()
297        #reset state w/o data
298        self.set_state()
299        # default flags for state
300        self.new_state = False
301        self.is_state_data = False
302        self.is_power_out = False
303
304    def get_background(self):
305        """
306        return the background textcrtl value as a float
307        """
308        background = self.background_tcl.GetValue().lstrip().rstrip()
309        if background == "":
310            raise ValueError, "Need a background"
311        if check_float(self.background_tcl):
312            return float(background)
313        else:
314            msg = "Receive invalid value for background : %s" % (background)
315            raise ValueError, msg
316
317    def get_scale(self):
318        """
319        return the scale textcrtl value as a float
320        """
321        scale = self.scale_tcl.GetValue().lstrip().rstrip()
322        if scale == "":
323            raise ValueError, "Need a background"
324        if check_float(self.scale_tcl):
325            if float(scale) <= 0.0:
326                self.scale_tcl.SetBackgroundColour("pink")
327                self.scale_tcl.Refresh()
328                msg = "Receive invalid value for scale: %s" % (scale)
329                raise ValueError, msg
330            return float(scale)
331        else:
332            raise ValueError, "Receive invalid value for scale : %s" % (scale)
333
334    def get_contrast(self):
335        """
336        return the contrast textcrtl value as a float
337        """
338        par_str = self.contrast_tcl.GetValue().strip()
339        contrast = None
340        if par_str != " " and check_float(self.contrast_tcl):
341            contrast = float(par_str)
342        return contrast
343
344    def get_extrapolation_type(self, low_q, high_q):
345        """
346        get extrapolation type
347        """
348        extrapolation = None
349        if low_q  and not high_q:
350            extrapolation = "low"
351        elif not low_q  and high_q:
352            extrapolation = "high"
353        elif low_q and high_q:
354            extrapolation = "both"
355        return extrapolation
356
357    def get_porod_const(self):
358        """
359        return the porod constant textcrtl value as a float
360        """
361        par_str = self.porod_constant_tcl.GetValue().strip()
362        porod_const = None
363        if par_str != "" and check_float(self.porod_constant_tcl):
364            porod_const = float(par_str)
365        return porod_const
366
367    def get_volume(self, inv, contrast, extrapolation):
368        """
369        get volume fraction
370        """
371        if contrast is not None:
372            try:
373                v, dv = inv.get_volume_fraction_with_error(contrast=contrast,
374                                                           extrapolation=extrapolation)
375                self.volume_tcl.SetValue(format_number(v))
376                self.volume_err_tcl.SetValue(format_number(dv))
377            except:
378                self.volume_tcl.SetValue(format_number(None))
379                self.volume_err_tcl.SetValue(format_number(None))
380                msg = "Error occurred computing volume "
381                msg += " fraction: %s" % sys.exc_value
382                wx.PostEvent(self.parent, StatusEvent(status=msg,
383                                                      info="error",
384                                                      type="stop"))
385
386    def get_surface(self, inv, contrast, porod_const, extrapolation):
387        """
388        get surface value
389        """
390        if contrast is not None and porod_const is not None:
391            try:
392                s, ds = inv.get_surface_with_error(contrast=contrast,
393                                                   porod_const=porod_const,
394                                                   extrapolation=extrapolation)
395                self.surface_tcl.SetValue(format_number(s))
396                self.surface_err_tcl.SetValue(format_number(ds))
397            except:
398                self.surface_tcl.SetValue(format_number(None))
399                self.surface_err_tcl.SetValue(format_number(None))
400                msg = "Error occurred computing "
401                msg += "specific surface: %s" % sys.exc_value
402                wx.PostEvent(self.parent, StatusEvent(status=msg, info="error",
403                                                      type="stop"))
404
405    def get_total_qstar(self, inv, extrapolation):
406        """
407        get total qstar
408        """
409        try:
410            qstar_total, qstar_total_err = \
411                                    inv.get_qstar_with_error(extrapolation)
412            self.invariant_total_tcl.SetValue(format_number(qstar_total))
413            self.invariant_total_err_tcl.SetValue(\
414                                    format_number(qstar_total_err))
415            self.inv_container.qstar_total = qstar_total
416            self.inv_container.qstar_total_err = qstar_total_err
417        except:
418            self.inv_container.qstar_total = "Error"
419            self.inv_container.qstar_total_err = "Error"
420            self.invariant_total_tcl.SetValue(format_number(None))
421            self.invariant_total_err_tcl.SetValue(format_number(None))
422            msg = "Error occurred computing invariant using"
423            msg += " extrapolation: %s" % sys.exc_value
424            wx.PostEvent(self.parent, StatusEvent(status=msg, type="stop"))
425
426    def get_low_qstar(self, inv, npts_low, low_q=False):
427        """
428        get low qstar
429        """
430        if low_q:
431            try:
432                qstar_low, qstar_low_err = inv.get_qstar_low()
433                self.inv_container.qstar_low = qstar_low
434                self.inv_container.qstar_low_err = qstar_low_err
435                extrapolated_data = inv.get_extra_data_low(npts_in=npts_low)
436                power_low = inv.get_extrapolation_power(range='low')
437                if self.power_law_low.GetValue():
438                    self.power_low_tcl.SetValue(format_number(power_low))
439                self._manager.plot_theory(data=extrapolated_data,
440                                          name="Low-Q extrapolation")
441            except:
442                self.inv_container.qstar_low = "ERROR"
443                self.inv_container.qstar_low_err = "ERROR"
444                self._manager.plot_theory(name="Low-Q extrapolation")
445                msg = "Error occurred computing low-Q "
446                msg += "invariant: %s" % sys.exc_value
447                wx.PostEvent(self.parent,
448                             StatusEvent(status=msg, type="stop"))
449                raise
450        else:
451            try:
452                self._manager.plot_theory(name="Low-Q extrapolation")
453            except:
454                logging.error(sys.exc_value)
455
456    def get_high_qstar(self, inv, high_q=False):
457        """
458        get high qstar
459        """
460        if high_q:
461            try:
462                qmax_plot = Q_MAXIMUM_PLOT * max(self._data.x)
463                if qmax_plot > Q_MAXIMUM:
464                    qmax_plot = Q_MAXIMUM
465                qstar_high, qstar_high_err = inv.get_qstar_high()
466                self.inv_container.qstar_high = qstar_high
467                self.inv_container.qstar_high_err = qstar_high_err
468                power_high = inv.get_extrapolation_power(range='high')
469                self.power_high_tcl.SetValue(format_number(power_high))
470                high_out_data = inv.get_extra_data_high(q_end=qmax_plot,
471                                                        npts=500)
472                self._manager.plot_theory(data=high_out_data,
473                                          name="High-Q extrapolation")
474            except:
475                #raise
476                self.inv_container.qstar_high = "ERROR"
477                self.inv_container.qstar_high_err = "ERROR"
478                self._manager.plot_theory(name="High-Q extrapolation")
479                msg = "Error occurred computing high-Q "
480                msg += "invariant: %s" % sys.exc_value
481                wx.PostEvent(self.parent, StatusEvent(status=msg,
482                                                      type="stop"))
483                raise
484        else:
485            try:
486                self._manager.plot_theory(name="High-Q extrapolation")
487            except:
488                logging.error(sys.exc_value)
489
490    def get_qstar(self, inv):
491        """
492        get qstar
493        """
494        qstar, qstar_err = inv.get_qstar_with_error()
495        self.inv_container.qstar = qstar
496        self.inv_container.qstar_err = qstar_err
497
498    def set_extrapolation_low(self, inv, low_q=False):
499        """
500        return float value necessary to compute invariant a low q
501        """
502        #get funtion
503        if self.guinier.GetValue():
504            function_low = "guinier"
505        # get the function
506        power_low = None #2.0/3.0
507        if self.power_law_low.GetValue():
508            function_low = "power_law"
509            if self.fit_enable_low.GetValue():
510                #set value of power_low to none to allow fitting
511                power_low = None
512            else:
513                power_low = self.power_low_tcl.GetValue().lstrip().rstrip()
514                if check_float(self.power_low_tcl):
515                    power_low = float(power_low)
516                else:
517                    if low_q:
518                        #Raise error only when qstar at low q is requested
519                        msg = "Expect float for power at low q, "
520                        msg += " got %s" % (power_low)
521                        wx.PostEvent(self.parent,
522                                     StatusEvent(status=msg,
523                                                 info="error",
524                                                 type="stop"))
525
526        #Get the number of points to extrapolated
527        npts_low = self.npts_low_tcl.GetValue().lstrip().rstrip()
528        if check_float(self.npts_low_tcl):
529            npts_low = float(npts_low)
530        else:
531            if low_q:
532                msg = "Expect float for number of points at low q,"
533                msg += " got %s" % (npts_low)
534                wx.PostEvent(self.parent,
535                             StatusEvent(status=msg,
536                                         info="error",
537                                         type="stop"))
538        #Set the invariant calculator
539        inv.set_extrapolation(range="low", npts=npts_low,
540                              function=function_low, power=power_low)
541        return inv, npts_low
542
543
544    def set_extrapolation_high(self, inv, high_q=False):
545        """
546        return float value necessary to compute invariant a high q
547        """
548        power_high = None
549        #if self.power_law_high.GetValue():
550        function_high = "power_law"
551        if self.fit_enable_high.GetValue():
552            #set value of power_high to none to allow fitting
553            power_high = None
554        else:
555            power_high = self.power_high_tcl.GetValue().lstrip().rstrip()
556            if check_float(self.power_high_tcl):
557                power_high = float(power_high)
558            else:
559                if high_q:
560                    #Raise error only when qstar at high q is requested
561                    msg = "Expect float for power at high q,"
562                    msg += " got %s" % (power_high)
563                    wx.PostEvent(self.parent,
564                                 StatusEvent(status=msg,
565                                             info="error",
566                                             type="stop"))
567
568        npts_high = self.npts_high_tcl.GetValue().lstrip().rstrip()
569        if check_float(self.npts_high_tcl):
570            npts_high = float(npts_high)
571        else:
572            if high_q:
573                msg = "Expect float for number of points at high q,"
574                msg += " got %s" % (npts_high)
575                wx.PostEvent(self.parent, StatusEvent(status=msg,
576                                                      info="error",
577                                                      type="stop"))
578        inv.set_extrapolation(range="high", npts=npts_high,
579                              function=function_high, power=power_high)
580        return inv, npts_high
581
582    def display_details(self, event):
583        """
584        open another panel for more details on invariant calculation
585        """
586        panel = InvariantDetailsPanel(parent=self,
587                                      qstar_container=self.inv_container)
588        panel.ShowModal()
589        panel.Destroy()
590        self.button_calculate.SetFocus()
591
592    def compute_invariant(self, event=None):
593        """
594        compute invariant
595        """
596        if self._data == None:
597            msg = "\n\nData must be loaded first in order"
598            msg += " to perform a compution..."
599            wx.PostEvent(self.parent, StatusEvent(status=msg))
600        # set a state for this computation for saving
601        elif event != None:
602            self._set_compute_state(state='compute')
603            self._set_bookmark_flag(True)
604            msg = "\n\nStarting a new invariant computation..."
605            wx.PostEvent(self.parent, StatusEvent(status=msg))
606
607
608        if self._data is None:
609            return
610        self.button_details.Enable()
611        #clear outputs textctrl
612        self._reset_output()
613        try:
614            background = self.get_background()
615            scale = self.get_scale()
616        except:
617            msg = "Invariant Error: %s" % (sys.exc_value)
618            wx.PostEvent(self.parent, StatusEvent(status=msg, type="stop"))
619            return
620
621        low_q = self.enable_low_cbox.GetValue()
622        high_q = self.enable_high_cbox.GetValue()
623        temp_data = copy.deepcopy(self._data)
624
625        #set invariant calculator
626        inv = invariant.InvariantCalculator(data=temp_data,
627                                            background=background,
628                                            scale=scale)
629        try:
630            inv, npts_low = self.set_extrapolation_low(inv=inv, low_q=low_q)
631            inv, npts_high = self.set_extrapolation_high(inv=inv, high_q=high_q)
632        except:
633            msg = "Error occurred computing invariant: %s" % sys.exc_value
634            wx.PostEvent(self.parent, StatusEvent(status=msg,
635                                                  info="warning", type="stop"))
636            return
637        #check the type of extrapolation
638        extrapolation = self.get_extrapolation_type(low_q=low_q, high_q=high_q)
639
640        #Compute invariant
641        try:
642            self.get_qstar(inv=inv)
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.perspectives.invariant.report_dialog 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.Show()
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
798        # get the state at pre_compute_num
799        comp_state = copy.deepcopy(self.state.state_list[current_compute_num])
800
801        # set the parameters
802        for key in comp_state:
803            value = comp_state[key]
804            try:
805                exec "self.%s.SetValue(str(%s))" % (key, value)
806            except TypeError:
807                exec "self.%s.SetValue(%s)" % (key, value)
808            except:
809                logging.error(sys.exc_value)
810
811        self.compute_invariant(event=None)
812
813        # set the input params at the state at pre_state_num
814        for key in current_state:
815            # set the inputs and boxes
816            value = current_state[key]
817            try:
818                exec 'self.%s.SetValue(str(%s))' % (key, value)
819            except TypeError:
820                exec 'self.%s.SetValue(%s)' % (key, value)
821            except:
822                logging.error(sys.exc_value)
823
824        self._enable_high_q_section(event=None)
825        self._enable_low_q_section(event=None)
826        self.state.state_list = backup_state_list
827        self.state.saved_state = current_state
828        self.state.state_num = state_num
829
830
831    def get_bookmark_by_num(self, num=None):
832        """
833        Get the bookmark state given by number
834
835        : param num: the given bookmark number
836
837        """
838        current_state = {}
839        comp_state = {}
840        backup_state_list = copy.deepcopy(self.state.state_list)
841
842        # get the previous state
843        try:
844            _, _, current_state, comp_state = self.state.bookmark_list[int(num)]
845        except:
846            logging.error(sys.exc_value)
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                logging.error(sys.exc_value)
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                logging.error(sys.exc_value)
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            logging.error(sys.exc_value)
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                logging.error(sys.exc_value)
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                logging.error(sys.exc_value)
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            logging.error(sys.exc_value)
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            logging.error(sys.exc_value)
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, _ = 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([(self.low_extrapolation_sizer,
1677                                                    0, wx.LEFT | wx.BOTTOM | wx.TOP, 5),
1678                                                   (self.high_extrapolation_sizer,
1679                                                    0, wx.LEFT | wx.BOTTOM | wx.TOP, 5)])
1680        self.extrapolation_sizer.AddMany([(self.extrapolation_range_sizer),
1681                                          (self.extrapolation_low_high_sizer)])
1682
1683    def _layout_volume_surface_sizer(self):
1684        """
1685        Draw widgets related to volume and surface
1686        """
1687        unit_volume = ''
1688        unit_surface = '[1/A]'
1689        uncertainty = "+/-"
1690        volume_txt = wx.StaticText(self, -1, 'Volume Fraction')
1691        self.volume_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, -1),
1692                                         name='volume_tcl')
1693        wx.EVT_TEXT(self, self.volume_tcl.GetId(), self._on_out_text)
1694        self.volume_tcl.SetToolTipString("Volume fraction.")
1695        self.volume_err_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, -1),
1696                                             name='volume_err_tcl')
1697        wx.EVT_TEXT(self, self.volume_err_tcl.GetId(), self._on_out_text)
1698        hint_msg = "Uncertainty on the volume fraction."
1699        self.volume_err_tcl.SetToolTipString(hint_msg)
1700        volume_units_txt = wx.StaticText(self, -1, unit_volume)
1701
1702        surface_txt = wx.StaticText(self, -1, 'Specific Surface')
1703        self.surface_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, -1),
1704                                          name='surface_tcl')
1705        wx.EVT_TEXT(self, self.surface_tcl.GetId(), self._on_out_text)
1706        self.surface_tcl.SetToolTipString("Specific surface value.")
1707        self.surface_err_tcl = OutputTextCtrl(self, -1, size=(_BOX_WIDTH, -1),
1708                                              name='surface_err_tcl')
1709        wx.EVT_TEXT(self, self.surface_err_tcl.GetId(), self._on_out_text)
1710        hint_msg = "Uncertainty on the specific surface."
1711        self.surface_err_tcl.SetToolTipString(hint_msg)
1712        surface_units_txt = wx.StaticText(self, -1, unit_surface)
1713        iy = 0
1714        ix = 0
1715        self.volume_surface_sizer.Add(volume_txt, (iy, ix), (1, 1),
1716                                      wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
1717        ix += 1
1718        self.volume_surface_sizer.Add(self.volume_tcl, (iy, ix), (1, 1),
1719                                      wx.EXPAND | wx.ADJUST_MINSIZE, 20)
1720        ix += 1
1721        self.volume_surface_sizer.Add(wx.StaticText(self, -1, uncertainty),
1722                                      (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 10)
1723        ix += 1
1724        self.volume_surface_sizer.Add(self.volume_err_tcl, (iy, ix), (1, 1),
1725                                      wx.EXPAND | wx.ADJUST_MINSIZE, 10)
1726        ix += 1
1727        self.volume_surface_sizer.Add(volume_units_txt, (iy, ix), (1, 1),
1728                                      wx.EXPAND | wx.ADJUST_MINSIZE, 10)
1729        iy += 1
1730        ix = 0
1731        self.volume_surface_sizer.Add(surface_txt, (iy, ix), (1, 1),
1732                                      wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
1733        ix += 1
1734        self.volume_surface_sizer.Add(self.surface_tcl, (iy, ix), (1, 1),
1735                                      wx.EXPAND | wx.ADJUST_MINSIZE, 20)
1736        ix += 1
1737        self.volume_surface_sizer.Add(wx.StaticText(self, -1, uncertainty),
1738                                      (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 10)
1739        ix += 1
1740        self.volume_surface_sizer.Add(self.surface_err_tcl, (iy, ix), (1, 1),
1741                                      wx.EXPAND | wx.ADJUST_MINSIZE, 10)
1742        ix += 1
1743        self.volume_surface_sizer.Add(surface_units_txt, (iy, ix), (1, 1),
1744                                      wx.EXPAND | wx.ADJUST_MINSIZE, 10)
1745        static_line = wx.StaticLine(self, -1)
1746        iy += 1
1747        ix = 0
1748
1749    def _layout_invariant_sizer(self):
1750        """
1751        Draw widgets related to invariant
1752        """
1753        uncertainty = "+/-"
1754        unit_invariant = '[1/(cm*A^3)]'
1755        invariant_total_txt = wx.StaticText(self, -1, 'Invariant Total [Q*]')
1756        self.invariant_total_tcl = OutputTextCtrl(self, -1,
1757                                                  size=(_BOX_WIDTH, -1),
1758                                                  name='invariant_total_tcl')
1759        msg_hint = "Total invariant [Q*], including extrapolated regions."
1760        self.invariant_total_tcl.SetToolTipString(msg_hint)
1761        self.invariant_total_err_tcl = OutputTextCtrl(self, -1,
1762                                                      size=(_BOX_WIDTH, -1),
1763                                                      name='invariant_total_err_tcl')
1764        hint_msg = "Uncertainty on invariant."
1765        self.invariant_total_err_tcl.SetToolTipString(hint_msg)
1766        invariant_total_units_txt = wx.StaticText(self, -1, unit_invariant,
1767                                                  size=(80, -1))
1768
1769        #Invariant total
1770        iy = 0
1771        ix = 0
1772        self.invariant_sizer.Add(invariant_total_txt, (iy, ix), (1, 1),
1773                                 wx.LEFT | wx.EXPAND | wx.ADJUST_MINSIZE, 15)
1774        ix += 1
1775        self.invariant_sizer.Add(self.invariant_total_tcl, (iy, ix), (1, 1),
1776                                 wx.EXPAND | wx.ADJUST_MINSIZE, 10)
1777        ix += 1
1778        self.invariant_sizer.Add(wx.StaticText(self, -1, uncertainty),
1779                                 (iy, ix), (1, 1), wx.EXPAND | wx.ADJUST_MINSIZE, 10)
1780        ix += 1
1781        self.invariant_sizer.Add(self.invariant_total_err_tcl, (iy, ix), (1, 1),
1782                                 wx.EXPAND | wx.ADJUST_MINSIZE, 10)
1783        ix += 1
1784        self.invariant_sizer.Add(invariant_total_units_txt, (iy, ix), (1, 1),
1785                                 wx.EXPAND | wx.ADJUST_MINSIZE, 10)
1786
1787    def _layout_inputs_sizer(self):
1788        """
1789        Draw widgets related to inputs
1790        """
1791        contrast_txt = wx.StaticText(self, -1, 'Contrast:')
1792        self.contrast_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
1793                                        style=0, name='contrast_tcl')
1794        wx.EVT_TEXT(self, self.contrast_tcl.GetId(), self._on_text)
1795        contrast_hint_txt = "Contrast"
1796        self.contrast_tcl.SetToolTipString(contrast_hint_txt)
1797        contrast_unit_txt = wx.StaticText(self, -1, '[1/A^2]', size=(40, -1))
1798        porod_const_txt = wx.StaticText(self, -1,
1799                                        'Porod\nConstant:\n(optional)\n')
1800        porod_unit_txt = wx.StaticText(self, -1, '[1/(cm*A^4)]', size=(80, -1))
1801        self.porod_constant_tcl = InvTextCtrl(self, -1,
1802                                              size=(_BOX_WIDTH, 20), style=0,
1803                                              name='porod_constant_tcl')
1804        wx.EVT_TEXT(self, self.porod_constant_tcl.GetId(), self._on_text)
1805        porod_const_hint_txt = "Porod Constant"
1806        self.porod_constant_tcl.SetToolTipString(porod_const_hint_txt)
1807
1808        background_txt = wx.StaticText(self, -1, 'Background:')
1809        self.background_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH, 20),
1810                                          style=0, name='background_tcl')
1811        wx.EVT_TEXT(self, self.background_tcl.GetId(), self._on_text)
1812        background_hint_txt = "Background"
1813        self.background_tcl.SetToolTipString(background_hint_txt)
1814        background_unit_txt = wx.StaticText(self, -1, '[1/cm]')
1815        scale_txt = wx.StaticText(self, -1, 'Scale:')
1816        self.scale_tcl = InvTextCtrl(self, -1, size=(_BOX_WIDTH, 20), style=0,
1817                                     name='scale_tcl')
1818        wx.EVT_TEXT(self, self.scale_tcl.GetId(), self._on_text)
1819        scale_hint_txt = "Scale"
1820        self.scale_tcl.SetToolTipString(scale_hint_txt)
1821        self.sizer_input.AddMany([(background_txt, 0, wx.LEFT | wx.BOTTOM, 5),
1822                                  (self.background_tcl, 0, wx.LEFT | wx.BOTTOM, 5),
1823                                  (background_unit_txt, 0, wx.LEFT | wx.BOTTOM, 5),
1824                                  (scale_txt, 0, wx.LEFT | wx.BOTTOM, 10),
1825                                  (self.scale_tcl, 0, wx.LEFT | wx.BOTTOM | wx.RIGHT, 5),
1826                                  (10, 10),
1827                                  (contrast_txt, 0, wx.LEFT | wx.BOTTOM, 5),
1828                                  (self.contrast_tcl, 0, wx.LEFT | wx.BOTTOM, 5),
1829                                  (contrast_unit_txt, 0, wx.LEFT | wx.BOTTOM, 5),
1830                                  (porod_const_txt, 0, wx.LEFT, 10),
1831                                  (self.porod_constant_tcl, 0, wx.LEFT | wx.BOTTOM | wx.RIGHT, 5),
1832                                  (porod_unit_txt, 0, wx.LEFT | wx.BOTTOM, 5)])
1833        self.inputs_sizer.Add(self.sizer_input)
1834
1835    def _layout_outputs_sizer(self):
1836        """
1837        Draw widgets related to outputs
1838        """
1839        self._layout_volume_surface_sizer()
1840        self._layout_invariant_sizer()
1841        static_line = wx.StaticLine(self, -1)
1842        self.outputs_sizer.AddMany([(self.volume_surface_sizer,
1843                                     0, wx.TOP | wx.BOTTOM, 10),
1844                                    (static_line, 0, wx.EXPAND, 0),
1845                                    (self.invariant_sizer, 0, wx.TOP | wx.BOTTOM, 10)])
1846    def _layout_button(self):
1847        """
1848        Do the layout for the button widgets
1849        """
1850        #compute button
1851        id = wx.NewId()
1852        self.button_calculate = wx.Button(self, id, "Compute",
1853                                          name='compute_invariant')
1854        self.button_calculate.SetToolTipString("Compute invariant")
1855        self.Bind(wx.EVT_BUTTON, self.compute_invariant, id=id)
1856        #detail button
1857        id = wx.NewId()
1858        self.button_details = wx.Button(self, id, "Details?")
1859        hint_msg = "Details about the results of the computation"
1860        self.button_details.SetToolTipString(hint_msg)
1861        self.Bind(wx.EVT_BUTTON, self.display_details, id=id)
1862        details = "Details on Invariant Total Calculations"
1863        details_txt = wx.StaticText(self, -1, details)
1864        self.button_sizer.AddMany([(details_txt, 0,
1865                                    wx.RIGHT | wx.BOTTOM | wx.TOP, 10),
1866                                   (self.button_details, 0, wx.ALL, 10),
1867                                   (self.button_calculate, 0,
1868                                    wx.RIGHT | wx.TOP | wx.BOTTOM, 10)])
1869    def _do_layout(self):
1870        """
1871        Draw window content
1872        """
1873        self._define_structure()
1874        self._layout_data_name()
1875        self._layout_extrapolation()
1876        self._layout_inputs_sizer()
1877        self._layout_outputs_sizer()
1878        self._layout_button()
1879        self.main_sizer.AddMany([(self.data_name_boxsizer, 0, wx.ALL, 10),
1880                                 (self.outputs_sizer, 0,
1881                                  wx.LEFT | wx.RIGHT | wx.BOTTOM, 10),
1882                                 (self.button_sizer, 0, wx.LEFT | wx.RIGHT, 15),
1883                                 (self.inputs_sizer, 0,
1884                                  wx.LEFT | wx.RIGHT | wx.BOTTOM, 10),
1885                                 (self.extrapolation_sizer, 0,
1886                                  wx.LEFT | wx.RIGHT | wx.BOTTOM, 10)])
1887        self.SetSizer(self.main_sizer)
1888        self.SetAutoLayout(True)
1889
1890
1891class InvariantDialog(wx.Dialog):
1892    """
1893    Invariant Dialog
1894    """
1895    def __init__(self, parent=None, id=1, graph=None,
1896                 data=None, title="Invariant", base=None):
1897        wx.Dialog.__init__(self, parent, id, title, size=(PANEL_WIDTH,
1898                                                          PANEL_HEIGHT))
1899        self.panel = InvariantPanel(self)
1900        self.Centre()
1901        self.Show(True)
1902
1903class InvariantWindow(wx.Frame):
1904    """
1905    Invariant Window
1906    """
1907    def __init__(self, parent=None, id=1, graph=None,
1908                 data=None, title="Invariant", base=None):
1909
1910        wx.Frame.__init__(self, parent, id, title, size=(PANEL_WIDTH + 100,
1911                                                         PANEL_HEIGHT + 100))
1912        from sas.dataloader.loader import  Loader
1913        self.loader = Loader()
1914        path = "C:/ECLPS/workspace/trunk/sasdataloader/test/ascii_test_3.txt"
1915        data = self.loader.load(path)
1916        self.panel = InvariantPanel(self)
1917
1918        data.name = data.filename
1919        self.panel.set_data(data)
1920        self.Centre()
1921        self.Show(True)
1922
1923class MyApp(wx.App):
1924    """
1925    Test App
1926    """
1927    def OnInit(self):
1928        """
1929        Init
1930        """
1931        wx.InitAllImageHandlers()
1932        frame = InvariantWindow()
1933        frame.Show(True)
1934        self.SetTopWindow(frame)
1935
1936        return True
1937
1938# end of class MyApp
1939
1940if __name__ == "__main__":
1941    app = MyApp(0)
1942    app.MainLoop()
Note: See TracBrowser for help on using the repository browser.