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

magnetic_scattrelease-4.2.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249unittest-saveload
Last change on this file since ec4b19c was ec4b19c, checked in by krzywon, 6 years ago

Apply image handler to invariant report generation and fix issue with passed variables.

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