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

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 3db44fb was 3db44fb, checked in by butler, 9 years ago

1) Fixed second issue that was caused by the recent cleanup of
DocumentationWindow?: loading html at anchor point for context help
(broken). In order to preserve the cleanup, the class was refactored to
take another parameter: html instruction string. This keeps it general
to accept not only the # anchor but alos queries of all sorts in the
future. Thus all modules using this class were also edited to match.

2) in process of editing the dozen or so instances did a bit of code
cleanup and pylint cleanup.

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