Changeset 1619


Ignore:
Timestamp:
Dec 26, 2014 9:58:22 PM (7 years ago)
Author:
toby
Message:

add columnsorter for hetrogeneous seq ref; reorg to start moving widgets out of g2grid

Location:
trunk
Files:
1 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/GSASII.py

    r1618 r1619  
    6868import GSASIIIO as G2IO
    6969import GSASIIgrid as G2gd
     70import GSASIIctrls as G2G
    7071import GSASIIplot as G2plt
    7172import GSASIIpwd as G2pwd
     
    14551456            else:
    14561457                inp = [rd.idstring, 10.,80.,0.01] # see names for what's what
    1457             dlg = G2gd.ScrolledMultiEditor(
     1458            dlg = G2G.ScrolledMultiEditor(
    14581459                self,[inp] * len(inp),range(len(inp)),names,
    14591460                header='Enter simulation name and range',
     
    20372038        wxID_PATTERNTREE = wx.NewId()
    20382039        #self.PatternTree = wx.TreeCtrl(id=wxID_PATTERNTREE, # replaced for logging
    2039         self.PatternTree = G2gd.G2TreeCtrl(id=wxID_PATTERNTREE,
     2040        self.PatternTree = G2G.G2TreeCtrl(id=wxID_PATTERNTREE,
    20402041            parent=self.mainPanel, pos=wx.Point(0, 0),style=wx.TR_DEFAULT_STYLE )
    20412042        self.PatternTree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnPatternTreeSelChanged)
  • trunk/GSASIIIO.py

    r1603 r1619  
    3838import GSASIIstrIO as G2stIO
    3939import GSASIImapvars as G2mv
     40import GSASIIctrls as G2G
    4041import os
    4142import os.path as ospath
     
    206207    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Wavelength (\xC5) '),
    207208               0,wx.ALIGN_LEFT|wx.ALL, 2)
    208     wdgt = G2gd.ValidatedTxtCtrl(dlg,Data,'wavelength')
     209    wdgt = G2G.ValidatedTxtCtrl(dlg,Data,'wavelength')
    209210    vsizer.Add(wdgt)
    210211    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
     
    213214    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Pixel size (\xb5m). Width '),
    214215               0,wx.ALIGN_LEFT|wx.ALL, 2)
    215     wdgt = G2gd.ValidatedTxtCtrl(dlg,Data['pixelSize'],0,
     216    wdgt = G2G.ValidatedTxtCtrl(dlg,Data['pixelSize'],0,
    216217                                 size=(50,-1))
    217218    vsizer.Add(wdgt)
    218219    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'  Height '),
    219220               wx.ALIGN_LEFT|wx.ALL, 2)
    220     wdgt = G2gd.ValidatedTxtCtrl(dlg,Data['pixelSize'],1,
     221    wdgt = G2G.ValidatedTxtCtrl(dlg,Data['pixelSize'],1,
    221222                                 size=(50,-1))
    222223    vsizer.Add(wdgt)
     
    226227    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Sample to detector (mm) '),
    227228               0,wx.ALIGN_LEFT|wx.ALL, 2)
    228     wdgt = G2gd.ValidatedTxtCtrl(dlg,Data,'distance')
     229    wdgt = G2G.ValidatedTxtCtrl(dlg,Data,'distance')
    229230    vsizer.Add(wdgt)
    230231    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
     
    233234    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Beam center (pixels). X = '),
    234235               0,wx.ALIGN_LEFT|wx.ALL, 2)
    235     wdgt = G2gd.ValidatedTxtCtrl(dlg,Data['center'],0,
     236    wdgt = G2G.ValidatedTxtCtrl(dlg,Data['center'],0,
    236237                                 size=(75,-1))
    237238    vsizer.Add(wdgt)
    238239    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'  Y = '),
    239240               wx.ALIGN_LEFT|wx.ALL, 2)
    240     wdgt = G2gd.ValidatedTxtCtrl(dlg,Data['center'],1,
     241    wdgt = G2G.ValidatedTxtCtrl(dlg,Data['center'],1,
    241242                                 size=(75,-1))
    242243    vsizer.Add(wdgt)
     
    246247    vsizer.Add(wx.StaticText(dlg,wx.ID_ANY,u'Comments '),
    247248               0,wx.ALIGN_LEFT|wx.ALL, 2)
    248     wdgt = G2gd.ValidatedTxtCtrl(dlg,Comments,0,size=(250,-1))
     249    wdgt = G2G.ValidatedTxtCtrl(dlg,Comments,0,size=(250,-1))
    249250    vsizer.Add(wdgt)
    250251    mainsizer.Add(vsizer,0,wx.ALIGN_LEFT|wx.ALL, 2)
  • trunk/GSASIIconstrGUI.py

    r1545 r1619  
    3131import GSASIImapvars as G2mv
    3232import GSASIIgrid as G2gd
     33import GSASIIctrls as G2G
    3334import GSASIIplot as G2plt
    3435import GSASIIobj as G2obj
     
    119120            name = wx.StaticText(panel,wx.ID_ANY,lbl1,
    120121                                 style=wx.ALIGN_RIGHT)
    121             scale = G2gd.ValidatedTxtCtrl(panel,self.data[id],0,
     122            scale = G2G.ValidatedTxtCtrl(panel,self.data[id],0,
    122123                                          typeHint=float,
    123124                                          OKcontrol=self.DisableOK)
     
    133134            name = wx.StaticText(panel,wx.ID_ANY,"New variable's\nname (optional)",
    134135                                 style=wx.ALIGN_CENTER)
    135             scale = G2gd.ValidatedTxtCtrl(panel,self.newvar,0,
     136            scale = G2G.ValidatedTxtCtrl(panel,self.newvar,0,
    136137                                          typeHint=str,notBlank=False)
    137138            dataGridSizer.Add(name,0,wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL,5)
     
    839840                constSizer.Add((-1,-1))
    840841            if refineflag:
    841                 ch = G2gd.G2CheckBox(pageDisplay,'',item,-2)
     842                ch = G2G.G2CheckBox(pageDisplay,'',item,-2)
    842843                constSizer.Add(ch,0,wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_CENTER,1)
    843844            else:
  • trunk/GSASIIexprGUI.py

    r1413 r1619  
    3232GSASIIpath.SetVersionNumber("$Revision$")
    3333import GSASIIgrid as G2gd
     34import GSASIIctrls as G2G
    3435import GSASIIpy3 as G2py3
    3536import GSASIIobj as G2obj
     
    458459                GridSiz.Add((-1,-1),0,wx.ALIGN_LEFT|wx.EXPAND,0)
    459460            elif self.varSelect.get(v) == 0:
    460                 wid = G2gd.ValidatedTxtCtrl(self.varbox,self.varName,v,
     461                wid = G2G.ValidatedTxtCtrl(self.varbox,self.varName,v,
    461462                                            #OnLeave=self.OnTxtLeave,
    462463                                            size=(50,-1))
     
    470471                GridSiz.Add((-1,-1),0,wx.ALIGN_RIGHT|wx.EXPAND,0)
    471472            elif self.varSelect.get(v) == 0:
    472                 wid = G2gd.ValidatedTxtCtrl(self.varbox,self.varValue,v,
     473                wid = G2G.ValidatedTxtCtrl(self.varbox,self.varValue,v,
    473474                                            #OnLeave=self.OnTxtLeave,
    474475                                            size=(75,-1))
     
    493494            if self.varSelect.get(v) == 0 and self.fit:
    494495                self.varRefflag[v] = self.varRefflag.get(v,True)
    495                 wid = G2gd.G2CheckBox(self.varbox,'',self.varRefflag,v)
     496                wid = G2G.G2CheckBox(self.varbox,'',self.varRefflag,v)
    496497                GridSiz.Add(wid,0,wx.ALIGN_LEFT|wx.EXPAND,0)
    497498            else:
     
    517518        sel = self.depChoices[event.GetEventObject().GetSelection()]
    518519        var = self.SelectG2var(sel,'Dependent variable',self.depParmLists[sel])
    519         if not var:
     520        if var is None:
    520521            self.dependentVar = None
    521522            self.OnValidate(None)
     
    538539        v = event.GetEventObject().label
    539540        sel = self.AllowedChoices[event.GetEventObject().GetSelection()]
    540         self.varSelect[v] = sel
    541541        if sel == 0:
    542542            sv = G2obj.MakeUniqueLabel(v,self.usedVars)
     543            self.varSelect[v] = sel
    543544            self.varName[v] = sv
    544545            self.varValue[v] = self.varValue.get(v,0.0)
    545546        else:
    546547            var = self.SelectG2var(sel,v,self.parmLists[sel])
    547             if not var:
    548                 del self.varSelect[v]
     548            if var is None:
    549549                self.OnValidate(None)
    550550                return
     551            self.varSelect[v] = sel
    551552            self.varName[v] = var
    552553        self.OnValidate(None)
  • trunk/GSASIIgrid.py

    r1618 r1619  
    4646import GSASIIexprGUI as G2exG
    4747import GSASIIlog as log
     48import GSASIIctrls as G2G
    4849
    4950# trig functions in degrees
     
    137138] = [wx.NewId() for item in range(10)]
    138139
    139 [ wxID_RENAMESEQSEL,wxID_SAVESEQSEL,wxID_SAVESEQSELCSV,wxID_PLOTSEQSEL,
     140[ wxID_RENAMESEQSEL,wxID_SAVESEQSEL,wxID_SAVESEQSELCSV,wxID_PLOTSEQSEL,wxID_ORGSEQSEL,
    140141  wxADDSEQVAR,wxDELSEQVAR,wxEDITSEQVAR,wxCOPYPARFIT,
    141142  wxADDPARFIT,wxDELPARFIT,wxEDITPARFIT,wxDOPARFIT,
    142 ] = [wx.NewId() for item in range(12)]
     143] = [wx.NewId() for item in range(13)]
    143144
    144145[ wxID_MODELCOPY,wxID_MODELFIT,wxID_MODELADD,wxID_ELEMENTADD,wxID_ELEMENTDELETE,
     
    211212       
    212213
    213 class G2TreeCtrl(wx.TreeCtrl):
    214     '''Create a wrapper around the standard TreeCtrl so we can "wrap"
    215     various events.
    216    
    217     This logs when a tree item is selected (in :meth:`onSelectionChanged`)
    218 
    219     This also wraps lists and dicts pulled out of the tree to track where
    220     they were retrieved from.
    221     '''
    222     def __init__(self,parent=None,*args,**kwargs):
    223         super(self.__class__,self).__init__(parent=parent,*args,**kwargs)
    224         self.G2frame = parent.GetParent()
    225         self.root = self.AddRoot('Loaded Data: ')
    226         self.SelectionChanged = None
    227         log.LogInfo['Tree'] = self
    228 
    229     def _getTreeItemsList(self,item):
    230         '''Get the full tree hierarchy from a reference to a tree item.
    231         Note that this effectively hard-codes phase and histogram names in the
    232         returned list. We may want to make these names relative in the future.
    233         '''
    234         textlist = [self.GetItemText(item)]
    235         parent = self.GetItemParent(item)
    236         while parent:
    237             if parent == self.root: break
    238             textlist.insert(0,self.GetItemText(parent))
    239             parent = self.GetItemParent(parent)
    240         return textlist
    241 
    242     def onSelectionChanged(self,event):
    243         '''Log each press on a tree item here.
    244         '''
    245         if self.SelectionChanged:
    246             textlist = self._getTreeItemsList(event.GetItem())
    247             if log.LogInfo['Logging'] and event.GetItem() != self.root:
    248                 textlist[0] = self.GetRelativeHistNum(textlist[0])
    249                 if textlist[0] == "Phases" and len(textlist) > 1:
    250                     textlist[1] = self.GetRelativePhaseNum(textlist[1])
    251                 log.MakeTreeLog(textlist)
    252             self.SelectionChanged(event)
    253 
    254     def Bind(self,eventtype,handler,*args,**kwargs):
    255         '''Override the Bind() function so that page change events can be trapped
    256         '''
    257         if eventtype == wx.EVT_TREE_SEL_CHANGED:
    258             self.SelectionChanged = handler
    259             wx.TreeCtrl.Bind(self,eventtype,self.onSelectionChanged)
    260             return
    261         wx.TreeCtrl.Bind(self,eventtype,handler,*args,**kwargs)
    262 
    263     # commented out, disables Logging
    264     # def GetItemPyData(self,*args,**kwargs):
    265     #    '''Override the standard method to wrap the contents
    266     #    so that the source can be logged when changed
    267     #    '''
    268     #    data = super(self.__class__,self).GetItemPyData(*args,**kwargs)
    269     #    textlist = self._getTreeItemsList(args[0])
    270     #    if type(data) is dict:
    271     #        return log.dictLogged(data,textlist)
    272     #    if type(data) is list:
    273     #        return log.listLogged(data,textlist)
    274     #    if type(data) is tuple: #N.B. tuples get converted to lists
    275     #        return log.listLogged(list(data),textlist)
    276     #    return data
    277 
    278     def GetRelativeHistNum(self,histname):
    279         '''Returns list with a histogram type and a relative number for that
    280         histogram, or the original string if not a histogram
    281         '''
    282         histtype = histname.split()[0]
    283         if histtype != histtype.upper(): # histograms (only) have a keyword all in caps
    284             return histname
    285         item, cookie = self.GetFirstChild(self.root)
    286         i = 0
    287         while item:
    288             itemtext = self.GetItemText(item)
    289             if itemtext == histname:
    290                 return histtype,i
    291             elif itemtext.split()[0] == histtype:
    292                 i += 1
    293             item, cookie = self.GetNextChild(self.root, cookie)
    294         else:
    295             raise Exception("Histogram not found: "+histname)
    296 
    297     def ConvertRelativeHistNum(self,histtype,histnum):
    298         '''Converts a histogram type and relative histogram number to a
    299         histogram name in the current project
    300         '''
    301         item, cookie = self.GetFirstChild(self.root)
    302         i = 0
    303         while item:
    304             itemtext = self.GetItemText(item)
    305             if itemtext.split()[0] == histtype:
    306                 if i == histnum: return itemtext
    307                 i += 1
    308             item, cookie = self.GetNextChild(self.root, cookie)
    309         else:
    310             raise Exception("Histogram #'+str(histnum)+' of type "+histtype+' not found')
    311        
    312     def GetRelativePhaseNum(self,phasename):
    313         '''Returns a phase number if the string matches a phase name
    314         or else returns the original string
    315         '''
    316         item, cookie = self.GetFirstChild(self.root)
    317         while item:
    318             itemtext = self.GetItemText(item)
    319             if itemtext == "Phases":
    320                 parent = item
    321                 item, cookie = self.GetFirstChild(parent)
    322                 i = 0
    323                 while item:
    324                     itemtext = self.GetItemText(item)
    325                     if itemtext == phasename:
    326                         return i
    327                     item, cookie = self.GetNextChild(parent, cookie)
    328                     i += 1
    329                 else:
    330                     return phasename # not a phase name
    331             item, cookie = self.GetNextChild(self.root, cookie)
    332         else:
    333             raise Exception("No phases found ")
    334 
    335     def ConvertRelativePhaseNum(self,phasenum):
    336         '''Converts relative phase number to a phase name in
    337         the current project
    338         '''
    339         item, cookie = self.GetFirstChild(self.root)
    340         while item:
    341             itemtext = self.GetItemText(item)
    342             if itemtext == "Phases":
    343                 parent = item
    344                 item, cookie = self.GetFirstChild(parent)
    345                 i = 0
    346                 while item:
    347                     if i == phasenum:
    348                         return self.GetItemText(item)
    349                     item, cookie = self.GetNextChild(parent, cookie)
    350                     i += 1
    351                 else:
    352                     raise Exception("Phase "+str(phasenum)+" not found")
    353             item, cookie = self.GetNextChild(self.root, cookie)
    354         else:
    355             raise Exception("No phases found ")
    356 #===========================================================================
    357214class G2LoggedButton(wx.Button):
    358215    '''A version of wx.Button that creates logging events. Bindings are saved
     
    378235        log.MakeButtonLog(self.locationcode,self.label)
    379236        self.handler(event)
    380 #===========================================================================
    381 class ValidatedTxtCtrl(wx.TextCtrl):
    382     '''Create a TextCtrl widget that uses a validator to prevent the
    383     entry of inappropriate characters and changes color to highlight
    384     when invalid input is supplied. As valid values are typed,
    385     they are placed into the dict or list where the initial value
    386     came from. The type of the initial value must be int,
    387     float or str or None (see :obj:`key` and :obj:`typeHint`);
    388     this type (or the one in :obj:`typeHint`) is preserved.
    389 
    390     Float values can be entered in the TextCtrl as numbers or also
    391     as algebraic expressions using operators + - / \* () and \*\*,
    392     in addition pi, sind(), cosd(), tand(), and sqrt() can be used,
    393     as well as appreviations s, sin, c, cos, t, tan and sq.
    394 
    395     :param wx.Panel parent: name of panel or frame that will be
    396       the parent to the TextCtrl. Can be None.
    397 
    398     :param dict/list loc: the dict or list with the initial value to be
    399       placed in the TextCtrl.
    400 
    401     :param int/str key: the dict key or the list index for the value to be
    402       edited by the TextCtrl. The ``loc[key]`` element must exist, but may
    403       have value None. If None, the type for the element is taken from
    404       :obj:`typeHint` and the value for the control is set initially
    405       blank (and thus invalid.) This is a way to specify a field without a
    406       default value: a user must set a valid value.
    407       If the value is not None, it must have a base
    408       type of int, float, str or unicode; the TextCrtl will be initialized
    409       from this value.
    410      
    411     :param list nDig: number of digits & places ([nDig,nPlc]) after decimal to use
    412       for display of float. Alternately, None can be specified which causes
    413       numbers to be displayed with approximately 5 significant figures
    414       (Default=None).
    415 
    416     :param bool notBlank: if True (default) blank values are invalid
    417       for str inputs.
    418      
    419     :param number min: minimum allowed valid value. If None (default) the
    420       lower limit is unbounded.
    421 
    422     :param number max: maximum allowed valid value. If None (default) the
    423       upper limit is unbounded
    424 
    425     :param function OKcontrol: specifies a function or method that will be
    426       called when the input is validated. The called function is supplied
    427       with one argument which is False if the TextCtrl contains an invalid
    428       value and True if the value is valid.
    429       Note that this function should check all values
    430       in the dialog when True, since other entries might be invalid.
    431       The default for this is None, which indicates no function should
    432       be called.
    433 
    434     :param function OnLeave: specifies a function or method that will be
    435       called when the focus for the control is lost.
    436       The called function is supplied with (at present) three keyword arguments:
    437 
    438          * invalid: (*bool*) True if the value for the TextCtrl is invalid
    439          * value:   (*int/float/str*)  the value contained in the TextCtrl
    440          * tc:      (*wx.TextCtrl*)  the TextCtrl name
    441 
    442       The number of keyword arguments may be increased in the future should needs arise,
    443       so it is best to code these functions with a \*\*kwargs argument so they will
    444       continue to run without errors
    445 
    446       The default for OnLeave is None, which indicates no function should
    447       be called.
    448 
    449     :param type typeHint: the value of typeHint is overrides the initial value
    450       for the dict/list element ``loc[key]``, if set to
    451       int or float, which specifies the type for input to the TextCtrl.
    452       Defaults as None, which is ignored.
    453 
    454     :param bool CIFinput: for str input, indicates that only printable
    455       ASCII characters may be entered into the TextCtrl. Forces output
    456       to be ASCII rather than Unicode. For float and int input, allows
    457       use of a single '?' or '.' character as valid input.
    458 
    459     :param dict OnLeaveArgs: a dict with keyword args that are passed to
    460       the :attr:`OnLeave` function. Defaults to ``{}``
    461 
    462     :param (other): other optional keyword parameters for the
    463       wx.TextCtrl widget such as size or style may be specified.
    464 
    465     '''
    466     def __init__(self,parent,loc,key,nDig=None,notBlank=True,min=None,max=None,
    467                  OKcontrol=None,OnLeave=None,typeHint=None,
    468                  CIFinput=False, OnLeaveArgs={}, **kw):
    469         # save passed values needed outside __init__
    470         self.result = loc
    471         self.key = key
    472         self.nDig = nDig
    473         self.OKcontrol=OKcontrol
    474         self.OnLeave = OnLeave
    475         self.OnLeaveArgs = OnLeaveArgs
    476         self.CIFinput = CIFinput
    477         self.type = str
    478         # initialization
    479         self.invalid = False   # indicates if the control has invalid contents
    480         self.evaluated = False # set to True when the validator recognizes an expression
    481         val = loc[key]
    482         if isinstance(val,int) or typeHint is int:
    483             self.type = int
    484             wx.TextCtrl.__init__(
    485                 self,parent,wx.ID_ANY,
    486                 validator=NumberValidator(int,result=loc,key=key,
    487                                           min=min,max=max,
    488                                           OKcontrol=OKcontrol,
    489                                           CIFinput=CIFinput),
    490                 **kw)
    491             if val is not None:
    492                 self._setValue(val)
    493             else: # no default is invalid for a number
    494                 self.invalid = True
    495                 self._IndicateValidity()
    496 
    497         elif isinstance(val,float) or typeHint is float:
    498             self.type = float
    499             wx.TextCtrl.__init__(
    500                 self,parent,wx.ID_ANY,
    501                 validator=NumberValidator(float,result=loc,key=key,
    502                                           min=min,max=max,
    503                                           OKcontrol=OKcontrol,
    504                                           CIFinput=CIFinput),
    505                 **kw)
    506             if val is not None:
    507                 self._setValue(val)
    508             else:
    509                 self.invalid = True
    510                 self._IndicateValidity()
    511 
    512         elif isinstance(val,str) or isinstance(val,unicode):
    513             if self.CIFinput:
    514                 wx.TextCtrl.__init__(
    515                     self,parent,wx.ID_ANY,val,
    516                     validator=ASCIIValidator(result=loc,key=key),
    517                     **kw)
    518             else:
    519                 wx.TextCtrl.__init__(self,parent,wx.ID_ANY,val,**kw)
    520             if notBlank:
    521                 self.Bind(wx.EVT_CHAR,self._onStringKey)
    522                 self.ShowStringValidity() # test if valid input
    523             else:
    524                 self.invalid = False
    525                 self.Bind(wx.EVT_CHAR,self._GetStringValue)
    526         elif val is None:
    527             raise Exception,("ValidatedTxtCtrl error: value of "+str(key)+
    528                              " element is None and typeHint not defined as int or float")
    529         else:
    530             raise Exception,("ValidatedTxtCtrl error: Unknown element ("+str(key)+
    531                              ") type: "+str(type(val)))
    532         # When the mouse is moved away or the widget loses focus,
    533         # display the last saved value, if an expression
    534         #self.Bind(wx.EVT_LEAVE_WINDOW, self._onLeaveWindow)
    535         self.Bind(wx.EVT_TEXT_ENTER, self._onLoseFocus)
    536         self.Bind(wx.EVT_KILL_FOCUS, self._onLoseFocus)
    537         # patch for wx 2.9 on Mac
    538         i,j= wx.__version__.split('.')[0:2]
    539         if int(i)+int(j)/10. > 2.8 and 'wxOSX' in wx.PlatformInfo:
    540             self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
    541 
    542     def SetValue(self,val):
    543         if self.result is not None: # note that this bypasses formatting
    544             self.result[self.key] = val
    545             log.LogVarChange(self.result,self.key)
    546         self._setValue(val)
    547 
    548     def _setValue(self,val):
    549         self.invalid = False
    550         if self.type is int:
    551             try:
    552                 if int(val) != val:
    553                     self.invalid = True
    554                 else:
    555                     val = int(val)
    556             except:
    557                 if self.CIFinput and (val == '?' or val == '.'):
    558                     pass
    559                 else:
    560                     self.invalid = True
    561             wx.TextCtrl.SetValue(self,str(val))
    562         elif self.type is float:
    563             try:
    564                 val = float(val) # convert strings, if needed
    565             except:
    566                 if self.CIFinput and (val == '?' or val == '.'):
    567                     pass
    568                 else:
    569                     self.invalid = True
    570             if self.nDig:
    571                 wx.TextCtrl.SetValue(self,str(G2py3.FormatValue(val,self.nDig)))
    572             else:
    573                 wx.TextCtrl.SetValue(self,str(G2py3.FormatSigFigs(val)).rstrip('0'))
    574         else:
    575             wx.TextCtrl.SetValue(self,str(val))
    576             self.ShowStringValidity() # test if valid input
    577             return
    578        
    579         self._IndicateValidity()
    580         if self.OKcontrol:
    581             self.OKcontrol(not self.invalid)
    582 
    583     def OnKeyDown(self,event):
    584         'Special callback for wx 2.9+ on Mac where backspace is not processed by validator'
    585         key = event.GetKeyCode()
    586         if key in [wx.WXK_BACK, wx.WXK_DELETE]:
    587             if self.Validator: wx.CallAfter(self.Validator.TestValid,self)
    588         if key == wx.WXK_RETURN:
    589             self._onLoseFocus(None)
    590         event.Skip()
    591                    
    592     def _onStringKey(self,event):
    593         event.Skip()
    594         if self.invalid: # check for validity after processing the keystroke
    595             wx.CallAfter(self.ShowStringValidity,True) # was invalid
    596         else:
    597             wx.CallAfter(self.ShowStringValidity,False) # was valid
    598 
    599     def _IndicateValidity(self):
    600         'Set the control colors to show invalid input'
    601         if self.invalid:
    602             self.SetForegroundColour("red")
    603             self.SetBackgroundColour("yellow")
    604             self.SetFocus()
    605             self.Refresh()
    606         else: # valid input
    607             self.SetBackgroundColour(
    608                 wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
    609             self.SetForegroundColour("black")
    610             self.Refresh()
    611 
    612     def ShowStringValidity(self,previousInvalid=True):
    613         '''Check if input is valid. Anytime the input is
    614         invalid, call self.OKcontrol (if defined) because it is fast.
    615         If valid, check for any other invalid entries only when
    616         changing from invalid to valid, since that is slower.
    617        
    618         :param bool previousInvalid: True if the TextCtrl contents were
    619           invalid prior to the current change.
    620          
    621         '''
    622         val = self.GetValue().strip()
    623         self.invalid = not val
    624         self._IndicateValidity()
    625         if self.invalid:
    626             if self.OKcontrol:
    627                 self.OKcontrol(False)
    628         elif self.OKcontrol and previousInvalid:
    629             self.OKcontrol(True)
    630         # always store the result
    631         if self.CIFinput: # for CIF make results ASCII
    632             self.result[self.key] = val.encode('ascii','replace')
    633         else:
    634             self.result[self.key] = val
    635         log.LogVarChange(self.result,self.key)
    636 
    637     def _GetStringValue(self,event):
    638         '''Get string input and store.
    639         '''
    640         event.Skip() # process keystroke
    641         wx.CallAfter(self._SaveStringValue)
    642        
    643     def _SaveStringValue(self):
    644         val = self.GetValue().strip()
    645         # always store the result
    646         if self.CIFinput: # for CIF make results ASCII
    647             self.result[self.key] = val.encode('ascii','replace')
    648         else:
    649             self.result[self.key] = val
    650         log.LogVarChange(self.result,self.key)
    651 
    652     def _onLoseFocus(self,event):
    653         if self.evaluated:
    654             self.EvaluateExpression()
    655         elif self.result is not None: # show formatted result, as Bob wants
    656             self._setValue(self.result[self.key])
    657         if self.OnLeave: self.OnLeave(invalid=self.invalid,
    658                                       value=self.result[self.key],
    659                                       tc=self,
    660                                       **self.OnLeaveArgs)
    661         if event: event.Skip()
    662 
    663     def EvaluateExpression(self):
    664         '''Show the computed value when an expression is entered to the TextCtrl
    665         Make sure that the number fits by truncating decimal places and switching
    666         to scientific notation, as needed.
    667         Called on loss of focus, enter, etc..
    668         '''
    669         if self.invalid: return # don't substitute for an invalid expression
    670         if not self.evaluated: return # true when an expression is evaluated
    671         if self.result is not None: # retrieve the stored result
    672             self._setValue(self.result[self.key])
    673         self.evaluated = False # expression has been recast as value, reset flag
    674        
    675 class NumberValidator(wx.PyValidator):
    676     '''A validator to be used with a TextCtrl to prevent
    677     entering characters other than digits, signs, and for float
    678     input, a period and exponents.
    679    
    680     The value is checked for validity after every keystroke
    681       If an invalid number is entered, the box is highlighted.
    682       If the number is valid, it is saved in result[key]
    683 
    684     :param type typ: the base data type. Must be int or float.
    685 
    686     :param bool positiveonly: If True, negative integers are not allowed
    687       (default False). This prevents the + or - keys from being pressed.
    688       Used with typ=int; ignored for typ=float.
    689 
    690     :param number min: Minimum allowed value. If None (default) the
    691       lower limit is unbounded
    692 
    693     :param number max: Maximum allowed value. If None (default) the
    694       upper limit is unbounded
    695      
    696     :param dict/list result: List or dict where value should be placed when valid
    697 
    698     :param any key: key to use for result (int for list)
    699 
    700     :param function OKcontrol: function or class method to control
    701       an OK button for a window.
    702       Ignored if None (default)
    703 
    704     :param bool CIFinput: allows use of a single '?' or '.' character
    705       as valid input.
    706      
    707     '''
    708     def __init__(self, typ, positiveonly=False, min=None, max=None,
    709                  result=None, key=None, OKcontrol=None, CIFinput=False):
    710         'Create the validator'
    711         wx.PyValidator.__init__(self)
    712         # save passed parameters
    713         self.typ = typ
    714         self.positiveonly = positiveonly
    715         self.min = min
    716         self.max = max
    717         self.result = result
    718         self.key = key
    719         self.OKcontrol = OKcontrol
    720         self.CIFinput = CIFinput
    721         # set allowed keys by data type
    722         self.Bind(wx.EVT_CHAR, self.OnChar)
    723         if self.typ == int and self.positiveonly:
    724             self.validchars = '0123456789'
    725         elif self.typ == int:
    726             self.validchars = '0123456789+-'
    727         elif self.typ == float:
    728             # allow for above and sind, cosd, sqrt, tand, pi, and abbreviations
    729             # also addition, subtraction, division, multiplication, exponentiation
    730             self.validchars = '0123456789.-+eE/cosindcqrtap()*'
    731         else:
    732             self.validchars = None
    733             return
    734         if self.CIFinput:
    735             self.validchars += '?.'
    736     def Clone(self):
    737         'Create a copy of the validator, a strange, but required component'
    738         return NumberValidator(typ=self.typ,
    739                                positiveonly=self.positiveonly,
    740                                min=self.min, max=self.max,
    741                                result=self.result, key=self.key,
    742                                OKcontrol=self.OKcontrol,
    743                                CIFinput=self.CIFinput)
    744     def TransferToWindow(self):
    745         'Needed by validator, strange, but required component'
    746         return True # Prevent wxDialog from complaining.
    747     def TransferFromWindow(self):
    748         'Needed by validator, strange, but required component'
    749         return True # Prevent wxDialog from complaining.
    750     def TestValid(self,tc):
    751         '''Check if the value is valid by casting the input string
    752         into the current type.
    753 
    754         Set the invalid variable in the TextCtrl object accordingly.
    755 
    756         If the value is valid, save it in the dict/list where
    757         the initial value was stored, if appropriate.
    758 
    759         :param wx.TextCtrl tc: A reference to the TextCtrl that the validator
    760           is associated with.
    761         '''
    762         tc.invalid = False # assume valid
    763         if self.CIFinput:
    764             val = tc.GetValue().strip()
    765             if val == '?' or val == '.':
    766                 self.result[self.key] = val
    767                 log.LogVarChange(self.result,self.key)
    768                 return
    769         try:
    770             val = self.typ(tc.GetValue())
    771         except (ValueError, SyntaxError) as e:
    772             if self.typ is float: # for float values, see if an expression can be evaluated
    773                 val = G2py3.FormulaEval(tc.GetValue())
    774                 if val is None:
    775                     tc.invalid = True
    776                     return
    777                 else:
    778                     tc.evaluated = True
    779             else:
    780                 tc.invalid = True
    781                 return
    782         # if self.max != None and self.typ == int:
    783         #     if val > self.max:
    784         #         tc.invalid = True
    785         # if self.min != None and self.typ == int:
    786         #     if val < self.min:
    787         #         tc.invalid = True  # invalid
    788         if self.max != None:
    789             if val > self.max:
    790                 tc.invalid = True
    791         if self.min != None:
    792             if val < self.min:
    793                 tc.invalid = True  # invalid
    794         if self.key is not None and self.result is not None and not tc.invalid:
    795             self.result[self.key] = val
    796             log.LogVarChange(self.result,self.key)
    797 
    798     def ShowValidity(self,tc):
    799         '''Set the control colors to show invalid input
    800 
    801         :param wx.TextCtrl tc: A reference to the TextCtrl that the validator
    802           is associated with.
    803 
    804         '''
    805         if tc.invalid:
    806             tc.SetForegroundColour("red")
    807             tc.SetBackgroundColour("yellow")
    808             tc.SetFocus()
    809             tc.Refresh()
    810             return False
    811         else: # valid input
    812             tc.SetBackgroundColour(
    813                 wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
    814             tc.SetForegroundColour("black")
    815             tc.Refresh()
    816             return True
    817 
    818     def CheckInput(self,previousInvalid):
    819         '''called to test every change to the TextCtrl for validity and
    820         to change the appearance of the TextCtrl
    821 
    822         Anytime the input is invalid, call self.OKcontrol
    823         (if defined) because it is fast.
    824         If valid, check for any other invalid entries only when
    825         changing from invalid to valid, since that is slower.
    826 
    827         :param bool previousInvalid: True if the TextCtrl contents were
    828           invalid prior to the current change.
    829         '''
    830         tc = self.GetWindow()
    831         self.TestValid(tc)
    832         self.ShowValidity(tc)
    833         # if invalid
    834         if tc.invalid and self.OKcontrol:
    835             self.OKcontrol(False)
    836         if not tc.invalid and self.OKcontrol and previousInvalid:
    837             self.OKcontrol(True)
    838 
    839     def OnChar(self, event):
    840         '''Called each type a key is pressed
    841         ignores keys that are not allowed for int and float types
    842         '''
    843         key = event.GetKeyCode()
    844         tc = self.GetWindow()
    845         if key == wx.WXK_RETURN:
    846             if tc.invalid:
    847                 self.CheckInput(True)
    848             else:
    849                 self.CheckInput(False)
    850             return
    851         if key < wx.WXK_SPACE or key == wx.WXK_DELETE or key > 255: # control characters get processed
    852             event.Skip()
    853             if tc.invalid:
    854                 wx.CallAfter(self.CheckInput,True)
    855             else:
    856                 wx.CallAfter(self.CheckInput,False)
    857             return
    858         elif chr(key) in self.validchars: # valid char pressed?
    859             event.Skip()
    860             if tc.invalid:
    861                 wx.CallAfter(self.CheckInput,True)
    862             else:
    863                 wx.CallAfter(self.CheckInput,False)
    864             return
    865         if not wx.Validator_IsSilent(): wx.Bell()
    866         return  # Returning without calling event.Skip, which eats the keystroke
    867 
    868 ################################################################################
    869 class ASCIIValidator(wx.PyValidator):
    870     '''A validator to be used with a TextCtrl to prevent
    871     entering characters other than ASCII characters.
    872    
    873     The value is checked for validity after every keystroke
    874       If an invalid number is entered, the box is highlighted.
    875       If the number is valid, it is saved in result[key]
    876 
    877     :param dict/list result: List or dict where value should be placed when valid
    878 
    879     :param any key: key to use for result (int for list)
    880 
    881     '''
    882     def __init__(self, result=None, key=None):
    883         'Create the validator'
    884         import string
    885         wx.PyValidator.__init__(self)
    886         # save passed parameters
    887         self.result = result
    888         self.key = key
    889         self.validchars = string.ascii_letters + string.digits + string.punctuation + string.whitespace
    890         self.Bind(wx.EVT_CHAR, self.OnChar)
    891     def Clone(self):
    892         'Create a copy of the validator, a strange, but required component'
    893         return ASCIIValidator(result=self.result, key=self.key)
    894         tc = self.GetWindow()
    895         tc.invalid = False # make sure the validity flag is defined in parent
    896     def TransferToWindow(self):
    897         'Needed by validator, strange, but required component'
    898         return True # Prevent wxDialog from complaining.
    899     def TransferFromWindow(self):
    900         'Needed by validator, strange, but required component'
    901         return True # Prevent wxDialog from complaining.
    902     def TestValid(self,tc):
    903         '''Check if the value is valid by casting the input string
    904         into ASCII.
    905 
    906         Save it in the dict/list where the initial value was stored
    907 
    908         :param wx.TextCtrl tc: A reference to the TextCtrl that the validator
    909           is associated with.
    910         '''
    911         self.result[self.key] = tc.GetValue().encode('ascii','replace')
    912         log.LogVarChange(self.result,self.key)
    913 
    914     def OnChar(self, event):
    915         '''Called each type a key is pressed
    916         ignores keys that are not allowed for int and float types
    917         '''
    918         key = event.GetKeyCode()
    919         tc = self.GetWindow()
    920         if key == wx.WXK_RETURN:
    921             self.TestValid(tc)
    922             return
    923         if key < wx.WXK_SPACE or key == wx.WXK_DELETE or key > 255: # control characters get processed
    924             event.Skip()
    925             self.TestValid(tc)
    926             return
    927         elif chr(key) in self.validchars: # valid char pressed?
    928             event.Skip()
    929             self.TestValid(tc)
    930             return
    931         if not wx.Validator_IsSilent():
    932             wx.Bell()
    933         return  # Returning without calling event.Skip, which eats the keystroke
    934 ################################################################################
    935237class EnumSelector(wx.ComboBox):
    936238    '''A customized :class:`wxpython.ComboBox` that selects items from a list
     
    992294
    993295################################################################################
    994 class G2CheckBox(wx.CheckBox):
    995     '''A customized version of a CheckBox that automatically initializes
    996     the control to a supplied list or dict entry and updates that
    997     entry as the widget is used.
    998 
    999     :param wx.Panel parent: name of panel or frame that will be
    1000       the parent to the widget. Can be None.
    1001     :param str label: text to put on check button
    1002     :param dict/list loc: the dict or list with the initial value to be
    1003       placed in the CheckBox.
    1004     :param int/str key: the dict key or the list index for the value to be
    1005       edited by the CheckBox. The ``loc[key]`` element must exist.
    1006       The CheckBox will be initialized from this value.
    1007       If the value is anything other that True (or 1), it will be taken as
    1008       False.
    1009     '''
    1010     def __init__(self,parent,label,loc,key):
    1011         wx.CheckBox.__init__(self,parent,id=wx.ID_ANY,label=label)
    1012         self.loc = loc
    1013         self.key = key
    1014         self.SetValue(self.loc[self.key]==True)
    1015         self.Bind(wx.EVT_CHECKBOX, self._OnCheckBox)
    1016     def _OnCheckBox(self,event):
    1017         self.loc[self.key] = self.GetValue()
    1018         log.LogVarChange(self.loc,self.key)
    1019296################################################################################
    1020297class G2ChoiceButton(wx.Choice):
     
    1080357        if self.onChoice:
    1081358            self.onChoice()
    1082 ################################################################################   
    1083 def CallScrolledMultiEditor(parent,dictlst,elemlst,prelbl=[],postlbl=[],
    1084                  title='Edit items',header='',size=(300,250),
    1085                              CopyButton=False, **kw):
    1086     '''Shell routine to call a ScrolledMultiEditor dialog. See
    1087     :class:`ScrolledMultiEditor` for parameter definitions.
    1088 
    1089     :returns: True if the OK button is pressed; False if the window is closed
    1090       with the system menu or the Cancel button.
    1091 
    1092     '''
    1093     dlg = ScrolledMultiEditor(parent,dictlst,elemlst,prelbl,postlbl,
    1094                               title,header,size,
    1095                               CopyButton, **kw)
    1096     if dlg.ShowModal() == wx.ID_OK:
    1097         dlg.Destroy()
    1098         return True
    1099     else:
    1100         dlg.Destroy()
    1101         return False
    1102 
    1103 class ScrolledMultiEditor(wx.Dialog):
    1104     '''Define a window for editing a potentially large number of dict- or
    1105     list-contained values with validation for each item. Edited values are
    1106     automatically placed in their source location. If invalid entries
    1107     are provided, the TextCtrl is turned yellow and the OK button is disabled.
    1108 
    1109     The type for each TextCtrl validation is determined by the
    1110     initial value of the entry (int, float or string).
    1111     Float values can be entered in the TextCtrl as numbers or also
    1112     as algebraic expressions using operators + - / \* () and \*\*,
    1113     in addition pi, sind(), cosd(), tand(), and sqrt() can be used,
    1114     as well as appreviations s(), sin(), c(), cos(), t(), tan() and sq().
    1115 
    1116     :param wx.Frame parent: name of parent window, or may be None
    1117 
    1118     :param tuple dictlst: a list of dicts or lists containing values to edit
    1119 
    1120     :param tuple elemlst: a list of keys for each item in a dictlst. Must have the
    1121       same length as dictlst.
    1122 
    1123     :param wx.Frame parent: name of parent window, or may be None
    1124    
    1125     :param tuple prelbl: a list of labels placed before the TextCtrl for each
    1126       item (optional)
    1127    
    1128     :param tuple postlbl: a list of labels placed after the TextCtrl for each
    1129       item (optional)
    1130 
    1131     :param str title: a title to place in the frame of the dialog
    1132 
    1133     :param str header: text to place at the top of the window. May contain
    1134       new line characters.
    1135 
    1136     :param wx.Size size: a size parameter that dictates the
    1137       size for the scrolled region of the dialog. The default is
    1138       (300,250).
    1139 
    1140     :param bool CopyButton: if True adds a small button that copies the
    1141       value for the current row to all fields below (default is False)
    1142      
    1143     :param list minvals: optional list of minimum values for validation
    1144       of float or int values. Ignored if value is None.
    1145     :param list maxvals: optional list of maximum values for validation
    1146       of float or int values. Ignored if value is None.
    1147     :param list sizevals: optional list of wx.Size values for each input
    1148       widget. Ignored if value is None.
    1149      
    1150     :param tuple checkdictlst: an optional list of dicts or lists containing bool
    1151       values (similar to dictlst).
    1152     :param tuple checkelemlst: an optional list of dicts or lists containing bool
    1153       key values (similar to elemlst). Must be used with checkdictlst.
    1154     :param string checklabel: a string to use for each checkbutton
    1155      
    1156     :returns: the wx.Dialog created here. Use method .ShowModal() to display it.
    1157    
    1158     *Example for use of ScrolledMultiEditor:*
    1159 
    1160     ::
    1161 
    1162         dlg = <pkg>.ScrolledMultiEditor(frame,dictlst,elemlst,prelbl,postlbl,
    1163                                         header=header)
    1164         if dlg.ShowModal() == wx.ID_OK:
    1165              for d,k in zip(dictlst,elemlst):
    1166                  print d[k]
    1167 
    1168     *Example definitions for dictlst and elemlst:*
    1169 
    1170     ::
    1171      
    1172           dictlst = (dict1,list1,dict1,list1)
    1173           elemlst = ('a', 1, 2, 3)
    1174 
    1175       This causes items dict1['a'], list1[1], dict1[2] and list1[3] to be edited.
    1176    
    1177     Note that these items must have int, float or str values assigned to
    1178     them. The dialog will force these types to be retained. String values
    1179     that are blank are marked as invalid.
    1180     '''
    1181    
    1182     def __init__(self,parent,dictlst,elemlst,prelbl=[],postlbl=[],
    1183                  title='Edit items',header='',size=(300,250),
    1184                  CopyButton=False,
    1185                  minvals=[],maxvals=[],sizevals=[],
    1186                  checkdictlst=[], checkelemlst=[], checklabel=""):
    1187         if len(dictlst) != len(elemlst):
    1188             raise Exception,"ScrolledMultiEditor error: len(dictlst) != len(elemlst) "+str(len(dictlst))+" != "+str(len(elemlst))
    1189         if len(checkdictlst) != len(checkelemlst):
    1190             raise Exception,"ScrolledMultiEditor error: len(checkdictlst) != len(checkelemlst) "+str(len(checkdictlst))+" != "+str(len(checkelemlst))
    1191         wx.Dialog.__init__( # create dialog & sizer
    1192             self,parent,wx.ID_ANY,title,
    1193             style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
    1194         mainSizer = wx.BoxSizer(wx.VERTICAL)
    1195         self.orig = []
    1196         self.dictlst = dictlst
    1197         self.elemlst = elemlst
    1198         self.checkdictlst = checkdictlst
    1199         self.checkelemlst = checkelemlst
    1200         self.StartCheckValues = [checkdictlst[i][checkelemlst[i]] for i in range(len(checkdictlst))]
    1201         self.ButtonIndex = {}
    1202         for d,i in zip(dictlst,elemlst):
    1203             self.orig.append(d[i])
    1204         # add a header if supplied
    1205         if header:
    1206             subSizer = wx.BoxSizer(wx.HORIZONTAL)
    1207             subSizer.Add((-1,-1),1,wx.EXPAND)
    1208             subSizer.Add(wx.StaticText(self,wx.ID_ANY,header))
    1209             subSizer.Add((-1,-1),1,wx.EXPAND)
    1210             mainSizer.Add(subSizer,0,wx.EXPAND,0)
    1211         # make OK button now, because we will need it for validation
    1212         self.OKbtn = wx.Button(self, wx.ID_OK)
    1213         self.OKbtn.SetDefault()
    1214         # create scrolled panel and sizer
    1215         panel = wxscroll.ScrolledPanel(self, wx.ID_ANY,size=size,
    1216             style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
    1217         cols = 4
    1218         if CopyButton: cols += 1
    1219         subSizer = wx.FlexGridSizer(cols=cols,hgap=2,vgap=2)
    1220         self.ValidatedControlsList = [] # make list of TextCtrls
    1221         self.CheckControlsList = [] # make list of CheckBoxes
    1222         for i,(d,k) in enumerate(zip(dictlst,elemlst)):
    1223             if i >= len(prelbl): # label before TextCtrl, or put in a blank
    1224                 subSizer.Add((-1,-1))
    1225             else:
    1226                 subSizer.Add(wx.StaticText(panel,wx.ID_ANY,str(prelbl[i])))
    1227             kargs = {}
    1228             if i < len(minvals):
    1229                 if minvals[i] is not None: kargs['min']=minvals[i]
    1230             if i < len(maxvals):
    1231                 if maxvals[i] is not None: kargs['max']=maxvals[i]
    1232             if i < len(sizevals):
    1233                 if sizevals[i]: kargs['size']=sizevals[i]
    1234             if CopyButton:
    1235                 import wx.lib.colourselect as wscs
    1236                 but = wscs.ColourSelect(label='v', # would like to use u'\u2193' or u'\u25BC' but not in WinXP
    1237                                         # is there a way to test?
    1238                                         parent=panel,
    1239                                         colour=(255,255,200),
    1240                                         size=wx.Size(30,23),
    1241                                         style=wx.RAISED_BORDER)
    1242                 but.Bind(wx.EVT_BUTTON, self._OnCopyButton)
    1243                 but.SetToolTipString('Press to copy adjacent value to all rows below')
    1244                 self.ButtonIndex[but] = i
    1245                 subSizer.Add(but)
    1246             # create the validated TextCrtl, store it and add it to the sizer
    1247             ctrl = ValidatedTxtCtrl(panel,d,k,OKcontrol=self.ControlOKButton,
    1248                                     **kargs)
    1249             self.ValidatedControlsList.append(ctrl)
    1250             subSizer.Add(ctrl)
    1251             if i < len(postlbl): # label after TextCtrl, or put in a blank
    1252                 subSizer.Add(wx.StaticText(panel,wx.ID_ANY,str(postlbl[i])))
    1253             else:
    1254                 subSizer.Add((-1,-1))
    1255             if i < len(checkdictlst):
    1256                 ch = G2CheckBox(panel,checklabel,checkdictlst[i],checkelemlst[i])
    1257                 self.CheckControlsList.append(ch)
    1258                 subSizer.Add(ch)                   
    1259             else:
    1260                 subSizer.Add((-1,-1))
    1261         # finish up ScrolledPanel
    1262         panel.SetSizer(subSizer)
    1263         panel.SetAutoLayout(1)
    1264         panel.SetupScrolling()
    1265         # patch for wx 2.9 on Mac
    1266         i,j= wx.__version__.split('.')[0:2]
    1267         if int(i)+int(j)/10. > 2.8 and 'wxOSX' in wx.PlatformInfo:
    1268             panel.SetMinSize((subSizer.GetSize()[0]+30,panel.GetSize()[1]))       
    1269         mainSizer.Add(panel,1, wx.ALL|wx.EXPAND,1)
    1270 
    1271         # Sizer for OK/Close buttons. N.B. on Close changes are discarded
    1272         # by restoring the initial values
    1273         btnsizer = wx.BoxSizer(wx.HORIZONTAL)
    1274         btnsizer.Add(self.OKbtn)
    1275         btn = wx.Button(self, wx.ID_CLOSE,"Cancel")
    1276         btn.Bind(wx.EVT_BUTTON,self._onClose)
    1277         btnsizer.Add(btn)
    1278         mainSizer.Add(btnsizer, 0, wx.ALIGN_CENTER|wx.ALL, 5)
    1279         # size out the window. Set it to be enlarged but not made smaller
    1280         self.SetSizer(mainSizer)
    1281         mainSizer.Fit(self)
    1282         self.SetMinSize(self.GetSize())
    1283 
    1284     def _OnCopyButton(self,event):
    1285         'Implements the copy down functionality'
    1286         but = event.GetEventObject()
    1287         n = self.ButtonIndex.get(but)
    1288         if n is None: return
    1289         for i,(d,k,ctrl) in enumerate(zip(self.dictlst,self.elemlst,self.ValidatedControlsList)):
    1290             if i < n: continue
    1291             if i == n:
    1292                 val = d[k]
    1293                 continue
    1294             d[k] = val
    1295             ctrl.SetValue(val)
    1296         for i in range(len(self.checkdictlst)):
    1297             if i < n: continue
    1298             self.checkdictlst[i][self.checkelemlst[i]] = self.checkdictlst[n][self.checkelemlst[n]]
    1299             self.CheckControlsList[i].SetValue(self.checkdictlst[i][self.checkelemlst[i]])
    1300     def _onClose(self,event):
    1301         'Used on Cancel: Restore original values & close the window'
    1302         for d,i,v in zip(self.dictlst,self.elemlst,self.orig):
    1303             d[i] = v
    1304         for i in range(len(self.checkdictlst)):
    1305             self.checkdictlst[i][self.checkelemlst[i]] = self.StartCheckValues[i]
    1306         self.EndModal(wx.ID_CANCEL)
    1307        
    1308     def ControlOKButton(self,setvalue):
    1309         '''Enable or Disable the OK button for the dialog. Note that this is
    1310         passed into the ValidatedTxtCtrl for use by validators.
    1311 
    1312         :param bool setvalue: if True, all entries in the dialog are
    1313           checked for validity. if False then the OK button is disabled.
    1314 
    1315         '''
    1316         if setvalue: # turn button on, do only if all controls show as valid
    1317             for ctrl in self.ValidatedControlsList:
    1318                 if ctrl.invalid:
    1319                     self.OKbtn.Disable()
    1320                     return
    1321             else:
    1322                 self.OKbtn.Enable()
    1323         else:
    1324             self.OKbtn.Disable()
    1325359
    1326360################################################################################
     
    1544578        self._default(data,self.default)
    1545579        self.Draw(self.data)
    1546        
    1547 class PickTwoDialog(wx.Dialog):
    1548     '''This does not seem to be in use
    1549     '''
    1550     def __init__(self,parent,title,prompt,names,choices):
    1551         wx.Dialog.__init__(self,parent,-1,title,
    1552             pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
    1553         self.panel = wx.Panel(self)         #just a dummy - gets destroyed in Draw!
    1554         self.prompt = prompt
    1555         self.choices = choices
    1556         self.names = names
    1557         self.Draw()
    1558 
    1559     def Draw(self):
    1560         Indx = {}
    1561        
    1562         def OnSelection(event):
    1563             Obj = event.GetEventObject()
    1564             id = Indx[Obj.GetId()]
    1565             self.choices[id] = Obj.GetValue().encode()  #to avoid Unicode versions
    1566             self.Draw()
    1567            
    1568         self.panel.DestroyChildren()
    1569         self.panel.Destroy()
    1570         self.panel = wx.Panel(self)
    1571         mainSizer = wx.BoxSizer(wx.VERTICAL)
    1572         mainSizer.Add(wx.StaticText(self.panel,-1,self.prompt),0,wx.ALIGN_CENTER)
    1573         for isel,name in enumerate(self.choices):
    1574             lineSizer = wx.BoxSizer(wx.HORIZONTAL)
    1575             lineSizer.Add(wx.StaticText(self.panel,-1,'Reference atom '+str(isel+1)),0,wx.ALIGN_CENTER)
    1576             nameList = self.names[:]
    1577             if isel:
    1578                 if self.choices[0] in nameList:
    1579                     nameList.remove(self.choices[0])
    1580             choice = wx.ComboBox(self.panel,-1,value=name,choices=nameList,
    1581                 style=wx.CB_READONLY|wx.CB_DROPDOWN)
    1582             Indx[choice.GetId()] = isel
    1583             choice.Bind(wx.EVT_COMBOBOX, OnSelection)
    1584             lineSizer.Add(choice,0,WACV)
    1585             mainSizer.Add(lineSizer)
    1586         OkBtn = wx.Button(self.panel,-1,"Ok")
    1587         OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
    1588         CancelBtn = wx.Button(self.panel,-1,'Cancel')
    1589         CancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
    1590         btnSizer = wx.BoxSizer(wx.HORIZONTAL)
    1591         btnSizer.Add((20,20),1)
    1592         btnSizer.Add(OkBtn)
    1593         btnSizer.Add(CancelBtn)
    1594         btnSizer.Add((20,20),1)
    1595         mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
    1596         self.panel.SetSizer(mainSizer)
    1597         self.panel.Fit()
    1598         self.Fit()
    1599        
    1600     def GetSelection(self):
    1601         return self.choices
    1602 
    1603     def OnOk(self,event):
    1604         parent = self.GetParent()
    1605         parent.Raise()
    1606         self.EndModal(wx.ID_OK)             
    1607        
    1608     def OnCancel(self,event):
    1609         parent = self.GetParent()
    1610         parent.Raise()
    1611         self.EndModal(wx.ID_CANCEL)
    1612        
     580               
    1613581class SingleFloatDialog(wx.Dialog):
    1614582    'Dialog to obtain a single float value from user'
     
    23561324
    23571325################################################################################
    2358 def SelectEdit1Var(G2frame,array,labelLst,elemKeysLst,dspLst,refFlgElem):
    2359     '''Select a variable from a list, then edit it and select histograms
    2360     to copy it to.
    2361 
    2362     :param wx.Frame G2frame: main GSAS-II frame
    2363     :param dict array: the array (dict or list) where values to be edited are kept
    2364     :param list labelLst: labels for each data item
    2365     :param list elemKeysLst: a list of lists of keys needed to be applied (see below)
    2366       to obtain the value of each parameter
    2367     :param list dspLst: list list of digits to be displayed (10,4) is 10 digits
    2368       with 4 decimal places. Can be None.
    2369     :param list refFlgElem: a list of lists of keys needed to be applied (see below)
    2370       to obtain the refine flag for each parameter or None if the parameter
    2371       does not have refine flag.
    2372 
    2373     Example::
    2374       array = data
    2375       labelLst = ['v1','v2']
    2376       elemKeysLst = [['v1'], ['v2',0]]
    2377       refFlgElem = [None, ['v2',1]]
    2378 
    2379      * The value for v1 will be in data['v1'] and this cannot be refined while,
    2380      * The value for v2 will be in data['v2'][0] and its refinement flag is data['v2'][1]
    2381     '''
    2382     def unkey(dct,keylist):
    2383         '''dive into a nested set of dicts/lists applying keys in keylist
    2384         consecutively
    2385         '''
    2386         d = dct
    2387         for k in keylist:
    2388             d = d[k]
    2389         return d
    2390 
    2391     def OnChoice(event):
    2392         'Respond when a parameter is selected in the Choice box'
    2393         valSizer.DeleteWindows()
    2394         lbl = event.GetString()
    2395         copyopts['currentsel'] = lbl
    2396         i = labelLst.index(lbl)
    2397         OKbtn.Enable(True)
    2398         ch.SetLabel(lbl)
    2399         args = {}
    2400         if dspLst[i]:
    2401             args = {'nDig':dspLst[i]}
    2402         Val = ValidatedTxtCtrl(
    2403             dlg,
    2404             unkey(array,elemKeysLst[i][:-1]),
    2405             elemKeysLst[i][-1],
    2406             **args)
    2407         copyopts['startvalue'] = unkey(array,elemKeysLst[i])
    2408         #unkey(array,elemKeysLst[i][:-1])[elemKeysLst[i][-1]] =
    2409         valSizer.Add(Val,0,wx.LEFT,5)
    2410         dlg.SendSizeEvent()
    2411        
    2412     # SelectEdit1Var execution begins here
    2413     saveArray = copy.deepcopy(array) # keep original values
    2414     TreeItemType = G2frame.PatternTree.GetItemText(G2frame.PickId)
    2415     copyopts = {'InTable':False,"startvalue":None,'currentsel':None}       
    2416     hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
    2417     histList = G2pdG.GetHistsLikeSelected(G2frame)
    2418     if not histList:
    2419         G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
    2420         return
    2421     dlg = wx.Dialog(G2frame.dataDisplay,wx.ID_ANY,'Set a parameter value',
    2422         style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
    2423     mainSizer = wx.BoxSizer(wx.VERTICAL)
    2424     mainSizer.Add((5,5))
    2425     subSizer = wx.BoxSizer(wx.HORIZONTAL)
    2426     subSizer.Add((-1,-1),1,wx.EXPAND)
    2427     subSizer.Add(wx.StaticText(dlg,wx.ID_ANY,'Select a parameter and set a new value'))
    2428     subSizer.Add((-1,-1),1,wx.EXPAND)
    2429     mainSizer.Add(subSizer,0,wx.EXPAND,0)
    2430     mainSizer.Add((0,10))
    2431 
    2432     subSizer = wx.FlexGridSizer(0,2,5,0)
    2433     subSizer.Add(wx.StaticText(dlg,wx.ID_ANY,'Parameter: '))
    2434     ch = wx.Choice(dlg, wx.ID_ANY, choices = sorted(labelLst))
    2435     ch.SetSelection(-1)
    2436     ch.Bind(wx.EVT_CHOICE, OnChoice)
    2437     subSizer.Add(ch)
    2438     subSizer.Add(wx.StaticText(dlg,wx.ID_ANY,'Value: '))
    2439     valSizer = wx.BoxSizer(wx.HORIZONTAL)
    2440     subSizer.Add(valSizer)
    2441     mainSizer.Add(subSizer)
    2442 
    2443     mainSizer.Add((-1,20))
    2444     subSizer = wx.BoxSizer(wx.HORIZONTAL)
    2445     subSizer.Add(G2CheckBox(dlg, 'Edit in table ', copyopts, 'InTable'))
    2446     mainSizer.Add(subSizer)
    2447 
    2448     btnsizer = wx.StdDialogButtonSizer()
    2449     OKbtn = wx.Button(dlg, wx.ID_OK,'Continue')
    2450     OKbtn.Enable(False)
    2451     OKbtn.SetDefault()
    2452     OKbtn.Bind(wx.EVT_BUTTON,lambda event: dlg.EndModal(wx.ID_OK))
    2453     btnsizer.AddButton(OKbtn)
    2454     btn = wx.Button(dlg, wx.ID_CANCEL)
    2455     btnsizer.AddButton(btn)
    2456     btnsizer.Realize()
    2457     mainSizer.Add((-1,5),1,wx.EXPAND,1)
    2458     mainSizer.Add(btnsizer,0,wx.ALIGN_CENTER,0)
    2459     mainSizer.Add((-1,10))
    2460 
    2461     dlg.SetSizer(mainSizer)
    2462     dlg.CenterOnParent()
    2463     if dlg.ShowModal() != wx.ID_OK:
    2464         array.update(saveArray)
    2465         dlg.Destroy()
    2466         return
    2467     dlg.Destroy()
    2468 
    2469     copyList = []
    2470     lbl = copyopts['currentsel']
    2471     dlg = G2MultiChoiceDialog(
    2472         G2frame.dataFrame,
    2473         'Copy parameter '+lbl+' from\n'+hst,
    2474         'Copy parameters', histList)
    2475     dlg.CenterOnParent()
    2476     try:
    2477         if dlg.ShowModal() == wx.ID_OK:
    2478             for i in dlg.GetSelections():
    2479                 copyList.append(histList[i])
    2480         else:
    2481             # reset the parameter since cancel was pressed
    2482             array.update(saveArray)
    2483             return
    2484     finally:
    2485         dlg.Destroy()
    2486 
    2487     prelbl = [hst]
    2488     i = labelLst.index(lbl)
    2489     keyLst = elemKeysLst[i]
    2490     refkeys = refFlgElem[i]
    2491     dictlst = [unkey(array,keyLst[:-1])]
    2492     if refkeys is not None:
    2493         refdictlst = [unkey(array,refkeys[:-1])]
    2494     else:
    2495         refdictlst = None
    2496     Id = GetPatternTreeItemId(G2frame,G2frame.root,hst)
    2497     hstData = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,Id,'Instrument Parameters'))[0]
    2498     for h in copyList:
    2499         Id = GetPatternTreeItemId(G2frame,G2frame.root,h)
    2500         instData = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,Id,'Instrument Parameters'))[0]
    2501         if len(hstData) != len(instData) or hstData['Type'][0] != instData['Type'][0]:  #don't mix data types or lam & lam1/lam2 parms!
    2502             print h+' not copied - instrument parameters not commensurate'
    2503             continue
    2504         hData = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,Id,TreeItemType))
    2505         if TreeItemType == 'Instrument Parameters':
    2506             hData = hData[0]
    2507         #copy the value if it is changed or we will not edit in a table
    2508         valNow = unkey(array,keyLst)
    2509         if copyopts['startvalue'] != valNow or not copyopts['InTable']:
    2510             unkey(hData,keyLst[:-1])[keyLst[-1]] = valNow
    2511         prelbl += [h]
    2512         dictlst += [unkey(hData,keyLst[:-1])]
    2513         if refdictlst is not None:
    2514             refdictlst += [unkey(hData,refkeys[:-1])]
    2515     if refdictlst is None:
    2516         args = {}
    2517     else:
    2518         args = {'checkdictlst':refdictlst,
    2519                 'checkelemlst':len(dictlst)*[refkeys[-1]],
    2520                 'checklabel':'Refine?'}
    2521     if copyopts['InTable']:
    2522         dlg = ScrolledMultiEditor(
    2523             G2frame.dataDisplay,dictlst,
    2524             len(dictlst)*[keyLst[-1]],prelbl,
    2525             header='Editing parameter '+lbl,
    2526             CopyButton=True,**args)
    2527         dlg.CenterOnParent()
    2528         if dlg.ShowModal() != wx.ID_OK:
    2529             array.update(saveArray)
    2530         dlg.Destroy()
    2531 
    2532 ################################################################################
    25331326class ShowLSParms(wx.Dialog):
    25341327    '''Create frame to show least-squares parameters
     
    32132006        self.PrefillDataMenu(self.SequentialMenu,helpType='Sequential',helpLbl='Sequential Refinement')
    32142007        self.SequentialFile = wx.Menu(title='')
    3215         self.SequentialMenu.Append(menu=self.SequentialFile, title='Selected Cols')
    3216         self.SequentialFile.Append(id=wxID_RENAMESEQSEL, kind=wx.ITEM_NORMAL,text='Rename',
     2008        self.SequentialMenu.Append(menu=self.SequentialFile, title='Columns')
     2009        self.SequentialFile.Append(id=wxID_RENAMESEQSEL, kind=wx.ITEM_NORMAL,text='Rename selected',
    32172010            help='Rename selected sequential refinement columns')
    3218         self.SequentialFile.Append(id=wxID_SAVESEQSEL, kind=wx.ITEM_NORMAL,text='Save as text',
     2011        self.SequentialFile.Append(id=wxID_SAVESEQSEL, kind=wx.ITEM_NORMAL,text='Save selected as text',
    32192012            help='Save selected sequential refinement results as a text file')
    3220         self.SequentialFile.Append(id=wxID_SAVESEQSELCSV, kind=wx.ITEM_NORMAL,text='Save as CSV',
     2013        self.SequentialFile.Append(id=wxID_SAVESEQSELCSV, kind=wx.ITEM_NORMAL,text='Save selected as CSV',
    32212014            help='Save selected sequential refinement results as a CSV spreadsheet file')
    32222015        self.SequentialFile.Append(id=wxID_PLOTSEQSEL, kind=wx.ITEM_NORMAL,text='Plot selected',
    32232016            help='Plot selected sequential refinement results')
     2017        self.SequentialFile.Append(id=wxID_ORGSEQSEL, kind=wx.ITEM_NORMAL,text='Reorganize',
     2018            help='Reorganize variables where variables change')
    32242019        self.SequentialPvars = wx.Menu(title='')
    32252020        self.SequentialMenu.Append(menu=self.SequentialPvars, title='Pseudo Vars')
     
    45343329        G2plt.PlotSelectedSequence(G2frame,cols,GetColumnInfo,SelectXaxis)
    45353330           
     3331    def OnReOrgSelSeq(event):
     3332        'Reorder the columns'
     3333        G2G.GetItemOrder(G2frame,VaryListChanges,vallookup,posdict)   
     3334        UpdateSeqResults(G2frame,data,G2frame.dataDisplay.GetSize()) # redisplay variables
     3335
    45363336    def OnSaveSelSeqCSV(event):
    45373337        'export the selected columns to a .csv file from menu command'
     
    50413841        lbl = variableLabels.get(var,G2obj.fmtVarDescr(var))
    50423842        dlg = SingleStringDialog(G2frame.dataFrame,'Set variable label',
    5043                                  'Set a name for variable '+var,lbl,size=(400,-1))
     3843                                 'Set a new name for variable '+var,lbl,size=(400,-1))
    50443844        if dlg.Show():
    50453845            variableLabels[var] = dlg.GetValue()
     
    51413941    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveSelSeqCSV, id=wxID_SAVESEQSELCSV)
    51423942    G2frame.dataFrame.Bind(wx.EVT_MENU, OnPlotSelSeq, id=wxID_PLOTSEQSEL)
     3943    G2frame.dataFrame.Bind(wx.EVT_MENU, OnReOrgSelSeq, id=wxID_ORGSEQSEL)
    51433944    G2frame.dataFrame.Bind(wx.EVT_MENU, AddNewPseudoVar, id=wxADDSEQVAR)
    51443945    G2frame.dataFrame.Bind(wx.EVT_MENU, DelPseudoVar, id=wxDELSEQVAR)
     
    51523953    EnableParFitEqMenus()
    51533954
    5154     VaryListChanges = []
     3955    # scan for locations where the variables change
     3956    VaryListChanges = [] # histograms where there is a change
    51553957    prevVaryList = []
    51563958    combinedVaryList = []
    51573959    firstValueList = []
     3960    vallookup = {}
     3961    posdict = {}
    51583962    for i,name in enumerate(histNames):
    51593963        if i == 0 or prevVaryList != sorted(data[name]['varyList']):
    5160             if GSASIIpath.GetConfigValue('debug'):
    5161                 print 'VaryList changes at',name
    5162                 print data[name]['varyList']
    5163                 print data[name]['variables']
    51643964            # add variables to list as they appear
    51653965            for j,var in enumerate(data[name]['varyList']):
     
    51673967                combinedVaryList.append(data[name]['varyList'][j])
    51683968                firstValueList.append(data[name]['variables'][j])
     3969            vallookup[name] = dict(zip(data[name]['varyList'],data[name]['variables']))
     3970            posdict[name] = {}
     3971            for lbl in data[name]['varyList']:
     3972                posdict[name][combinedVaryList.index(lbl)] = lbl           
    51693973            prevVaryList = sorted(data[name]['varyList'])
    5170             VaryListChanges += [name]
     3974            VaryListChanges.append(name)
     3975    if len(VaryListChanges) > 1:
     3976        G2frame.dataFrame.SequentialFile.Enable(wxID_ORGSEQSEL,True)
     3977    else:
     3978        G2frame.dataFrame.SequentialFile.Enable(wxID_ORGSEQSEL,False)
    51713979    #-----------------------------------------------------------------------------------
    51723980    # build up the data table by columns -----------------------------------------------
     
    52314039            colList += zip(*cells)
    52324040            colSigs += zip(*cellESDs)
     4041    # sort out the variables in their selected order
     4042    varcols = 0
     4043    for d in posdict.itervalues():
     4044        varcols = max(varcols,max(d.keys())+1)
     4045    # get labels for each column
     4046    for i in range(varcols):
     4047        lbl = ''
     4048        for h in VaryListChanges:
     4049            if posdict[h].get(i):
     4050                if posdict[h].get(i) in lbl: continue
     4051                if lbl != "": lbl += '/'
     4052                lbl += posdict[h].get(i)
     4053        colLabels.append(lbl)
     4054    Types += varcols*[wg.GRID_VALUE_FLOAT]
     4055    vals = []
     4056    esds = []
     4057    varsellist = None        # will be a list of variable names in the order they are selected to appear
     4058    # tabulate values for each hist, leaving None for blank columns
     4059    for name in histNames:
     4060        if name in posdict:
     4061            varsellist = [posdict[name].get(i) for i in range(varcols)]
     4062            sellist = [data[name]['varyList'].index(v) if v is not None else None for v in varsellist]
     4063        if not varsellist: raise Exception()
     4064        vals.append([data[name]['variables'][s] if s is not None else None for s in sellist])
     4065        esds.append([data[name]['sig'][s] if s is not None else None for s in sellist])
     4066    colList += zip(*vals)
     4067    colSigs += zip(*esds)
    52334068    # add the variables that were refined; change from rows to columns
    52344069    #colList += zip(*[data[name]['variables'] for name in histNames])
     
    52364071    #Types += len(data[histNames[0]]['varyList'])*[wg.GRID_VALUE_FLOAT]
    52374072    #colSigs += zip(*[data[name]['sig'] for name in histNames])
    5238     for var in combinedVaryList:
    5239         colLabels += [var]
    5240         Types += [wg.GRID_VALUE_FLOAT]
    5241         vals = []
    5242         sigs = []
    5243         for name in histNames:
    5244             try:
    5245                 i = data[name]['varyList'].index(var)
    5246                 vals.append(data[name]['variables'][i])
    5247                 sigs.append(data[name]['sig'][i])
    5248             except ValueError: # var not in list
    5249                 vals.append(None)
    5250                 sigs.append(None)
    5251         colList += [vals]
    5252         colSigs += [sigs]
     4073
     4074    # for var in combinedVaryList:
     4075    #     colLabels += [var]
     4076    #     Types += [wg.GRID_VALUE_FLOAT]
     4077    #     vals = []
     4078    #     sigs = []
     4079    #     for name in histNames:
     4080    #         try:
     4081    #             i = data[name]['varyList'].index(var)
     4082    #             vals.append(data[name]['variables'][i])
     4083    #             sigs.append(data[name]['sig'][i])
     4084    #         except ValueError: # var not in list
     4085    #             vals.append(None)
     4086    #             sigs.append(None)
     4087    #     colList += [vals]
     4088    #     colSigs += [sigs]
    52534089               
    52544090    # tabulate constrained variables, removing histogram numbers if needed
     
    53984234        dictlst = [inp] * len(inp)
    53994235        elemlst = range(len(inp))
    5400         dlg = ScrolledMultiEditor(
     4236        dlg = G2G.ScrolledMultiEditor(
    54014237            G2frame,[inp] * len(inp), range(len(inp)), names,
    54024238            header='Edit simulation range',
     
    59074743    print 70*'*'   
    59084744       
    5909 if __name__ == '__main__':
    5910     app = wx.PySimpleApp()
    5911     frm = wx.Frame(None) # create a frame
    5912     frm.Show(True)
    5913 
    5914     #======================================================================
    5915     # test ScrolledMultiEditor
    5916     #======================================================================
    5917     # Data1 = {
    5918     #      'Order':1,
    5919     #      'omega':'string',
    5920     #      'chi':2.0,
    5921     #      'phi':'',
    5922     #      }
    5923     # elemlst = sorted(Data1.keys())
    5924     # prelbl = sorted(Data1.keys())
    5925     # dictlst = len(elemlst)*[Data1,]
    5926     #Data2 = [True,False,False,True]
    5927     #Checkdictlst = len(Data2)*[Data2,]
    5928     #Checkelemlst = range(len(Checkdictlst))
    5929     # print 'before',Data1,'\n',Data2
    5930     # dlg = ScrolledMultiEditor(
    5931     #     frm,dictlst,elemlst,prelbl,
    5932     #     checkdictlst=Checkdictlst,checkelemlst=Checkelemlst,
    5933     #     checklabel="Refine?",
    5934     #     header="test")
    5935     # if dlg.ShowModal() == wx.ID_OK:
    5936     #     print "OK"
    5937     # else:
    5938     #     print "Cancel"
    5939     # print 'after',Data1,'\n',Data2
    5940     # dlg.Destroy()
    5941     Data3 = {
    5942          'Order':1.0,
    5943          'omega':1.1,
    5944          'chi':2.0,
    5945          'phi':2.3,
    5946          'Order1':1.0,
    5947          'omega1':1.1,
    5948          'chi1':2.0,
    5949          'phi1':2.3,
    5950          'Order2':1.0,
    5951          'omega2':1.1,
    5952          'chi2':2.0,
    5953          'phi2':2.3,
    5954          }
    5955     elemlst = sorted(Data3.keys())
    5956     dictlst = len(elemlst)*[Data3,]
    5957     prelbl = elemlst[:]
    5958     prelbl[0]="this is a much longer label to stretch things out"
    5959     Data2 = len(elemlst)*[False,]
    5960     Data2[1] = Data2[3] = True
    5961     Checkdictlst = len(elemlst)*[Data2,]
    5962     Checkelemlst = range(len(Checkdictlst))
    5963     #print 'before',Data3,'\n',Data2
    5964     #print dictlst,"\n",elemlst
    5965     #print Checkdictlst,"\n",Checkelemlst
    5966     dlg = ScrolledMultiEditor(
    5967         frm,dictlst,elemlst,prelbl,
    5968         checkdictlst=Checkdictlst,checkelemlst=Checkelemlst,
    5969         checklabel="Refine?",
    5970         header="test",CopyButton=True)
    5971     if dlg.ShowModal() == wx.ID_OK:
    5972         print "OK"
    5973     else:
    5974         print "Cancel"
    5975     #print 'after',Data3,'\n',Data2
    5976 
    5977     # Data2 = list(range(100))
    5978     # elemlst += range(2,6)
    5979     # postlbl += range(2,6)
    5980     # dictlst += len(range(2,6))*[Data2,]
    5981 
    5982     # prelbl = range(len(elemlst))
    5983     # postlbl[1] = "a very long label for the 2nd item to force a horiz. scrollbar"
    5984     # header="""This is a longer\nmultiline and perhaps silly header"""
    5985     # dlg = ScrolledMultiEditor(frm,dictlst,elemlst,prelbl,postlbl,
    5986     #                           header=header,CopyButton=True)
    5987     # print Data1
    5988     # if dlg.ShowModal() == wx.ID_OK:
    5989     #     for d,k in zip(dictlst,elemlst):
    5990     #         print k,d[k]
    5991     # dlg.Destroy()
    5992     # if CallScrolledMultiEditor(frm,dictlst,elemlst,prelbl,postlbl,
    5993     #                            header=header):
    5994     #     for d,k in zip(dictlst,elemlst):
    5995     #         print k,d[k]
    5996 
    5997     #======================================================================
    5998     # test G2MultiChoiceDialog
    5999     #======================================================================
    6000     # choices = []
    6001     # for i in range(21):
    6002     #     choices.append("option_"+str(i))
    6003     # dlg = G2MultiChoiceDialog(frm, 'Sequential refinement',
    6004     #                           'Select dataset to include',
    6005     #                           choices)
    6006     # sel = range(2,11,2)
    6007     # dlg.SetSelections(sel)
    6008     # dlg.SetSelections((1,5))
    6009     # if dlg.ShowModal() == wx.ID_OK:
    6010     #     for sel in dlg.GetSelections():
    6011     #         print sel,choices[sel]
    6012    
    6013     #======================================================================
    6014     # test wx.MultiChoiceDialog
    6015     #======================================================================
    6016     # dlg = wx.MultiChoiceDialog(frm, 'Sequential refinement',
    6017     #                           'Select dataset to include',
    6018     #                           choices)
    6019     # sel = range(2,11,2)
    6020     # dlg.SetSelections(sel)
    6021     # dlg.SetSelections((1,5))
    6022     # if dlg.ShowModal() == wx.ID_OK:
    6023     #     for sel in dlg.GetSelections():
    6024     #         print sel,choices[sel]
    6025 
    6026     pnl = wx.Panel(frm)
    6027     siz = wx.BoxSizer(wx.VERTICAL)
    6028 
    6029     td = {'Goni':200.,'a':1.,'calc':1./3.,'string':'s'}
    6030     for key in sorted(td):
    6031         txt = ValidatedTxtCtrl(pnl,td,key)
    6032         siz.Add(txt)
    6033     pnl.SetSizer(siz)
    6034     siz.Fit(frm)
    6035     app.MainLoop()
    6036     print td
  • trunk/GSASIIimgGUI.py

    r1583 r1619  
    2929import GSASIIIO as G2IO
    3030import GSASIIgrid as G2gd
     31import GSASIIctrls as G2G
    3132import numpy as np
    3233
     
    12271228    Text.SetBackgroundColour(VERY_LIGHT_GREY)
    12281229    littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Lower/Upper thresholds '),0,WACV)
    1229     lowerThreshold = G2gd.ValidatedTxtCtrl(G2frame.dataDisplay,loc=thresh[1],key=0,
     1230    lowerThreshold = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,loc=thresh[1],key=0,
    12301231                                           min=thresh[0][0],OnLeave=Replot,typeHint=int)
    12311232    littleSizer.Add(lowerThreshold,0,WACV)
    1232     upperThreshold = G2gd.ValidatedTxtCtrl(G2frame.dataDisplay,loc=thresh[1],key=1,
     1233    upperThreshold = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,loc=thresh[1],key=1,
    12331234                                           max=thresh[0][1],OnLeave=Replot,typeHint=int)
    12341235    littleSizer.Add(upperThreshold,0,WACV)
     
    12501251                littleSizer.Add(spotText,0,WACV)
    12511252                spotText.Bind(wx.EVT_ENTER_WINDOW,OnTextMsg)
    1252                 spotDiameter = G2gd.ValidatedTxtCtrl(G2frame.dataDisplay,loc=Spots[i],key=2,
     1253                spotDiameter = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,loc=Spots[i],key=2,
    12531254                                           max=100.,OnLeave=Replot,nDig=[8,2])
    12541255                littleSizer.Add(spotDiameter,0,WACV)
     
    12731274                ringText.Bind(wx.EVT_ENTER_WINDOW,OnTextMsg)
    12741275                littleSizer.Add(ringText,0,WACV)
    1275                 ringThick = G2gd.ValidatedTxtCtrl(G2frame.dataDisplay,loc=Rings[i],key=1,
     1276                ringThick = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,loc=Rings[i],key=1,
    12761277                                           min=0.001,max=1.,OnLeave=Replot,nDig=[8,3])
    12771278                littleSizer.Add(ringThick,0,WACV)
     
    13031304                azmText.Bind(wx.EVT_ENTER_WINDOW,OnTextMsg)
    13041305                littleSizer.Add(azmText,0,WACV)
    1305                 arcThick = G2gd.ValidatedTxtCtrl(G2frame.dataDisplay,loc=Arcs[i],key=2,
     1306                arcThick = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,loc=Arcs[i],key=2,
    13061307                                           min=0.001,max=20.,OnLeave=Replot,nDig=[8,3])
    13071308                littleSizer.Add(arcThick,0,WACV)
     
    16581659        samZ.Bind(wx.EVT_KILL_FOCUS,OnSamZ)
    16591660        samSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,label=' Sample load(MPa): '),0,WACV)
    1660         samLoad = G2gd.ValidatedTxtCtrl(G2frame.dataDisplay,data,'Sample load',
     1661        samLoad = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data,'Sample load',
    16611662                nDig=[8,3],typeHint=float,)
    16621663        samSizer.Add(samLoad,0,WACV)
  • trunk/GSASIIplot.py

    r1618 r1619  
    31353135                Xnew.append(X[i])
    31363136                Ynew.append(Y[i])
    3137                 Ysnew.append(sig[i])
     3137                if sig: Ysnew.append(sig[i])
    31383138            if Ysnew:
    31393139                if G2frame.seqReverse and not G2frame.seqXaxis:
  • trunk/GSASIIpwdGUI.py

    r1618 r1619  
    3838import GSASIIplot as G2plt
    3939import GSASIIgrid as G2gd
     40import GSASIIctrls as G2G
    4041import GSASIIElemGUI as G2elemGUI
    4142import GSASIIElem as G2elem
     
    12391240        '''
    12401241        updateData(insVal,insRef)
    1241         G2gd.SelectEdit1Var(G2frame,data,labelLst,elemKeysLst,dspLst,refFlgElem)
     1242        G2G.SelectEdit1Var(G2frame,data,labelLst,elemKeysLst,dspLst,refFlgElem)
    12421243        insVal.update({key:data[key][1] for key in instkeys})
    12431244        insRef.update({key:data[key][2] for key in instkeys})
     
    13151316                    dspLst.append([10,4])
    13161317                    refFlgElem.append([key,2])                   
    1317                     ratVal = G2gd.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,key,nDig=(10,4),typeHint=float,OnLeave=AfterChange)
     1318                    ratVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,key,nDig=(10,4),typeHint=float,OnLeave=AfterChange)
    13181319                    instSizer.Add(ratVal,0)
    13191320                    instSizer.Add(RefineBox(key),0,WACV)
     
    13291330                    instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,u' Lam (\xc5): (%10.6f)'%(insDef[key])),
    13301331                        0,WACV)
    1331                     waveVal = G2gd.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,key,nDig=(10,6),typeHint=float,OnLeave=AfterChange)
     1332                    waveVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,key,nDig=(10,6),typeHint=float,OnLeave=AfterChange)
    13321333                    labelLst.append(u'Lam (\xc5)')
    13331334                    elemKeysLst.append([key,1])
     
    13501351                            wx.StaticText(G2frame.dataDisplay,-1,lblWdef(item,4,insDef[item])),
    13511352                            0,WACV)
    1352                         itemVal = G2gd.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,item,nDig=(10,4),typeHint=float,OnLeave=AfterChange)
     1353                        itemVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,item,nDig=(10,4),typeHint=float,OnLeave=AfterChange)
    13531354                        instSizer.Add(itemVal,0,WACV)
    13541355                        refFlgElem.append([item,2])
     
    13801381                        wx.StaticText(G2frame.dataDisplay,-1,lblWdef(item,nDig[1],insDef[item])),
    13811382                        0,WACV)
    1382                     itemVal = G2gd.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,item,nDig=nDig,typeHint=float,OnLeave=AfterChange)
     1383                    itemVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,item,nDig=nDig,typeHint=float,OnLeave=AfterChange)
    13831384                    instSizer.Add(itemVal,0,WACV)
    13841385                    instSizer.Add(RefineBox(item),0,WACV)
     
    14291430                            wx.StaticText(G2frame.dataDisplay,-1,lblWdef(item,nDig[1],insDef[item])),
    14301431                            0,WACV)
    1431                     itemVal = G2gd.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,item,nDig=nDig,typeHint=float,OnLeave=AfterChange)
     1432                    itemVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,item,nDig=nDig,typeHint=float,OnLeave=AfterChange)
    14321433                    instSizer.Add(itemVal,0,WACV)
    14331434                    labelLst.append(item)
     
    14401441                instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,u' Lam (\xc5): (%10.6f)'%(insDef['Lam'])),
    14411442                    0,WACV)
    1442                 waveVal = G2gd.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,'Lam',nDig=(10,6),typeHint=float,OnLeave=AfterChange)
     1443                waveVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,'Lam',nDig=(10,6),typeHint=float,OnLeave=AfterChange)
    14431444                instSizer.Add(waveVal,0,WACV)
    14441445                labelLst.append(u'Lam (\xc5)')
     
    14521453                instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,u' Lam (\xc5): (%10.6f)'%(insDef['Lam'])),
    14531454                    0,WACV)
    1454                 waveVal = G2gd.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,'Lam',nDig=(10,6),typeHint=float,OnLeave=AfterChange)
     1455                waveVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,'Lam',nDig=(10,6),typeHint=float,OnLeave=AfterChange)
    14551456                instSizer.Add(waveVal,0,WACV)
    14561457                labelLst.append(u'Lam (\xc5)')
     
    18471848    def OnCopy1Val(event):
    18481849        'Select one value to copy to many histograms and optionally allow values to be edited in a table'
    1849         G2gd.SelectEdit1Var(G2frame,data,labelLst,elemKeysLst,dspLst,refFlgElem)
     1850        G2G.SelectEdit1Var(G2frame,data,labelLst,elemKeysLst,dspLst,refFlgElem)
    18501851        wx.CallAfter(UpdateSampleGrid,G2frame,data)
    18511852       
     
    19561957        dspLst.append(nDig)
    19571958        if 'list' in str(type(data[key])):
    1958             parmRef = G2gd.G2CheckBox(G2frame.dataDisplay,' '+lbl,data[key],1)
     1959            parmRef = G2G.G2CheckBox(G2frame.dataDisplay,' '+lbl,data[key],1)
    19591960            parmSizer.Add(parmRef,0,WACV|wx.EXPAND)
    1960             parmVal = G2gd.ValidatedTxtCtrl(G2frame.dataDisplay,data[key],0,
     1961            parmVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data[key],0,
    19611962                nDig=nDig,typeHint=float,OnLeave=AfterChange)
    19621963            elemKeysLst.append([key,0])
     
    19651966            parmSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' '+lbl),
    19661967                0,WACV|wx.EXPAND)
    1967             parmVal = G2gd.ValidatedTxtCtrl(G2frame.dataDisplay,data,key,
     1968            parmVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data,key,
    19681969                typeHint=float,OnLeave=AfterChange)
    19691970            elemKeysLst.append([key])
     
    19731974       
    19741975    for key in ('FreePrm1','FreePrm2','FreePrm3'):
    1975         parmVal = G2gd.ValidatedTxtCtrl(G2frame.dataDisplay,Controls,key,typeHint=str,
     1976        parmVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,Controls,key,typeHint=str,
    19761977                                        notBlank=False)
    19771978        parmSizer.Add(parmVal,1,wx.EXPAND)
    1978         parmVal = G2gd.ValidatedTxtCtrl(G2frame.dataDisplay,data,key,typeHint=float)
     1979        parmVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data,key,typeHint=float)
    19791980        parmSizer.Add(parmVal,1,wx.EXPAND)
    19801981        labelLst.append(Controls[key])
     
    37873788                    sizeSizer.Add(nRadii,0,WACV)
    37883789                    sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' R dist. cutoff: '),0,WACV)
    3789                     rCutoff = G2gd.ValidatedTxtCtrl(G2frame.dataDisplay,level['Controls'],'Cutoff',
     3790                    rCutoff = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,level['Controls'],'Cutoff',
    37903791                        min=0.001,max=0.1,typeHint=float)
    37913792                    sizeSizer.Add(rCutoff,0,WACV)
     
    38833884        topSizer.Add(matsel,0,WACV)
    38843885        topSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Volume fraction: '),0,WACV)
    3885         volfrac = G2gd.ValidatedTxtCtrl(G2frame.dataDisplay,data['Particle']['Matrix']['VolFrac'],0,
     3886        volfrac = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data['Particle']['Matrix']['VolFrac'],0,
    38863887                typeHint=float)
    38873888        topSizer.Add(volfrac,0,WACV)
Note: See TracChangeset for help on using the changeset viewer.