source: trunk/GSASIIgrid.py @ 927

Last change on this file since 927 was 927, checked in by vondreele, 9 years ago

more G2str fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 106.3 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASIIgrid - data display routines
3########### SVN repository information ###################
4# $Date: 2013-05-20 16:06:42 +0000 (Mon, 20 May 2013) $
5# $Author: vondreele $
6# $Revision: 927 $
7# $URL: trunk/GSASIIgrid.py $
8# $Id: GSASIIgrid.py 927 2013-05-20 16:06:42Z vondreele $
9########### SVN repository information ###################
10'''
11*GSASIIgrid: Basic GUI routines*
12--------------------------------
13
14
15'''
16import wx
17import wx.grid as wg
18import wx.wizard as wz
19import wx.aui
20import time
21import cPickle
22import sys
23import numpy as np
24import numpy.ma as ma
25import os.path
26import wx.html        # could postpone this for quicker startup
27import webbrowser     # could postpone this for quicker startup
28import GSASIIpath
29GSASIIpath.SetVersionNumber("$Revision: 927 $")
30import GSASIImath as G2mth
31import GSASIIIO as G2IO
32import GSASIIlattice as G2lat
33import GSASIIplot as G2plt
34import GSASIIpwdGUI as G2pdG
35import GSASIIimgGUI as G2imG
36import GSASIIphsGUI as G2phG
37import GSASIIspc as G2spc
38import GSASIImapvars as G2mv
39import GSASIIconstrGUI as G2cnstG
40import GSASIIrestrGUI as G2restG
41
42# trig functions in degrees
43sind = lambda x: np.sin(x*np.pi/180.)
44tand = lambda x: np.tan(x*np.pi/180.)
45cosd = lambda x: np.cos(x*np.pi/180.)
46
47# globals we will use later
48__version__ = None # gets overridden in GSASII.py
49path2GSAS2 = os.path.dirname(os.path.realpath(__file__)) # save location of this file
50helpLocDict = {}
51htmlPanel = None
52htmlFrame = None
53helpMode = 'browser'
54#if sys.platform.lower().startswith('win'): helpMode = 'internal' # need a global control to set this
55   
56htmlFirstUse = True
57
58[ wxID_FOURCALC, wxID_FOURSEARCH, wxID_FOURCLEAR, wxID_PEAKSMOVE, wxID_PEAKSCLEAR, 
59    wxID_CHARGEFLIP, wxID_PEAKSUNIQUE, wxID_PEAKSDELETE, wxID_PEAKSDA,
60    wxID_PEAKSDISTVP, wxID_PEAKSVIEWPT, wxID_FINDEQVPEAKS,wxID_SHOWBONDS,
61] = [wx.NewId() for item in range(13)]
62
63[ wxID_PWDRADD, wxID_HKLFADD,wxID_PWDANALYSIS,wxID_DATADELETE,
64] = [wx.NewId() for item in range(4)]
65
66[ wxID_ATOMSEDITADD, wxID_ATOMSEDITINSERT, wxID_ATOMSEDITDELETE, wxID_ATOMSREFINE, 
67    wxID_ATOMSMODIFY, wxID_ATOMSTRANSFORM, wxID_ATOMSVIEWADD, wxID_ATOMVIEWINSERT,
68    wxID_RELOADDRAWATOMS,wxID_ATOMSDISAGL,wxID_ATOMMOVE,wxID_RBAPPEND,
69    wxID_ASSIGNATMS2RB
70] = [wx.NewId() for item in range(13)]
71
72[ wxID_DRAWATOMSTYLE, wxID_DRAWATOMLABEL, wxID_DRAWATOMCOLOR, wxID_DRAWATOMRESETCOLOR, 
73    wxID_DRAWVIEWPOINT, wxID_DRAWTRANSFORM, wxID_DRAWDELETE, wxID_DRAWFILLCELL, 
74    wxID_DRAWADDEQUIV, wxID_DRAWFILLCOORD, wxID_DRAWDISAGLTOR,  wxID_DRAWPLANE,
75    wxID_DRAWDISTVP,
76] = [wx.NewId() for item in range(13)]
77
78[ wxID_DRAWRESTRBOND, wxID_DRAWRESTRANGLE, wxID_DRAWRESTRPLANE, wxID_DRAWRESTRCHIRAL,
79] = [wx.NewId() for item in range(4)]
80
81[ wxID_CLEARTEXTURE,wxID_REFINETEXTURE,
82] = [wx.NewId() for item in range(2)]
83
84[ wxID_PAWLEYLOAD, wxID_PAWLEYDELETE, wxID_PAWLEYESTIMATE,
85    wxID_PAWLEYUPDATE,
86] = [wx.NewId() for item in range(4)]
87
88[ wxID_IMCALIBRATE,wxID_IMRECALIBRATE,wxID_IMINTEGRATE, wxID_IMCLEARCALIB, 
89    wxID_IMCOPYCONTROLS, wxID_INTEGRATEALL, wxID_IMSAVECONTROLS, wxID_IMLOADCONTROLS,
90] = [wx.NewId() for item in range(8)]
91
92[ wxID_MASKCOPY, wxID_MASKSAVE, wxID_MASKLOAD,
93] = [wx.NewId() for item in range(3)]
94
95[ wxID_STRSTACOPY, wxID_STRSTAFIT, wxID_STRSTASAVE, wxID_STRSTALOAD,wxID_APPENDDZERO,
96] = [wx.NewId() for item in range(5)]
97
98[ wxID_BACKCOPY,wxID_LIMITCOPY,wxID_SAMPLECOPY, wxID_BACKFLAGCOPY, wxID_SAMPLEFLAGCOPY,
99    wxID_SAMPLESAVE, wxID_SAMPLELOAD,
100] = [wx.NewId() for item in range(7)]
101
102[ wxID_INSTPRMRESET,wxID_CHANGEWAVETYPE,wxID_INSTCOPY, wxID_INSTFLAGCOPY, wxID_INSTLOAD,
103    wxID_INSTSAVE,
104] = [wx.NewId() for item in range(6)]
105
106[ wxID_UNDO,wxID_LSQPEAKFIT,wxID_LSQONECYCLE,wxID_RESETSIGGAM,wxID_CLEARPEAKS,wxID_AUTOSEARCH,
107] = [wx.NewId() for item in range(6)]
108
109[  wxID_INDXRELOAD, wxID_INDEXPEAKS, wxID_REFINECELL, wxID_COPYCELL, wxID_MAKENEWPHASE,
110] = [wx.NewId() for item in range(5)]
111
112[ wxID_CONSTRAINTADD,wxID_EQUIVADD,wxID_HOLDADD,wxID_FUNCTADD,
113] = [wx.NewId() for item in range(4)]
114
115[ wxID_RESTRAINTADD, wxID_RESTSELPHASE,wxID_RESTDELETE, wxID_RESRCHANGEVAL, 
116    wxID_RESTCHANGEESD,wxID_AARESTRAINTADD,wxID_AARESTRAINTPLOT,
117] = [wx.NewId() for item in range(7)]
118
119[ wxID_RIGIDBODYADD,wxID_DRAWDEFINERB,wxID_RIGIDBODYIMPORT,wxID_RESIDUETORSSEQ,
120    wxID_AUTOFINDRESRB,wxID_GLOBALRESREFINE,wxID_RBREMOVEALL,wxID_COPYRBPARMS,
121] = [wx.NewId() for item in range(8)]
122
123[ wxID_SAVESEQSEL,
124] = [wx.NewId() for item in range(1)]
125
126[ wxID_SELECTPHASE,
127] = [wx.NewId() for item in range(1)]
128
129[ wxID_PDFCOPYCONTROLS, wxID_PDFSAVECONTROLS, wxID_PDFLOADCONTROLS, 
130    wxID_PDFCOMPUTE, wxID_PDFCOMPUTEALL, wxID_PDFADDELEMENT, wxID_PDFDELELEMENT,
131] = [wx.NewId() for item in range(7)]
132
133VERY_LIGHT_GREY = wx.Colour(235,235,235)
134
135################################################################################
136#### GSAS-II class definitions
137################################################################################
138       
139class SymOpDialog(wx.Dialog):
140    '''Class to select a symmetry operator
141    '''
142    def __init__(self,parent,SGData,New=True,ForceUnit=False):
143        wx.Dialog.__init__(self,parent,-1,'Select symmetry operator',
144            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
145        panel = wx.Panel(self)
146        self.SGData = SGData
147        self.New = New
148        self.Force = ForceUnit
149        self.OpSelected = [0,0,0,[0,0,0],False,False]
150        mainSizer = wx.BoxSizer(wx.VERTICAL)
151        if ForceUnit:
152            choice = ['No','Yes']
153            self.force = wx.RadioBox(panel,-1,'Force to unit cell?',choices=choice)
154            self.force.Bind(wx.EVT_RADIOBOX, self.OnOpSelect)
155            mainSizer.Add(self.force,0,wx.ALIGN_CENTER_VERTICAL)
156        mainSizer.Add((5,5),0)
157        if SGData['SGInv']:
158            choice = ['No','Yes']
159            self.inv = wx.RadioBox(panel,-1,'Choose inversion?',choices=choice)
160            self.inv.Bind(wx.EVT_RADIOBOX, self.OnOpSelect)
161            mainSizer.Add(self.inv,0,wx.ALIGN_CENTER_VERTICAL)
162        mainSizer.Add((5,5),0)
163        if SGData['SGLatt'] != 'P':
164            LattOp = G2spc.Latt2text(SGData['SGLatt']).split(';')
165            self.latt = wx.RadioBox(panel,-1,'Choose cell centering?',choices=LattOp)
166            self.latt.Bind(wx.EVT_RADIOBOX, self.OnOpSelect)
167            mainSizer.Add(self.latt,0,wx.ALIGN_CENTER_VERTICAL)
168        mainSizer.Add((5,5),0)
169        if SGData['SGLaue'] in ['-1','2/m','mmm','4/m','4/mmm']:
170            Ncol = 2
171        else:
172            Ncol = 3
173        OpList = []
174        for M,T in SGData['SGOps']:
175            OpList.append(G2spc.MT2text(M,T))
176        self.oprs = wx.RadioBox(panel,-1,'Choose space group operator?',choices=OpList,
177            majorDimension=Ncol)
178        self.oprs.Bind(wx.EVT_RADIOBOX, self.OnOpSelect)
179        mainSizer.Add(self.oprs,0,wx.ALIGN_CENTER_VERTICAL)
180        mainSizer.Add((5,5),0)
181        mainSizer.Add(wx.StaticText(panel,-1,"   Choose unit cell?"),0,wx.ALIGN_CENTER_VERTICAL)
182        mainSizer.Add((5,5),0)
183        cellSizer = wx.BoxSizer(wx.HORIZONTAL)
184        cellSizer.Add((5,0),0)
185        cellName = ['X','Y','Z']
186        self.cell = []
187        for i in range(3):
188            self.cell.append(wx.SpinCtrl(panel,-1,cellName[i],size=wx.Size(50,20)))
189            self.cell[-1].SetRange(-3,3)
190            self.cell[-1].SetValue(0)
191            self.cell[-1].Bind(wx.EVT_SPINCTRL, self.OnOpSelect)
192            cellSizer.Add(self.cell[-1],0,wx.ALIGN_CENTER_VERTICAL)
193        mainSizer.Add(cellSizer,0,)
194        if self.New:
195            choice = ['No','Yes']
196            self.new = wx.RadioBox(panel,-1,'Generate new positions?',choices=choice)
197            self.new.Bind(wx.EVT_RADIOBOX, self.OnOpSelect)
198            mainSizer.Add(self.new,0,wx.ALIGN_CENTER_VERTICAL)
199        mainSizer.Add((5,5),0)
200
201        OkBtn = wx.Button(panel,-1,"Ok")
202        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
203        cancelBtn = wx.Button(panel,-1,"Cancel")
204        cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
205        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
206        btnSizer.Add((20,20),1)
207        btnSizer.Add(OkBtn)
208        btnSizer.Add((20,20),1)
209        btnSizer.Add(cancelBtn)
210        btnSizer.Add((20,20),1)
211
212        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
213        panel.SetSizer(mainSizer)
214        panel.Fit()
215        self.Fit()
216
217    def OnOpSelect(self,event):
218        if self.SGData['SGInv']:
219            self.OpSelected[0] = self.inv.GetSelection()
220        if self.SGData['SGLatt'] != 'P':
221            self.OpSelected[1] = self.latt.GetSelection()
222        self.OpSelected[2] = self.oprs.GetSelection()
223        for i in range(3):
224            self.OpSelected[3][i] = float(self.cell[i].GetValue())
225        if self.New:
226            self.OpSelected[4] = self.new.GetSelection()
227        if self.Force:
228            self.OpSelected[5] = self.force.GetSelection()
229
230    def GetSelection(self):
231        return self.OpSelected
232
233    def OnOk(self,event):
234        parent = self.GetParent()
235        parent.Raise()
236        self.EndModal(wx.ID_OK)
237
238    def OnCancel(self,event):
239        parent = self.GetParent()
240        parent.Raise()
241        self.EndModal(wx.ID_CANCEL)
242
243class DisAglDialog(wx.Dialog):
244    '''Distance Angle Controls dialog
245    '''
246    def __default__(self,data,default):
247        if data:
248            self.data = data
249        else:
250            self.data = {}
251            self.data['Name'] = default['Name']
252            self.data['Factors'] = [0.85,0.85]
253            self.data['AtomTypes'] = default['AtomTypes']
254            self.data['BondRadii'] = default['BondRadii']
255            self.data['AngleRadii'] = default['AngleRadii']
256       
257    def __init__(self,parent,data,default):
258        wx.Dialog.__init__(self,parent,-1,'Distance Angle Controls', 
259            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
260        self.default = default
261        self.panel = wx.Panel(self)         #just a dummy - gets destroyed in Draw!
262        self.__default__(data,self.default)
263        self.Draw(self.data)
264               
265    def Draw(self,data):
266        self.panel.Destroy()
267        self.panel = wx.Panel(self)
268        mainSizer = wx.BoxSizer(wx.VERTICAL)
269        mainSizer.Add(wx.StaticText(self.panel,-1,'Controls for phase '+data['Name']),
270            0,wx.ALIGN_CENTER_VERTICAL|wx.LEFT,10)
271        mainSizer.Add((10,10),1)
272       
273        radiiSizer = wx.FlexGridSizer(2,3,5,5)
274        radiiSizer.Add(wx.StaticText(self.panel,-1,' Type'),0,wx.ALIGN_CENTER_VERTICAL)
275        radiiSizer.Add(wx.StaticText(self.panel,-1,'Bond radii'),0,wx.ALIGN_CENTER_VERTICAL)
276        radiiSizer.Add(wx.StaticText(self.panel,-1,'Angle radii'),0,wx.ALIGN_CENTER_VERTICAL)
277        self.objList = {}
278        for id,item in enumerate(self.data['AtomTypes']):
279            radiiSizer.Add(wx.StaticText(self.panel,-1,' '+item),0,wx.ALIGN_CENTER_VERTICAL)
280            bRadii = wx.TextCtrl(self.panel,-1,value='%.3f'%(data['BondRadii'][id]),style=wx.TE_PROCESS_ENTER)
281            self.objList[bRadii.GetId()] = ['BondRadii',id]
282            bRadii.Bind(wx.EVT_TEXT_ENTER,self.OnRadiiVal)
283            bRadii.Bind(wx.EVT_KILL_FOCUS,self.OnRadiiVal)
284            radiiSizer.Add(bRadii,0,wx.ALIGN_CENTER_VERTICAL)
285            aRadii = wx.TextCtrl(self.panel,-1,value='%.3f'%(data['AngleRadii'][id]),style=wx.TE_PROCESS_ENTER)
286            self.objList[aRadii.GetId()] = ['AngleRadii',id]
287            aRadii.Bind(wx.EVT_TEXT_ENTER,self.OnRadiiVal)
288            aRadii.Bind(wx.EVT_KILL_FOCUS,self.OnRadiiVal)
289            radiiSizer.Add(aRadii,0,wx.ALIGN_CENTER_VERTICAL)
290        mainSizer.Add(radiiSizer,0,wx.EXPAND)
291        factorSizer = wx.FlexGridSizer(2,2,5,5)
292        Names = ['Bond','Angle']
293        for i,name in enumerate(Names):
294            factorSizer.Add(wx.StaticText(self.panel,-1,name+' search factor'),0,wx.ALIGN_CENTER_VERTICAL)
295            bondFact = wx.TextCtrl(self.panel,-1,value='%.3f'%(data['Factors'][i]),style=wx.TE_PROCESS_ENTER)
296            self.objList[bondFact.GetId()] = ['Factors',i]
297            bondFact.Bind(wx.EVT_TEXT_ENTER,self.OnRadiiVal)
298            bondFact.Bind(wx.EVT_KILL_FOCUS,self.OnRadiiVal)
299            factorSizer.Add(bondFact)
300        mainSizer.Add(factorSizer,0,wx.EXPAND)
301       
302        OkBtn = wx.Button(self.panel,-1,"Ok")
303        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
304        ResetBtn = wx.Button(self.panel,-1,'Reset')
305        ResetBtn.Bind(wx.EVT_BUTTON, self.OnReset)
306        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
307        btnSizer.Add((20,20),1)
308        btnSizer.Add(OkBtn)
309        btnSizer.Add(ResetBtn)
310        btnSizer.Add((20,20),1)
311        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
312        self.panel.SetSizer(mainSizer)
313        self.panel.Fit()
314        self.Fit()
315   
316    def OnRadiiVal(self,event):
317        Obj = event.GetEventObject()
318        item = self.objList[Obj.GetId()]
319        try:
320            self.data[item[0]][item[1]] = float(Obj.GetValue())
321        except ValueError:
322            pass
323        Obj.SetValue("%.3f"%(self.data[item[0]][item[1]]))          #reset in case of error
324       
325    def GetData(self):
326        return self.data
327       
328    def OnOk(self,event):
329        parent = self.GetParent()
330        parent.Raise()
331        self.EndModal(wx.ID_OK)             
332       
333    def OnReset(self,event):
334        data = {}
335        self.__default__(data,self.default)
336        self.Draw(self.data)
337       
338class PickTwoDialog(wx.Dialog):
339    '''This does not seem to be in use
340    '''
341    def __init__(self,parent,title,prompt,names,choices):
342        wx.Dialog.__init__(self,parent,-1,title, 
343            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
344        self.panel = wx.Panel(self)         #just a dummy - gets destroyed in Draw!
345        self.prompt = prompt
346        self.choices = choices
347        self.names = names
348        self.Draw()
349
350    def Draw(self):
351        Indx = {}
352       
353        def OnSelection(event):
354            Obj = event.GetEventObject()
355            id = Indx[Obj.GetId()]
356            self.choices[id] = Obj.GetValue().encode()  #to avoid Unicode versions
357            self.Draw()
358           
359        self.panel.DestroyChildren()
360        self.panel.Destroy()
361        self.panel = wx.Panel(self)
362        mainSizer = wx.BoxSizer(wx.VERTICAL)
363        mainSizer.Add(wx.StaticText(self.panel,-1,self.prompt),0,wx.ALIGN_CENTER)
364        for isel,name in enumerate(self.choices):
365            lineSizer = wx.BoxSizer(wx.HORIZONTAL)
366            lineSizer.Add(wx.StaticText(self.panel,-1,'Reference atom '+str(isel+1)),0,wx.ALIGN_CENTER)
367            nameList = self.names[:]
368            if isel:
369                if self.choices[0] in nameList:
370                    nameList.remove(self.choices[0])
371            choice = wx.ComboBox(self.panel,-1,value=name,choices=nameList,
372                style=wx.CB_READONLY|wx.CB_DROPDOWN)
373            Indx[choice.GetId()] = isel
374            choice.Bind(wx.EVT_COMBOBOX, OnSelection)
375            lineSizer.Add(choice,0,wx.ALIGN_CENTER)
376            mainSizer.Add(lineSizer)
377        OkBtn = wx.Button(self.panel,-1,"Ok")
378        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
379        CancelBtn = wx.Button(self.panel,-1,'Cancel')
380        CancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
381        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
382        btnSizer.Add((20,20),1)
383        btnSizer.Add(OkBtn)
384        btnSizer.Add(CancelBtn)
385        btnSizer.Add((20,20),1)
386        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
387        self.panel.SetSizer(mainSizer)
388        self.panel.Fit()
389        self.Fit()
390       
391    def GetSelection(self):
392        return self.choices
393
394    def OnOk(self,event):
395        parent = self.GetParent()
396        parent.Raise()
397        self.EndModal(wx.ID_OK)             
398       
399    def OnCancel(self,event):
400        parent = self.GetParent()
401        parent.Raise()
402        self.EndModal(wx.ID_CANCEL)
403       
404class SingleFloatDialog(wx.Dialog):
405    'Dialog to obtain a single float value from user'
406    def __init__(self,parent,title,prompt,value,limits=[0.,1.],format='%.5g'):
407        wx.Dialog.__init__(self,parent,-1,title, 
408            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
409        self.panel = wx.Panel(self)         #just a dummy - gets destroyed in Draw!
410        self.limits = limits
411        self.value = value
412        self.prompt = prompt
413        self.format = format
414        self.Draw()
415       
416    def Draw(self):
417       
418        def OnValItem(event):
419            try:
420                val = float(valItem.GetValue())
421                if val < self.limits[0] or val > self.limits[1]:
422                    raise ValueError
423            except ValueError:
424                val = self.value
425            self.value = val
426            valItem.SetValue(self.format%(self.value))
427           
428        self.panel.Destroy()
429        self.panel = wx.Panel(self)
430        mainSizer = wx.BoxSizer(wx.VERTICAL)
431        mainSizer.Add(wx.StaticText(self.panel,-1,self.prompt),0,wx.ALIGN_CENTER)
432        valItem = wx.TextCtrl(self.panel,-1,value=self.format%(self.value),style=wx.TE_PROCESS_ENTER)
433        mainSizer.Add(valItem,0,wx.ALIGN_CENTER)
434        valItem.Bind(wx.EVT_TEXT_ENTER,OnValItem)
435        valItem.Bind(wx.EVT_KILL_FOCUS,OnValItem)
436        OkBtn = wx.Button(self.panel,-1,"Ok")
437        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
438        CancelBtn = wx.Button(self.panel,-1,'Cancel')
439        CancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
440        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
441        btnSizer.Add((20,20),1)
442        btnSizer.Add(OkBtn)
443        btnSizer.Add(CancelBtn)
444        btnSizer.Add((20,20),1)
445        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
446        self.panel.SetSizer(mainSizer)
447        self.panel.Fit()
448        self.Fit()
449
450    def GetValue(self):
451        return self.value
452       
453    def OnOk(self,event):
454        parent = self.GetParent()
455        parent.Raise()
456        self.EndModal(wx.ID_OK)             
457       
458    def OnCancel(self,event):
459        parent = self.GetParent()
460        parent.Raise()
461        self.EndModal(wx.ID_CANCEL)
462       
463class GridFractionEditor(wg.PyGridCellEditor):
464    '''A grid cell editor class that allows entry of values as fractions as well
465    as sine and cosine values [as s() and c()]
466    '''
467    def __init__(self,grid):
468        wg.PyGridCellEditor.__init__(self)
469
470    def Create(self, parent, id, evtHandler):
471        self._tc = wx.TextCtrl(parent, id, "")
472        self._tc.SetInsertionPoint(0)
473        self.SetControl(self._tc)
474
475        if evtHandler:
476            self._tc.PushEventHandler(evtHandler)
477
478        self._tc.Bind(wx.EVT_CHAR, self.OnChar)
479
480    def SetSize(self, rect):
481        self._tc.SetDimensions(rect.x, rect.y, rect.width+2, rect.height+2,
482                               wx.SIZE_ALLOW_MINUS_ONE)
483
484    def BeginEdit(self, row, col, grid):
485        self.startValue = grid.GetTable().GetValue(row, col)
486        self._tc.SetValue(str(self.startValue))
487        self._tc.SetInsertionPointEnd()
488        self._tc.SetFocus()
489        self._tc.SetSelection(0, self._tc.GetLastPosition())
490
491    def EndEdit(self, row, col, grid):
492        changed = False
493
494        val = self._tc.GetValue().lower()
495       
496        if val != self.startValue:
497            changed = True
498            neg = False
499            if '-' in val:
500                neg = True
501            if '/' in val and '.' not in val:
502                val += '.'
503            elif 's' in val and not 'sind(' in val:
504                if neg:
505                    val = '-sind('+val.strip('-s')+')'
506                else:
507                    val = 'sind('+val.strip('s')+')'
508            elif 'c' in val and not 'cosd(' in val:
509                if neg:
510                    val = '-cosd('+val.strip('-c')+')'
511                else:
512                    val = 'cosd('+val.strip('c')+')'
513            try:
514                val = float(eval(val))
515            except (SyntaxError,NameError):
516                val = self.startValue
517            grid.GetTable().SetValue(row, col, val) # update the table
518
519        self.startValue = ''
520        self._tc.SetValue('')
521        return changed
522
523    def Reset(self):
524        self._tc.SetValue(self.startValue)
525        self._tc.SetInsertionPointEnd()
526
527    def Clone(self):
528        return GridFractionEditor(grid)
529
530    def StartingKey(self, evt):
531        self.OnChar(evt)
532        if evt.GetSkipped():
533            self._tc.EmulateKeyPress(evt)
534
535    def OnChar(self, evt):
536        key = evt.GetKeyCode()
537        if key == 15:
538            return
539        if key > 255:
540            evt.Skip()
541            return
542        char = chr(key)
543        if char in '.+-/0123456789cosind()':
544            self._tc.WriteText(char)
545        else:
546            evt.Skip()
547
548class MyHelp(wx.Menu):
549    '''
550    A class that creates the contents of a help menu.
551    The menu will start with two entries:
552
553    * 'Help on <helpType>': where helpType is a reference to an HTML page to
554      be opened
555    * About: opens an About dialog using OnHelpAbout. N.B. on the Mac this
556      gets moved to the App menu to be consistent with Apple style.
557
558    NOTE: for this to work properly with respect to system menus, the title
559    for the menu must be &Help, or it will not be processed properly:
560
561    ::
562
563       menu.Append(menu=MyHelp(self,...),title="&Help")
564
565    '''
566    def __init__(self,frame,helpType=None,helpLbl=None,morehelpitems=[],title=''):
567        wx.Menu.__init__(self,title)
568        self.HelpById = {}
569        self.frame = frame
570        self.Append(help='', id=wx.ID_ABOUT, kind=wx.ITEM_NORMAL,
571            text='&About GSAS-II')
572        frame.Bind(wx.EVT_MENU, self.OnHelpAbout, id=wx.ID_ABOUT)
573        if GSASIIpath.whichsvn():
574            helpobj = self.Append(
575                help='', id=wx.ID_ANY, kind=wx.ITEM_NORMAL,
576                text='&Check for updates')
577            frame.Bind(wx.EVT_MENU, self.OnCheckUpdates, helpobj)
578        for lbl,indx in morehelpitems:
579            helpobj = self.Append(text=lbl,
580                id=wx.ID_ANY, kind=wx.ITEM_NORMAL)
581            frame.Bind(wx.EVT_MENU, self.OnHelpById, helpobj)
582            self.HelpById[helpobj.GetId()] = indx
583        # add a help item only when helpType is specified
584        if helpType is not None:
585            self.AppendSeparator()
586            if helpLbl is None: helpLbl = helpType
587            helpobj = self.Append(text='Help on '+helpLbl,
588                                  id=wx.ID_ANY, kind=wx.ITEM_NORMAL)
589            frame.Bind(wx.EVT_MENU, self.OnHelpById, helpobj)
590            self.HelpById[helpobj.GetId()] = helpType
591       
592    def OnHelpById(self,event):
593        '''Called when Help on... is pressed in a menu. Brings up
594        a web page for documentation.
595        '''
596        helpType = self.HelpById.get(event.GetId())
597        if helpType is None:
598            print 'Error: help lookup failed!',event.GetEventObject()
599            print 'id=',event.GetId()
600        else:
601            ShowHelp(helpType,self.frame)
602
603    def OnHelpAbout(self, event):
604        "Display an 'About GSAS-II' box"
605        global __version__
606        info = wx.AboutDialogInfo()
607        info.Name = 'GSAS-II'
608        info.Version = __version__ + ' Revision '+str(GSASIIpath.GetVersionNumber())
609        info.Copyright = '''
610Robert B. Von Dreele & Brian H. Toby
611Argonne National Laboratory(C)
612This product includes software developed
613by the UChicago Argonne, LLC, as
614Operator of Argonne National Laboratory.       
615Please cite:
616B.H. Toby & R.B. Von Dreele, J. Appl. Cryst. 46, 544-549 (2013) '''
617        info.Description = '''
618General Structure Analysis System - GSAS-II
619'''
620        wx.AboutBox(info)
621
622    def OnCheckUpdates(self,event):
623        '''Check if the GSAS-II repository has an update for the current source files
624        and perform that update if requested.
625        '''
626        if not GSASIIpath.whichsvn():
627            dlg = wx.MessageDialog(self,'No Subversion','Cannot update GSAS-II because subversion (svn) '+
628                                   'was not found.'
629                                   ,wx.OK)
630            dlg.ShowModal()
631            return
632        wx.BeginBusyCursor()
633        local = GSASIIpath.svnGetRev()
634        if local is None: 
635            wx.EndBusyCursor()
636            dlg = wx.MessageDialog(self.frame,
637                                   'Unable to run subversion on the GSAS-II current directory. Is GSAS-II installed correctly?',
638                                   'Subversion error',
639                                   wx.OK)
640            dlg.ShowModal()
641            return
642        print 'Installed GSAS-II version: '+local
643        repos = GSASIIpath.svnGetRev(local=False)
644        wx.EndBusyCursor()
645        if repos is None: 
646            dlg = wx.MessageDialog(self.frame,
647                                   'Unable to access the GSAS-II server. Is this computer on the internet?',
648                                   'Server unavailable',
649                                   wx.OK)
650            dlg.ShowModal()
651            return
652        print 'GSAS-II version on server: '+repos
653        if local == repos:
654            dlg = wx.MessageDialog(self.frame,
655                                   'GSAS-II is up-to-date. Version '+local+' is already loaded.',
656                                   'GSAS-II Up-to-date',
657                                   wx.OK)
658            dlg.ShowModal()
659            return
660        mods = GSASIIpath.svnFindLocalChanges()
661        if mods:
662            dlg = wx.MessageDialog(self.frame,
663                                   'You have version '+local+
664                                   ' of GSAS-II installed, but the current version is '+repos+
665                                   '. However, you have modified '+str(len(mods))+
666                                   ' file(s) on your local computer have been modified.'
667                                   ' Updating could wipe out your local changes. Press OK to start an update:',
668                                   'Local GSAS-II Mods',
669                                   wx.OK|wx.CANCEL)
670            if dlg.ShowModal() != wx.ID_OK: return
671        else:
672            dlg = wx.MessageDialog(self.frame,
673                                   'You have version '+local+
674                                   ' of GSAS-II installed, but the current version is '+repos+
675                                   '. Press OK to start an update:',
676                                   'GSAS-II Updates',
677                                   wx.OK|wx.CANCEL)
678            if dlg.ShowModal() != wx.ID_OK: return
679        print 'start updates'
680        wx.BeginBusyCursor()
681        moddict = GSASIIpath.svnUpdateDir()
682        wx.EndBusyCursor()
683        if moddict is None: 
684            dlg = wx.MessageDialog(self.frame,
685                                   'Error accessing the GSAS-II server or performing the update. '+
686                                   'Try again later or perform a manual update',
687                                   'Update Error',
688                                   wx.OK)
689            dlg.ShowModal()
690            return
691        modsbytype = {}
692        for key in moddict:
693            typ = moddict[key]
694            if modsbytype.get(typ) is None:
695                modsbytype[typ] = []
696            modsbytype[typ].append(key)
697        msg = 'Update was completed. Changes will take effect when GSAS-II is next updated. The following files were updated, ordered by status:'
698        for key in modsbytype:
699            msg += '\n' + key + ':\n\t'
700            for fil in modsbytype:
701                msg += fil + ', '
702        dlg = wx.MessageDialog(self.frame,msg, 'Update Completed', wx.OK)
703        dlg.ShowModal()
704        return
705
706class AddHelp(wx.Menu):
707    '''This class a single entry for the help menu (used on the Mac only):
708    'Help on <helpType>': where helpType is a reference to an HTML page to
709    be opened
710
711    NOTE: the title when appending this menu should be '&Help' so the wx handles
712    it correctly.
713    '''
714    def __init__(self,frame,helpType,helpLbl=None,title=''):
715        wx.Menu.__init__(self,title)
716        self.frame = frame
717        if helpLbl is None: helpLbl = helpType
718        # add a help item only when helpType is specified
719        helpobj = self.Append(text='Help on '+helpLbl,
720                              id=wx.ID_ANY, kind=wx.ITEM_NORMAL)
721        frame.Bind(wx.EVT_MENU, self.OnHelpById, helpobj)
722        self.HelpById = helpType
723       
724    def OnHelpById(self,event):
725        '''Called when Help on... is pressed in a menu. Brings up
726        a web page for documentation.
727        '''
728        ShowHelp(self.HelpById,self.frame)
729
730class MyHtmlPanel(wx.Panel):
731    '''Defines a panel to display Help information'''
732    def __init__(self, frame, id):
733        self.frame = frame
734        wx.Panel.__init__(self, frame, id)
735        sizer = wx.BoxSizer(wx.VERTICAL)
736        back = wx.Button(self, -1, "Back")
737        back.Bind(wx.EVT_BUTTON, self.OnBack)
738        self.htmlwin = G2HtmlWindow(self, id, size=(750,450))
739        sizer.Add(self.htmlwin, 1,wx.EXPAND)
740        sizer.Add(back, 0, wx.ALIGN_LEFT, 0)
741        self.SetSizer(sizer)
742        sizer.Fit(frame)       
743        self.Bind(wx.EVT_SIZE,self.OnHelpSize)
744    def OnHelpSize(self,event):         #does the job but weirdly!!
745        anchor = self.htmlwin.GetOpenedAnchor()
746        if anchor:           
747            self.htmlwin.ScrollToAnchor(anchor)
748            wx.CallAfter(self.htmlwin.ScrollToAnchor,anchor)
749            event.Skip()
750    def OnBack(self, event):
751        self.htmlwin.HistoryBack()
752    def LoadFile(self,file):
753        pos = file.rfind('#')
754        if pos != -1:
755            helpfile = file[:pos]
756            helpanchor = file[pos+1:]
757        else:
758            helpfile = file
759            helpanchor = None
760        self.htmlwin.LoadPage(helpfile)
761        if helpanchor is not None:
762            self.htmlwin.ScrollToAnchor(helpanchor)
763            xs,ys = self.htmlwin.GetViewStart()
764            self.htmlwin.Scroll(xs,ys-1)
765
766class G2HtmlWindow(wx.html.HtmlWindow):
767    '''Displays help information in a primitive HTML browser type window
768    '''
769    def __init__(self, parent, *args, **kwargs):
770        self.parent = parent
771        wx.html.HtmlWindow.__init__(self, parent, *args, **kwargs)
772    def LoadPage(self, *args, **kwargs):
773        wx.html.HtmlWindow.LoadPage(self, *args, **kwargs)
774        self.TitlePage()
775    def OnLinkClicked(self, *args, **kwargs):
776        wx.html.HtmlWindow.OnLinkClicked(self, *args, **kwargs)
777        xs,ys = self.GetViewStart()
778        self.Scroll(xs,ys-1)
779        self.TitlePage()
780    def HistoryBack(self, *args, **kwargs):
781        wx.html.HtmlWindow.HistoryBack(self, *args, **kwargs)
782        self.TitlePage()
783    def TitlePage(self):
784        self.parent.frame.SetTitle(self.GetOpenedPage() + ' -- ' + 
785            self.GetOpenedPageTitle())
786
787class DataFrame(wx.Frame):
788    '''Create the dataframe window and all the entries in menus.
789    The binding is for the menus is not done here, but rather is done
790    where the functions can be accessed (in various GSASII*GUI modules).
791    '''
792    def Bind(self,*args,**kwargs):
793        '''Override the Bind() function: on the Mac the binding is to
794        the main window, so that menus operate with any window on top.
795        For other platforms, call the default wx.Frame Bind()
796        '''
797        if sys.platform == "darwin": # mac
798            self.G2frame.Bind(*args,**kwargs)
799        else:
800            wx.Frame.Bind(self,*args,**kwargs)     
801       
802    def PrefillDataMenu(self,menu,helpType,helpLbl=None,empty=False):
803        '''Create the "standard" part of data frame menus. Note that on Linux and
804        Windows nothing happens here. On Mac, this menu duplicates the
805        tree menu, but adds an extra help command for the data item and a separator.
806        '''
807        self.datamenu = menu
808        self.helpType = helpType
809        self.helpLbl = helpLbl
810        if sys.platform == "darwin": # mac                         
811            self.G2frame.FillMainMenu(menu) # add the data tree menu items
812            if not empty:
813                menu.Append(wx.Menu(title=''),title='|') # add a separator
814       
815    def PostfillDataMenu(self,empty=False):
816        '''Create the "standard" part of data frame menus. Note that on Linux and
817        Windows, this is the standard help Menu. On Mac, this menu duplicates the
818        tree menu, but adds an extra help command for the data item and a separator.
819        '''
820        menu = self.datamenu
821        helpType = self.helpType
822        helpLbl = self.helpLbl
823        if sys.platform == "darwin": # mac
824            if not empty:
825                menu.Append(wx.Menu(title=''),title='|') # add another separator
826            menu.Append(AddHelp(self.G2frame,helpType=helpType, helpLbl=helpLbl),
827                        title='&Help')
828        else: # other
829            menu.Append(menu=MyHelp(self,helpType=helpType, helpLbl=helpLbl),
830                        title='&Help')
831
832    def _init_menus(self):
833        'define all GSAS-II data frame menus'
834
835        # for use where no menu or data frame help is provided
836        self.BlankMenu = wx.MenuBar()
837       
838        # Controls
839        self.ControlsMenu = wx.MenuBar()
840        self.PrefillDataMenu(self.ControlsMenu,helpType='Controls',empty=True)
841        self.PostfillDataMenu(empty=True)
842       
843        # Notebook
844        self.DataNotebookMenu = wx.MenuBar() 
845        self.PrefillDataMenu(self.DataNotebookMenu,helpType='Notebook',empty=True)
846        self.PostfillDataMenu(empty=True)
847       
848        # Comments
849        self.DataCommentsMenu = wx.MenuBar()
850        self.PrefillDataMenu(self.DataCommentsMenu,helpType='Comments',empty=True)
851        self.PostfillDataMenu(empty=True)
852       
853        # Constraints
854        self.ConstraintMenu = wx.MenuBar()
855        self.PrefillDataMenu(self.ConstraintMenu,helpType='Constraints')
856        self.ConstraintEdit = wx.Menu(title='')
857        self.ConstraintMenu.Append(menu=self.ConstraintEdit, title='Edit')
858        self.ConstraintEdit.Append(id=wxID_HOLDADD, kind=wx.ITEM_NORMAL,text='Add hold',
859            help='Add hold on a parameter value')
860        self.ConstraintEdit.Append(id=wxID_EQUIVADD, kind=wx.ITEM_NORMAL,text='Add equivalence',
861            help='Add equivalence between parameter values')
862        self.ConstraintEdit.Append(id=wxID_CONSTRAINTADD, kind=wx.ITEM_NORMAL,text='Add constraint',
863            help='Add constraint on parameter values')
864        self.ConstraintEdit.Append(id=wxID_FUNCTADD, kind=wx.ITEM_NORMAL,text='Add New Var',
865            help='Add variable composed of existing parameter')
866        self.PostfillDataMenu()
867       
868        # Rigid bodies
869        self.VectorRBEdit = wx.Menu(title='')
870        self.VectorRBEdit.Append(id=wxID_RIGIDBODYADD, kind=wx.ITEM_NORMAL,text='Add rigid body',
871            help='Add vector rigid body')
872        self.ResidueRBMenu = wx.Menu(title='')
873        self.ResidueRBMenu.Append(id=wxID_RIGIDBODYIMPORT, kind=wx.ITEM_NORMAL,text='Import XYZ',
874            help='Import rigid body XYZ from file')
875        self.ResidueRBMenu.Append(id=wxID_RESIDUETORSSEQ, kind=wx.ITEM_NORMAL,text='Define sequence',
876            help='Define torsion sequence')
877        self.ResidueRBMenu.Append(id=wxID_RIGIDBODYADD, kind=wx.ITEM_NORMAL,text='Import residues',
878            help='Import residue rigid bodies from macro file')
879           
880        self.RigidBodyMenu = wx.MenuBar()
881        self.PrefillDataMenu(self.RigidBodyMenu,helpType='Rigid bodies')
882        self.RigidBodyMenu.Append(menu=self.VectorRBEdit, title='Edit')       
883        self.PostfillDataMenu()
884           
885        # Restraints
886        self.RestraintEdit = wx.Menu(title='')
887        self.RestraintEdit.Append(id=wxID_RESTSELPHASE, kind=wx.ITEM_NORMAL,text='Select phase',
888            help='Select phase')
889        self.RestraintEdit.Append(id=wxID_RESTRAINTADD, kind=wx.ITEM_NORMAL,text='Add restraints',
890            help='Add restraints')
891        self.RestraintEdit.Enable(wxID_RESTRAINTADD,True)    #gets disenabled if macromolecule phase
892        self.RestraintEdit.Append(id=wxID_AARESTRAINTADD, kind=wx.ITEM_NORMAL,text='Add residue restraints',
893            help='Add residue based restraints for macromolecules from macro file')
894        self.RestraintEdit.Enable(wxID_AARESTRAINTADD,False)    #gets enabled if macromolecule phase
895        self.RestraintEdit.Append(id=wxID_AARESTRAINTPLOT, kind=wx.ITEM_NORMAL,text='Plot residue restraints',
896            help='Plot selected residue based restraints for macromolecules from macro file')
897        self.RestraintEdit.Enable(wxID_AARESTRAINTPLOT,False)    #gets enabled if macromolecule phase
898        self.RestraintEdit.Append(id=wxID_RESRCHANGEVAL, kind=wx.ITEM_NORMAL,text='Change value',
899            help='Change observed value')
900        self.RestraintEdit.Append(id=wxID_RESTCHANGEESD, kind=wx.ITEM_NORMAL,text='Change esd',
901            help='Change esd in observed value')
902        self.RestraintEdit.Append(id=wxID_RESTDELETE, kind=wx.ITEM_NORMAL,text='Delete restraints',
903            help='Delete selected restraints')
904
905        self.RestraintMenu = wx.MenuBar()
906        self.PrefillDataMenu(self.RestraintMenu,helpType='Restraints')
907        self.RestraintMenu.Append(menu=self.RestraintEdit, title='Edit')
908        self.PostfillDataMenu()
909           
910        # Sequential results
911        self.SequentialMenu = wx.MenuBar()
912        self.PrefillDataMenu(self.SequentialMenu,helpType='Sequential',helpLbl='Sequential Refinement')
913        self.SequentialFile = wx.Menu(title='')
914        self.SequentialMenu.Append(menu=self.SequentialFile, title='File')
915        self.SequentialFile.Append(id=wxID_SAVESEQSEL, kind=wx.ITEM_NORMAL,text='Save...',
916            help='Save selected sequential refinement results')
917        self.PostfillDataMenu()
918           
919        # PDR
920        self.ErrorMenu = wx.MenuBar()
921        self.PrefillDataMenu(self.ErrorMenu,helpType='PWD Analysis',helpLbl='Powder Fit Error Analysis')
922        self.ErrorAnal = wx.Menu(title='')
923        self.ErrorMenu.Append(menu=self.ErrorAnal,title='Analysis')
924        self.ErrorAnal.Append(id=wxID_PWDANALYSIS,kind=wx.ITEM_NORMAL,text='Analyze',
925            help='Error analysis on powder pattern')
926        self.PostfillDataMenu()
927           
928        # PDR / Limits
929        self.LimitMenu = wx.MenuBar()
930        self.PrefillDataMenu(self.LimitMenu,helpType='Limits')
931        self.LimitEdit = wx.Menu(title='')
932        self.LimitMenu.Append(menu=self.LimitEdit, title='File')
933        self.LimitEdit.Append(id=wxID_LIMITCOPY, kind=wx.ITEM_NORMAL,text='Copy',
934            help='Copy limits to other histograms')
935        self.PostfillDataMenu()
936           
937        # PDR / Background
938        self.BackMenu = wx.MenuBar()
939        self.PrefillDataMenu(self.BackMenu,helpType='Background')
940        self.BackEdit = wx.Menu(title='')
941        self.BackMenu.Append(menu=self.BackEdit, title='File')
942        self.BackEdit.Append(id=wxID_BACKCOPY, kind=wx.ITEM_NORMAL,text='Copy',
943            help='Copy background parameters to other histograms')
944        self.BackEdit.Append(id=wxID_BACKFLAGCOPY, kind=wx.ITEM_NORMAL,text='Copy flags',
945            help='Copy background refinement flags to other histograms')
946        self.PostfillDataMenu()
947           
948        # PDR / Instrument Parameters
949        self.InstMenu = wx.MenuBar()
950        self.PrefillDataMenu(self.InstMenu,helpType='Instrument Parameters')
951        self.InstEdit = wx.Menu(title='')
952        self.InstMenu.Append(menu=self.InstEdit, title='Operations')
953        self.InstEdit.Append(help='Reset instrument profile parameters to default', 
954            id=wxID_INSTLOAD, kind=wx.ITEM_NORMAL,text='Load profile...')
955        self.InstEdit.Append(help='Load instrument profile parameters from file', 
956            id=wxID_INSTSAVE, kind=wx.ITEM_NORMAL,text='Save profile...')
957        self.InstEdit.Append(help='Save instrument profile parameters to file', 
958            id=wxID_INSTPRMRESET, kind=wx.ITEM_NORMAL,text='Reset profile')
959        self.InstEdit.Append(help='Copy instrument profile parameters to other histograms', 
960            id=wxID_INSTCOPY, kind=wx.ITEM_NORMAL,text='Copy')
961        self.InstEdit.Append(id=wxID_INSTFLAGCOPY, kind=wx.ITEM_NORMAL,text='Copy flags',
962            help='Copy instrument parameter refinement flags to other histograms')
963#        self.InstEdit.Append(help='Change radiation type (Ka12 - synch)',
964#            id=wxID_CHANGEWAVETYPE, kind=wx.ITEM_NORMAL,text='Change radiation')
965        self.PostfillDataMenu()
966       
967        # PDR / Sample Parameters
968        self.SampleMenu = wx.MenuBar()
969        self.PrefillDataMenu(self.SampleMenu,helpType='Sample Parameters')
970        self.SampleEdit = wx.Menu(title='')
971        self.SampleMenu.Append(menu=self.SampleEdit, title='File')
972        self.SampleEdit.Append(id=wxID_SAMPLELOAD, kind=wx.ITEM_NORMAL,text='Load',
973            help='Load sample parameters from file')
974        self.SampleEdit.Append(id=wxID_SAMPLESAVE, kind=wx.ITEM_NORMAL,text='Save',
975            help='Save sample parameters to file')
976        self.SampleEdit.Append(id=wxID_SAMPLECOPY, kind=wx.ITEM_NORMAL,text='Copy',
977            help='Copy refinable sample parameters to other histograms')
978        self.SampleEdit.Append(id=wxID_SAMPLEFLAGCOPY, kind=wx.ITEM_NORMAL,text='Copy flags',
979            help='Copy sample parameter refinement flags to other histograms')
980        self.PostfillDataMenu()
981
982        # PDR / Peak List
983        self.PeakMenu = wx.MenuBar()
984        self.PrefillDataMenu(self.PeakMenu,helpType='Peak List')
985        self.PeakEdit = wx.Menu(title='')
986        self.PeakMenu.Append(menu=self.PeakEdit, title='Peak Fitting')
987        self.AutoSearch = self.PeakEdit.Append(help='Automatic peak search', 
988            id=wxID_AUTOSEARCH, kind=wx.ITEM_NORMAL,text='Auto search')
989        self.UnDo = self.PeakEdit.Append(help='Undo last least squares refinement', 
990            id=wxID_UNDO, kind=wx.ITEM_NORMAL,text='UnDo')
991        self.PeakFit = self.PeakEdit.Append(id=wxID_LSQPEAKFIT, kind=wx.ITEM_NORMAL,text='LSQ PeakFit', 
992            help='Peak fitting via least-squares' )
993        self.PFOneCycle = self.PeakEdit.Append(id=wxID_LSQONECYCLE, kind=wx.ITEM_NORMAL,text='LSQ one cycle', 
994            help='One cycle of Peak fitting via least-squares' )
995        self.PeakEdit.Append(id=wxID_RESETSIGGAM, kind=wx.ITEM_NORMAL, 
996            text='Reset sig and gam',help='Reset sigma and gamma to global fit' )
997        self.PeakEdit.Append(id=wxID_CLEARPEAKS, kind=wx.ITEM_NORMAL,text='Clear peaks', 
998            help='Clear the peak list' )
999        self.PostfillDataMenu()
1000        self.UnDo.Enable(False)
1001        self.PeakFit.Enable(False)
1002        self.PFOneCycle.Enable(False)
1003       
1004        # PDR / Index Peak List
1005        self.IndPeaksMenu = wx.MenuBar()
1006        self.PrefillDataMenu(self.IndPeaksMenu,helpType='Index Peak List')
1007        self.IndPeaksEdit = wx.Menu(title='')
1008        self.IndPeaksMenu.Append(menu=self.IndPeaksEdit,title='Operations')
1009        self.IndPeaksEdit.Append(help='Load/Reload index peaks from peak list',id=wxID_INDXRELOAD, 
1010            kind=wx.ITEM_NORMAL,text='Load/Reload')
1011        self.PostfillDataMenu()
1012       
1013        # PDR / Unit Cells List
1014        self.IndexMenu = wx.MenuBar()
1015        self.PrefillDataMenu(self.IndexMenu,helpType='Unit Cells List')
1016        self.IndexEdit = wx.Menu(title='')
1017        self.IndexMenu.Append(menu=self.IndexEdit, title='Cell Index/Refine')
1018        self.IndexPeaks = self.IndexEdit.Append(help='', id=wxID_INDEXPEAKS, kind=wx.ITEM_NORMAL,
1019            text='Index Cell')
1020        self.CopyCell = self.IndexEdit.Append( id=wxID_COPYCELL, kind=wx.ITEM_NORMAL,text='Copy Cell', 
1021            help='Copy selected unit cell from indexing to cell refinement fields')
1022        self.RefineCell = self.IndexEdit.Append( id=wxID_REFINECELL, kind=wx.ITEM_NORMAL, 
1023            text='Refine Cell',help='Refine unit cell parameters from indexed peaks')
1024        self.MakeNewPhase = self.IndexEdit.Append( id=wxID_MAKENEWPHASE, kind=wx.ITEM_NORMAL,
1025            text='Make new phase',help='Make new phase from selected unit cell')
1026        self.PostfillDataMenu()
1027        self.IndexPeaks.Enable(False)
1028        self.CopyCell.Enable(False)
1029        self.RefineCell.Enable(False)
1030        self.MakeNewPhase.Enable(False)
1031       
1032        # PDR / Reflection Lists
1033        self.ReflMenu = wx.MenuBar()
1034        self.PrefillDataMenu(self.ReflMenu,helpType='Reflection List')
1035        self.ReflEdit = wx.Menu(title='')
1036        self.ReflMenu.Append(menu=self.ReflEdit, title='Reflection List')
1037        self.SelectPhase = self.ReflEdit.Append(help='Select phase for reflection list',id=wxID_SELECTPHASE, 
1038            kind=wx.ITEM_NORMAL,text='Select phase')
1039        self.PostfillDataMenu()
1040       
1041        # IMG / Image Controls
1042        self.ImageMenu = wx.MenuBar()
1043        self.PrefillDataMenu(self.ImageMenu,helpType='Image Controls')
1044        self.ImageEdit = wx.Menu(title='')
1045        self.ImageMenu.Append(menu=self.ImageEdit, title='Operations')
1046        self.ImageEdit.Append(help='Calibrate detector by fitting to calibrant lines', 
1047            id=wxID_IMCALIBRATE, kind=wx.ITEM_NORMAL,text='Calibrate')
1048        self.ImageEdit.Append(help='Recalibrate detector by fitting to calibrant lines', 
1049            id=wxID_IMRECALIBRATE, kind=wx.ITEM_NORMAL,text='Recalibrate')
1050        self.ImageEdit.Append(help='Clear calibration data points and rings',id=wxID_IMCLEARCALIB, 
1051            kind=wx.ITEM_NORMAL,text='Clear calibration')
1052        self.ImageEdit.Append(help='Integrate selected image',id=wxID_IMINTEGRATE, 
1053            kind=wx.ITEM_NORMAL,text='Integrate')
1054        self.ImageEdit.Append(help='Integrate all images selected from list',id=wxID_INTEGRATEALL,
1055            kind=wx.ITEM_NORMAL,text='Integrate all')
1056        self.ImageEdit.Append(help='Copy image controls to other images', 
1057            id=wxID_IMCOPYCONTROLS, kind=wx.ITEM_NORMAL,text='Copy Controls')
1058        self.ImageEdit.Append(help='Save image controls to file', 
1059            id=wxID_IMSAVECONTROLS, kind=wx.ITEM_NORMAL,text='Save Controls')
1060        self.ImageEdit.Append(help='Load image controls from file', 
1061            id=wxID_IMLOADCONTROLS, kind=wx.ITEM_NORMAL,text='Load Controls')
1062        self.PostfillDataMenu()
1063           
1064        # IMG / Masks
1065        self.MaskMenu = wx.MenuBar()
1066        self.PrefillDataMenu(self.MaskMenu,helpType='Image Masks')
1067        self.MaskEdit = wx.Menu(title='')
1068        self.MaskMenu.Append(menu=self.MaskEdit, title='Operations')
1069        self.MaskEdit.Append(help='Copy mask to other images', 
1070            id=wxID_MASKCOPY, kind=wx.ITEM_NORMAL,text='Copy mask')
1071        self.MaskEdit.Append(help='Save mask to file', 
1072            id=wxID_MASKSAVE, kind=wx.ITEM_NORMAL,text='Save mask')
1073        self.MaskEdit.Append(help='Load mask from file', 
1074            id=wxID_MASKLOAD, kind=wx.ITEM_NORMAL,text='Load mask')
1075        self.PostfillDataMenu()
1076           
1077        # IMG / Stress/Strain
1078        self.StrStaMenu = wx.MenuBar()
1079        self.PrefillDataMenu(self.StrStaMenu,helpType='Stress/Strain')
1080        self.StrStaEdit = wx.Menu(title='')
1081        self.StrStaMenu.Append(menu=self.StrStaEdit, title='Operations')
1082        self.StrStaEdit.Append(help='Append d-zero for one ring', 
1083            id=wxID_APPENDDZERO, kind=wx.ITEM_NORMAL,text='Append d-zero')
1084        self.StrStaEdit.Append(help='Fit stress/strain data', 
1085            id=wxID_STRSTAFIT, kind=wx.ITEM_NORMAL,text='Fit stress/strain')
1086        self.StrStaEdit.Append(help='Copy stress/strain data to other images', 
1087            id=wxID_STRSTACOPY, kind=wx.ITEM_NORMAL,text='Copy stress/strain')
1088        self.StrStaEdit.Append(help='Save stress/strain data to file', 
1089            id=wxID_STRSTASAVE, kind=wx.ITEM_NORMAL,text='Save stress/strain')
1090        self.StrStaEdit.Append(help='Load stress/strain data from file', 
1091            id=wxID_STRSTALOAD, kind=wx.ITEM_NORMAL,text='Load stress/strain')
1092        self.PostfillDataMenu()
1093           
1094        # PDF / PDF Controls
1095        self.PDFMenu = wx.MenuBar()
1096        self.PrefillDataMenu(self.PDFMenu,helpType='PDF Controls')
1097        self.PDFEdit = wx.Menu(title='')
1098        self.PDFMenu.Append(menu=self.PDFEdit, title='PDF Controls')
1099        self.PDFEdit.Append(help='Add element to sample composition',id=wxID_PDFADDELEMENT, kind=wx.ITEM_NORMAL,
1100            text='Add element')
1101        self.PDFEdit.Append(help='Delete element from sample composition',id=wxID_PDFDELELEMENT, kind=wx.ITEM_NORMAL,
1102            text='Delete element')
1103        self.PDFEdit.Append(help='Copy PDF controls', id=wxID_PDFCOPYCONTROLS, kind=wx.ITEM_NORMAL,
1104            text='Copy controls')
1105        #        self.PDFEdit.Append(help='Load PDF controls from file',id=wxID_PDFLOADCONTROLS, kind=wx.ITEM_NORMAL,
1106        #            text='Load Controls')
1107        #        self.PDFEdit.Append(help='Save PDF controls to file', id=wxID_PDFSAVECONTROLS, kind=wx.ITEM_NORMAL,
1108        #            text='Save controls')
1109        self.PDFEdit.Append(help='Compute PDF', id=wxID_PDFCOMPUTE, kind=wx.ITEM_NORMAL,
1110            text='Compute PDF')
1111        self.PDFEdit.Append(help='Compute all PDFs', id=wxID_PDFCOMPUTEALL, kind=wx.ITEM_NORMAL,
1112            text='Compute all PDFs')
1113        self.PostfillDataMenu()
1114           
1115        # Phase / General tab
1116        self.DataGeneral = wx.MenuBar()
1117        self.PrefillDataMenu(self.DataGeneral,helpType='General', helpLbl='Phase/General')
1118        self.GeneralCalc = wx.Menu(title='')
1119        self.DataGeneral.Append(menu=self.GeneralCalc,title='Compute')
1120        self.GeneralCalc.Append(help='Compute Fourier map',id=wxID_FOURCALC, kind=wx.ITEM_NORMAL,
1121            text='Fourier map')
1122        self.GeneralCalc.Append(help='Search Fourier map',id=wxID_FOURSEARCH, kind=wx.ITEM_NORMAL,
1123            text='Search map')
1124        self.GeneralCalc.Append(help='Run charge flipping',id=wxID_CHARGEFLIP, kind=wx.ITEM_NORMAL,
1125            text='Charge flipping')
1126        self.GeneralCalc.Append(help='Clear map',id=wxID_FOURCLEAR, kind=wx.ITEM_NORMAL,
1127            text='Clear map')
1128        self.PostfillDataMenu()
1129       
1130        # Phase / Data tab
1131        self.DataMenu = wx.MenuBar()
1132        self.PrefillDataMenu(self.DataMenu,helpType='Data', helpLbl='Phase/Data')
1133        self.DataEdit = wx.Menu(title='')
1134        self.DataMenu.Append(menu=self.DataEdit, title='Edit')
1135        self.DataEdit.Append(id=wxID_PWDRADD, kind=wx.ITEM_NORMAL,text='Add powder histograms',
1136            help='Select new powder histograms to be used for this phase')
1137        self.DataEdit.Append(id=wxID_HKLFADD, kind=wx.ITEM_NORMAL,text='Add single crystal histograms',
1138            help='Select new single crystal histograms to be used for this phase')
1139        self.DataEdit.Append(id=wxID_DATADELETE, kind=wx.ITEM_NORMAL,text='Delete histograms',
1140            help='Delete histograms from use for this phase')
1141        self.PostfillDataMenu()
1142           
1143        # Phase / Atoms tab
1144        self.AtomsMenu = wx.MenuBar()
1145        self.PrefillDataMenu(self.AtomsMenu,helpType='Atoms')
1146        self.AtomEdit = wx.Menu(title='')
1147        self.AtomCompute = wx.Menu(title='')
1148        self.AtomsMenu.Append(menu=self.AtomEdit, title='Edit')
1149        self.AtomsMenu.Append(menu=self.AtomCompute, title='Compute')
1150        self.AtomEdit.Append(id=wxID_ATOMSEDITADD, kind=wx.ITEM_NORMAL,text='Append atom',
1151            help='Appended as an H atom')
1152        self.AtomEdit.Append(id=wxID_ATOMSVIEWADD, kind=wx.ITEM_NORMAL,text='Append view point',
1153            help='Appended as an H atom')
1154        self.AtomEdit.Append(id=wxID_RBAPPEND, kind=wx.ITEM_NORMAL,text='Append rigid body',
1155            help='Append atoms for rigid body')
1156        self.AtomEdit.Append(id=wxID_ATOMSEDITINSERT, kind=wx.ITEM_NORMAL,text='Insert atom',
1157            help='Select atom row to insert before; inserted as an H atom')
1158        self.AtomEdit.Append(id=wxID_ATOMVIEWINSERT, kind=wx.ITEM_NORMAL,text='Insert view point',
1159            help='Select atom row to insert before; inserted as an H atom')
1160        self.AtomEdit.Append(id=wxID_ATOMMOVE, kind=wx.ITEM_NORMAL,text='Move atom to view point',
1161            help='Select single atom to move')
1162        self.AtomEdit.Append(id=wxID_ATOMSEDITDELETE, kind=wx.ITEM_NORMAL,text='Delete atom',
1163            help='Select atoms to delete first')
1164        self.AtomEdit.Append(id=wxID_ATOMSREFINE, kind=wx.ITEM_NORMAL,text='Set atom refinement flags',
1165            help='Select atoms to refine first')
1166        self.AtomEdit.Append(id=wxID_ATOMSMODIFY, kind=wx.ITEM_NORMAL,text='Modify atom parameters',
1167            help='Select atoms to modify first')
1168        self.AtomEdit.Append(id=wxID_ATOMSTRANSFORM, kind=wx.ITEM_NORMAL,text='Transform atoms',
1169            help='Select atoms to transform first')
1170        self.AtomEdit.Append(id=wxID_RELOADDRAWATOMS, kind=wx.ITEM_NORMAL,text='Reload draw atoms',
1171            help='Reload atom drawing list')
1172        submenu = wx.Menu()
1173        self.AtomEdit.AppendMenu(wx.ID_ANY, 'Reimport atoms', submenu, 
1174            help='Reimport atoms from file; sequence must match')
1175        # setup a cascade menu for the formats that have been defined
1176        self.ReImportMenuId = {}  # points to readers for each menu entry
1177        for reader in self.G2frame.ImportPhaseReaderlist:
1178            item = submenu.Append(
1179                wx.ID_ANY,help=reader.longFormatName,
1180                kind=wx.ITEM_NORMAL,text='reimport coordinates from '+reader.formatName+' file')
1181            self.ReImportMenuId[item.GetId()] = reader
1182        item = submenu.Append(
1183            wx.ID_ANY,
1184            help='Reimport coordinates, try to determine format from file',
1185            kind=wx.ITEM_NORMAL,
1186            text='guess format from file')
1187        self.ReImportMenuId[item.GetId()] = None # try all readers
1188
1189        self.AtomCompute.Append(id=wxID_ATOMSDISAGL, kind=wx.ITEM_NORMAL,text='Distances && Angles',
1190            help='Compute distances & angles for selected atoms')
1191        self.PostfillDataMenu()
1192                 
1193        # Phase / Draw Options tab
1194        self.DataDrawOptions = wx.MenuBar()
1195        self.PrefillDataMenu(self.DataDrawOptions,helpType='Draw Options', helpLbl='Phase/Draw Options',empty=True)
1196        self.PostfillDataMenu(empty=True)
1197       
1198        # Phase / Draw Atoms tab
1199        self.DrawAtomsMenu = wx.MenuBar()
1200        self.PrefillDataMenu(self.DrawAtomsMenu,helpType='Draw Atoms')
1201        self.DrawAtomEdit = wx.Menu(title='')
1202        self.DrawAtomCompute = wx.Menu(title='')
1203        self.DrawAtomRestraint = wx.Menu(title='')
1204        self.DrawAtomRigidBody = wx.Menu(title='')
1205        self.DrawAtomsMenu.Append(menu=self.DrawAtomEdit, title='Edit')
1206        self.DrawAtomsMenu.Append(menu=self.DrawAtomCompute,title='Compute')
1207        self.DrawAtomsMenu.Append(menu=self.DrawAtomRestraint, title='Restraints')
1208        self.DrawAtomsMenu.Append(menu=self.DrawAtomRigidBody, title='Rigid body')
1209        self.DrawAtomEdit.Append(id=wxID_DRAWATOMSTYLE, kind=wx.ITEM_NORMAL,text='Atom style',
1210            help='Select atoms first')
1211        self.DrawAtomEdit.Append(id=wxID_DRAWATOMLABEL, kind=wx.ITEM_NORMAL,text='Atom label',
1212            help='Select atoms first')
1213        self.DrawAtomEdit.Append(id=wxID_DRAWATOMCOLOR, kind=wx.ITEM_NORMAL,text='Atom color',
1214            help='Select atoms first')
1215        self.DrawAtomEdit.Append(id=wxID_DRAWATOMRESETCOLOR, kind=wx.ITEM_NORMAL,text='Reset atom colors',
1216            help='Resets all atom colors to defaults')
1217        self.DrawAtomEdit.Append(id=wxID_DRAWVIEWPOINT, kind=wx.ITEM_NORMAL,text='View point',
1218            help='View point is 1st atom selected')
1219        self.DrawAtomEdit.Append(id=wxID_DRAWADDEQUIV, kind=wx.ITEM_NORMAL,text='Add atoms',
1220            help='Add symmetry & cell equivalents to drawing set from selected atoms')
1221        self.DrawAtomEdit.Append(id=wxID_DRAWTRANSFORM, kind=wx.ITEM_NORMAL,text='Transform atoms',
1222            help='Transform selected atoms by symmetry & cell translations')
1223        self.DrawAtomEdit.Append(id=wxID_DRAWFILLCOORD, kind=wx.ITEM_NORMAL,text='Fill CN-sphere',
1224            help='Fill coordination sphere for selected atoms')           
1225        self.DrawAtomEdit.Append(id=wxID_DRAWFILLCELL, kind=wx.ITEM_NORMAL,text='Fill unit cell',
1226            help='Fill unit cell with selected atoms')
1227        self.DrawAtomEdit.Append(id=wxID_DRAWDELETE, kind=wx.ITEM_NORMAL,text='Delete atoms',
1228            help='Delete atoms from drawing set')
1229        self.DrawAtomCompute.Append(id=wxID_DRAWDISTVP, kind=wx.ITEM_NORMAL,text='View pt. dist.',
1230            help='Compute distance of selected atoms from view point')   
1231        self.DrawAtomCompute.Append(id=wxID_DRAWDISAGLTOR, kind=wx.ITEM_NORMAL,text='Dist. Ang. Tors.',
1232            help='Compute distance, angle or torsion for 2-4 selected atoms')   
1233        self.DrawAtomCompute.Append(id=wxID_DRAWPLANE, kind=wx.ITEM_NORMAL,text='Best plane',
1234            help='Compute best plane for 4+ selected atoms')   
1235        self.DrawAtomRestraint.Append(id=wxID_DRAWRESTRBOND, kind=wx.ITEM_NORMAL,text='Add bond restraint',
1236            help='Add bond restraint for selected atoms (2)')
1237        self.DrawAtomRestraint.Append(id=wxID_DRAWRESTRANGLE, kind=wx.ITEM_NORMAL,text='Add angle restraint',
1238            help='Add angle restraint for selected atoms (3: one end 1st)')
1239        self.DrawAtomRestraint.Append(id=wxID_DRAWRESTRPLANE, kind=wx.ITEM_NORMAL,text='Add plane restraint',
1240            help='Add plane restraint for selected atoms (4+)')
1241        self.DrawAtomRestraint.Append(id=wxID_DRAWRESTRCHIRAL, kind=wx.ITEM_NORMAL,text='Add chiral restraint',
1242            help='Add chiral restraint for selected atoms (4: center atom 1st)')
1243        self.DrawAtomRigidBody.Append(id=wxID_DRAWDEFINERB, kind=wx.ITEM_NORMAL,text='Define rigid body',
1244            help='Define rigid body with selected atoms')
1245        self.PostfillDataMenu()
1246           
1247        # Phase / Texture tab
1248        self.TextureMenu = wx.MenuBar()
1249        self.PrefillDataMenu(self.TextureMenu,helpType='Texture')
1250        self.TextureEdit = wx.Menu(title='')
1251        self.TextureMenu.Append(menu=self.TextureEdit, title='Texture')
1252        self.TextureEdit.Append(id=wxID_REFINETEXTURE, kind=wx.ITEM_NORMAL,text='Refine texture', 
1253            help='Refine the texture coefficients from sequential Pawley results')
1254        self.TextureEdit.Append(id=wxID_CLEARTEXTURE, kind=wx.ITEM_NORMAL,text='Clear texture', 
1255            help='Clear the texture coefficients' )
1256        self.PostfillDataMenu()
1257           
1258        # Phase / Pawley tab
1259        self.PawleyMenu = wx.MenuBar()
1260        self.PrefillDataMenu(self.PawleyMenu,helpType='Pawley')
1261        self.PawleyEdit = wx.Menu(title='')
1262        self.PawleyMenu.Append(menu=self.PawleyEdit,title='Operations')
1263        self.PawleyEdit.Append(id=wxID_PAWLEYLOAD, kind=wx.ITEM_NORMAL,text='Pawley create',
1264            help='Initialize Pawley reflection list')
1265        self.PawleyEdit.Append(id=wxID_PAWLEYESTIMATE, kind=wx.ITEM_NORMAL,text='Pawley estimate',
1266            help='Estimate initial Pawley intensities')
1267        self.PawleyEdit.Append(id=wxID_PAWLEYUPDATE, kind=wx.ITEM_NORMAL,text='Pawley update',
1268            help='Update Pawley intensities with abs(Fobs) from reflection list')
1269#        self.PawleyEdit.Append(id=wxID_PAWLEYDELETE, kind=wx.ITEM_NORMAL,text='Pawley delete',
1270#            help='Delete selected Pawley reflection')
1271        self.PostfillDataMenu()
1272           
1273        # Phase / Map peaks tab
1274        self.MapPeaksMenu = wx.MenuBar()
1275        self.PrefillDataMenu(self.MapPeaksMenu,helpType='Map peaks')
1276        self.MapPeaksEdit = wx.Menu(title='')
1277        self.MapPeaksMenu.Append(menu=self.MapPeaksEdit, title='Map peaks')
1278        self.MapPeaksEdit.Append(id=wxID_PEAKSMOVE, kind=wx.ITEM_NORMAL,text='Move peaks', 
1279            help='Move selected peaks to atom list')
1280        self.MapPeaksEdit.Append(id=wxID_PEAKSVIEWPT, kind=wx.ITEM_NORMAL,text='View point',
1281            help='View point is 1st peak selected')
1282        self.MapPeaksEdit.Append(id=wxID_PEAKSDISTVP, kind=wx.ITEM_NORMAL,text='View pt. dist.',
1283            help='Compute distance of selected peaks from view point')   
1284        self.MapPeaksEdit.Append(id=wxID_SHOWBONDS, kind=wx.ITEM_NORMAL,text='Hide bonds',
1285            help='Hide or show bonds between peak positions')   
1286        self.MapPeaksEdit.Append(id=wxID_PEAKSDA, kind=wx.ITEM_NORMAL,text='Calc dist/ang', 
1287            help='Calculate distance or angle for selection')
1288        self.MapPeaksEdit.Append(id=wxID_FINDEQVPEAKS, kind=wx.ITEM_NORMAL,text='Equivalent peaks', 
1289            help='Find equivalent peaks')
1290        self.MapPeaksEdit.Append(id=wxID_PEAKSUNIQUE, kind=wx.ITEM_NORMAL,text='Unique peaks', 
1291            help='Select unique set')
1292        self.MapPeaksEdit.Append(id=wxID_PEAKSDELETE, kind=wx.ITEM_NORMAL,text='Delete peaks', 
1293            help='Delete selected peaks')
1294        self.MapPeaksEdit.Append(id=wxID_PEAKSCLEAR, kind=wx.ITEM_NORMAL,text='Clear peaks', 
1295            help='Clear the map peak list')
1296        self.PostfillDataMenu()
1297
1298        # Phase / Rigid bodies tab
1299        self.RigidBodiesMenu = wx.MenuBar()
1300        self.PrefillDataMenu(self.RigidBodiesMenu,helpType='Rigid bodies')
1301        self.RigidBodiesEdit = wx.Menu(title='')
1302        self.RigidBodiesMenu.Append(menu=self.RigidBodiesEdit, title='Edit')
1303        self.RigidBodiesEdit.Append(id=wxID_ASSIGNATMS2RB, kind=wx.ITEM_NORMAL,text='Assign atoms to rigid body',
1304            help='Select & position rigid body in structure of existing atoms')
1305        self.RigidBodiesEdit.Append(id=wxID_AUTOFINDRESRB, kind=wx.ITEM_NORMAL,text='Auto find residues',
1306            help='Auto find of residue RBs in macromolecule')
1307        self.RigidBodiesEdit.Append(id=wxID_COPYRBPARMS, kind=wx.ITEM_NORMAL,text='Copy rigid body parms',
1308            help='Copy rigid body location & TLS parameters')
1309        self.RigidBodiesEdit.Append(id=wxID_GLOBALRESREFINE, kind=wx.ITEM_NORMAL,text='Global residue refine',
1310            help='Global setting of residue RB refinement flags')
1311        self.RigidBodiesEdit.Append(id=wxID_RBREMOVEALL, kind=wx.ITEM_NORMAL,text='Remove all rigid bodies',
1312            help='Remove all rigid body assignment for atoms')
1313        self.PostfillDataMenu()
1314    # end of GSAS-II menu definitions
1315       
1316    def _init_ctrls(self, parent,name=None,size=None,pos=None):
1317        wx.Frame.__init__(self,parent=parent,
1318            style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX | wx.FRAME_FLOAT_ON_PARENT ,
1319            size=size,pos=pos,title='GSAS-II data display')
1320        self._init_menus()
1321        if name:
1322            self.SetLabel(name)
1323        self.Show()
1324       
1325    def __init__(self,parent,frame,data=None,name=None, size=None,pos=None):
1326        self.G2frame = frame
1327        self._init_ctrls(parent,name,size,pos)
1328        self.data = data
1329        clientSize = wx.ClientDisplayRect()
1330        Size = self.GetSize()
1331        xPos = clientSize[2]-Size[0]
1332        self.SetPosition(wx.Point(xPos,clientSize[1]+250))
1333        self.AtomGrid = []
1334        self.selectedRow = 0
1335       
1336    def setSizePosLeft(self,Width):
1337        clientSize = wx.ClientDisplayRect()
1338        Width[1] = min(Width[1],clientSize[2]-300)
1339        Width[0] = max(Width[0],300)
1340        self.SetSize(Width)
1341#        self.SetPosition(wx.Point(clientSize[2]-Width[0],clientSize[1]+250))
1342       
1343    def Clear(self):
1344        self.ClearBackground()
1345        self.DestroyChildren()
1346                   
1347################################################################################
1348#####  GSNotebook
1349################################################################################           
1350       
1351class GSNoteBook(wx.aui.AuiNotebook):
1352    '''Notebook used in various locations; implemented with wx.aui extension
1353    '''
1354    def __init__(self, parent, name='',size = None):
1355        wx.aui.AuiNotebook.__init__(self, parent, -1,
1356                                    style=wx.aui.AUI_NB_TOP |
1357                                    wx.aui.AUI_NB_SCROLL_BUTTONS)
1358        if size: self.SetSize(size)
1359                                                     
1360    def Clear(self):       
1361        GSNoteBook.DeleteAllPages(self)
1362       
1363    def FindPage(self,name):
1364        numPage = self.GetPageCount()
1365        for page in range(numPage):
1366            if self.GetPageText(page) == name:
1367                return page
1368
1369    def ChangeSelection(self,page):
1370        # in the wx.Notebook ChangeSelection is like SetSelection, but it
1371        # does not invoke the event related to pressing the tab button
1372        # I don't see a way to do that in aui.
1373        oldPage = self.GetSelection()
1374        self.SetSelection(page)
1375        return oldPage
1376
1377    # def __getattribute__(self,name):
1378    #     '''This method provides a way to print out a message every time
1379    #     that a method in a class is called -- to see what all the calls
1380    #     might be, or where they might be coming from.
1381    #     Cute trick for debugging!
1382    #     '''
1383    #     attr = object.__getattribute__(self, name)
1384    #     if hasattr(attr, '__call__'):
1385    #         def newfunc(*args, **kwargs):
1386    #             print('GSauiNoteBook calling %s' %attr.__name__)
1387    #             result = attr(*args, **kwargs)
1388    #             return result
1389    #         return newfunc
1390    #     else:
1391    #         return attr
1392           
1393################################################################################
1394#####  GSGrid
1395################################################################################           
1396       
1397class GSGrid(wg.Grid):
1398    '''Basic wx.Grid implementation
1399    '''
1400    def __init__(self, parent, name=''):
1401        wg.Grid.__init__(self,parent,-1,name=name)                   
1402        #self.SetSize(parent.GetClientSize())
1403        # above removed to speed drawing of initial grid
1404        # does not appear to be needed
1405           
1406    def Clear(self):
1407        wg.Grid.ClearGrid(self)
1408       
1409    def SetCellStyle(self,r,c,color="white",readonly=True):
1410        self.SetCellBackgroundColour(r,c,color)
1411        self.SetReadOnly(r,c,isReadOnly=readonly)
1412       
1413    def GetSelection(self):
1414        #this is to satisfy structure drawing stuff in G2plt when focus changes
1415        return None
1416                                               
1417################################################################################
1418#####  Table
1419################################################################################           
1420       
1421class Table(wg.PyGridTableBase):
1422    '''Basic data table for use with GSgrid
1423    '''
1424    def __init__(self, data=[], rowLabels=None, colLabels=None, types = None):
1425        wg.PyGridTableBase.__init__(self)
1426        self.colLabels = colLabels
1427        self.rowLabels = rowLabels
1428        self.dataTypes = types
1429        self.data = data
1430       
1431    def AppendRows(self, numRows=1):
1432        self.data.append([])
1433        return True
1434       
1435    def CanGetValueAs(self, row, col, typeName):
1436        if self.dataTypes:
1437            colType = self.dataTypes[col].split(':')[0]
1438            if typeName == colType:
1439                return True
1440            else:
1441                return False
1442        else:
1443            return False
1444
1445    def CanSetValueAs(self, row, col, typeName):
1446        return self.CanGetValueAs(row, col, typeName)
1447
1448    def DeleteRow(self,pos):
1449        data = self.GetData()
1450        self.SetData([])
1451        new = []
1452        for irow,row in enumerate(data):
1453            if irow <> pos:
1454                new.append(row)
1455        self.SetData(new)
1456       
1457    def GetColLabelValue(self, col):
1458        if self.colLabels:
1459            return self.colLabels[col]
1460           
1461    def GetData(self):
1462        data = []
1463        for row in range(self.GetNumberRows()):
1464            data.append(self.GetRowValues(row))
1465        return data
1466       
1467    def GetNumberCols(self):
1468        try:
1469            return len(self.colLabels)
1470        except TypeError:
1471            return None
1472       
1473    def GetNumberRows(self):
1474        return len(self.data)
1475       
1476    def GetRowLabelValue(self, row):
1477        if self.rowLabels:
1478            return self.rowLabels[row]
1479       
1480    def GetColValues(self, col):
1481        data = []
1482        for row in range(self.GetNumberRows()):
1483            data.append(self.GetValue(row, col))
1484        return data
1485       
1486    def GetRowValues(self, row):
1487        data = []
1488        for col in range(self.GetNumberCols()):
1489            data.append(self.GetValue(row, col))
1490        return data
1491       
1492    def GetTypeName(self, row, col):
1493        try:
1494            return self.dataTypes[col]
1495        except TypeError:
1496            return None
1497
1498    def GetValue(self, row, col):
1499        try:
1500            return self.data[row][col]
1501        except IndexError:
1502            return None
1503           
1504    def InsertRows(self, pos, rows):
1505        for row in range(rows):
1506            self.data.insert(pos,[])
1507            pos += 1
1508       
1509    def IsEmptyCell(self,row,col):
1510        try:
1511            return not self.data[row][col]
1512        except IndexError:
1513            return True
1514       
1515    def OnKeyPress(self, event):
1516        dellist = self.GetSelectedRows()
1517        if event.GetKeyCode() == wx.WXK_DELETE and dellist:
1518            grid = self.GetView()
1519            for i in dellist: grid.DeleteRow(i)
1520               
1521    def SetColLabelValue(self, col, label):
1522        numcols = self.GetNumberCols()
1523        if col > numcols-1:
1524            self.colLabels.append(label)
1525        else:
1526            self.colLabels[col]=label
1527       
1528    def SetData(self,data):
1529        for row in range(len(data)):
1530            self.SetRowValues(row,data[row])
1531               
1532    def SetRowLabelValue(self, row, label):
1533        self.rowLabels[row]=label
1534           
1535    def SetRowValues(self,row,data):
1536        self.data[row] = data
1537           
1538    def SetValue(self, row, col, value):
1539        def innerSetValue(row, col, value):
1540            try:
1541                self.data[row][col] = value
1542            except TypeError:
1543                return
1544            except IndexError:
1545                print row,col,value
1546                # add a new row
1547                if row > self.GetNumberRows():
1548                    self.data.append([''] * self.GetNumberCols())
1549                elif col > self.GetNumberCols():
1550                    for row in range(self.GetNumberRows):
1551                        self.data[row].append('')
1552                print self.data
1553                self.data[row][col] = value
1554        innerSetValue(row, col, value)
1555       
1556################################################################################
1557#### Help
1558################################################################################
1559
1560def ShowHelp(helpType,frame):
1561    '''Called to bring up a web page for documentation.'''
1562    global htmlFirstUse
1563    # look up a definition for help info from dict
1564    helplink = helpLocDict.get(helpType)
1565    if helplink is None:
1566        # no defined link to use, create a default based on key
1567        helplink = 'gsasII.html#'+helpType.replace(' ','_')
1568    helplink = os.path.join(path2GSAS2,'help',helplink)
1569    if helpMode == 'internal':
1570        try:
1571            htmlPanel.LoadFile(helplink)
1572            htmlFrame.Raise()
1573        except:
1574            htmlFrame = wx.Frame(frame, -1, size=(610, 510))
1575            htmlFrame.Show(True)
1576            htmlFrame.SetTitle("HTML Window") # N.B. reset later in LoadFile
1577            htmlPanel = MyHtmlPanel(htmlFrame,-1)
1578            htmlPanel.LoadFile(helplink)
1579    else:
1580        pfx = "file://"
1581        if sys.platform.lower().startswith('win'):
1582            pfx = ''
1583        if htmlFirstUse:
1584            webbrowser.open_new(pfx+helplink)
1585            htmlFirstUse = False
1586        else:
1587            webbrowser.open(pfx+helplink, new=0, autoraise=True)
1588
1589################################################################################
1590#####  Notebook
1591################################################################################           
1592       
1593def UpdateNotebook(G2frame,data):
1594    '''Called when the data tree notebook entry is selected. Allows for
1595    editing of the text in that tree entry
1596    '''
1597    def OnNoteBook(event):
1598        data = G2frame.dataDisplay.GetValue()
1599        G2frame.PatternTree.SetItemPyData(GetPatternTreeItemId(G2frame,G2frame.root,'Notebook'),data)
1600                   
1601    if G2frame.dataDisplay:
1602        G2frame.dataDisplay.Destroy()
1603    G2frame.dataFrame.SetLabel('Notebook')
1604    G2frame.dataDisplay = wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
1605        style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER | wx.TE_DONTWRAP)
1606    G2frame.dataDisplay.Bind(wx.EVT_TEXT_ENTER,OnNoteBook)
1607    G2frame.dataDisplay.Bind(wx.EVT_KILL_FOCUS,OnNoteBook)
1608    for line in data:
1609        G2frame.dataDisplay.AppendText(line+"\n")
1610    G2frame.dataDisplay.AppendText('Notebook entry @ '+time.ctime()+"\n")
1611    G2frame.dataFrame.setSizePosLeft([400,250])
1612           
1613################################################################################
1614#####  Controls
1615################################################################################           
1616       
1617def UpdateControls(G2frame,data):
1618    '''Edit overall GSAS-II controls in main Controls data tree entry
1619    '''
1620    #patch
1621    if 'deriv type' not in data:
1622        data = {}
1623        data['deriv type'] = 'analytic Hessian'
1624        data['min dM/M'] = 0.0001
1625        data['shift factor'] = 1.
1626        data['max cyc'] = 3       
1627        data['F**2'] = True
1628        data['minF/sig'] = 0
1629    if 'shift factor' not in data:
1630        data['shift factor'] = 1.
1631    if 'max cyc' not in data:
1632        data['max cyc'] = 3
1633    if 'F**2' not in data:
1634        data['F**2'] = True
1635        data['minF/sig'] = 0
1636    #end patch
1637
1638    def SeqSizer():
1639       
1640        def OnSelectData(event):
1641            choices = ['All',]+GetPatternTreeDataNames(G2frame,['PWDR',])
1642            sel = []
1643            if 'Seq Data' in data:
1644                for item in data['Seq Data']:
1645                    sel.append(choices.index(item))
1646            names = []
1647            dlg = wx.MultiChoiceDialog(G2frame,'Select data:','Sequential refinement',choices)
1648            dlg.SetSelections(sel)
1649            if dlg.ShowModal() == wx.ID_OK:
1650                sel = dlg.GetSelections()
1651                for i in sel: names.append(choices[i])
1652                if 'All' in names:
1653                    names = choices[1:]
1654                data['Seq Data'] = names               
1655            dlg.Destroy()
1656            reverseSel.Enable(True)
1657           
1658        def OnReverse(event):
1659            data['Reverse Seq'] = reverseSel.GetValue()
1660                   
1661        seqSizer = wx.BoxSizer(wx.HORIZONTAL)
1662        seqSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Sequential Refinement Powder Data: '),0,wx.ALIGN_CENTER_VERTICAL)
1663        selSeqData = wx.Button(G2frame.dataDisplay,-1,label=' Select data')
1664        selSeqData.Bind(wx.EVT_BUTTON,OnSelectData)
1665        seqSizer.Add(selSeqData,0,wx.ALIGN_CENTER_VERTICAL)
1666        seqSizer.Add((5,0),0)
1667        reverseSel = wx.CheckBox(G2frame.dataDisplay,-1,label=' Reverse order?')
1668        reverseSel.Bind(wx.EVT_CHECKBOX,OnReverse)
1669        if 'Seq Data' not in data:
1670            reverseSel.Enable(False)
1671        if 'Reverse Seq' in data:
1672            reverseSel.SetValue(data['Reverse Seq'])
1673        seqSizer.Add(reverseSel,0,wx.ALIGN_CENTER_VERTICAL)
1674        return seqSizer
1675       
1676    def LSSizer():       
1677       
1678        def OnDerivType(event):
1679            data['deriv type'] = derivSel.GetValue()
1680            derivSel.SetValue(data['deriv type'])
1681            wx.CallAfter(UpdateControls,G2frame,data)
1682           
1683        def OnConvergence(event):
1684            try:
1685                value = max(1.e-9,min(1.0,float(Cnvrg.GetValue())))
1686            except ValueError:
1687                value = 0.0001
1688            data['min dM/M'] = value
1689            Cnvrg.SetValue('%.2g'%(value))
1690           
1691        def OnMaxCycles(event):
1692            data['max cyc'] = int(maxCyc.GetValue())
1693            maxCyc.SetValue(str(data['max cyc']))
1694                       
1695        def OnFactor(event):
1696            try:
1697                value = min(max(float(Factr.GetValue()),0.00001),100.)
1698            except ValueError:
1699                value = 1.0
1700            data['shift factor'] = value
1701            Factr.SetValue('%.5f'%(value))
1702           
1703        def OnFsqRef(event):
1704            data['F**2'] = fsqRef.GetValue()
1705       
1706        def OnMinSig(event):
1707            try:
1708                value = min(max(float(minSig.GetValue()),0.),5.)
1709            except ValueError:
1710                value = 1.0
1711            data['minF/sig'] = value
1712            minSig.SetValue('%.2f'%(value))
1713
1714        LSSizer = wx.FlexGridSizer(cols=4,vgap=5,hgap=5)
1715        LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Refinement derivatives: '),0,wx.ALIGN_CENTER_VERTICAL)
1716        Choice=['analytic Jacobian','numeric','analytic Hessian']
1717        derivSel = wx.ComboBox(parent=G2frame.dataDisplay,value=data['deriv type'],choices=Choice,
1718            style=wx.CB_READONLY|wx.CB_DROPDOWN)
1719        derivSel.SetValue(data['deriv type'])
1720        derivSel.Bind(wx.EVT_COMBOBOX, OnDerivType)
1721           
1722        LSSizer.Add(derivSel,0,wx.ALIGN_CENTER_VERTICAL)
1723        LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Min delta-M/M: '),0,wx.ALIGN_CENTER_VERTICAL)
1724        Cnvrg = wx.TextCtrl(G2frame.dataDisplay,-1,value='%.2g'%(data['min dM/M']),style=wx.TE_PROCESS_ENTER)
1725        Cnvrg.Bind(wx.EVT_TEXT_ENTER,OnConvergence)
1726        Cnvrg.Bind(wx.EVT_KILL_FOCUS,OnConvergence)
1727        LSSizer.Add(Cnvrg,0,wx.ALIGN_CENTER_VERTICAL)
1728        if 'Hessian' in data['deriv type']:
1729            LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Max cycles: '),0,wx.ALIGN_CENTER_VERTICAL)
1730            Choice = ['0','1','2','3','5','10','15','20']
1731            maxCyc = wx.ComboBox(parent=G2frame.dataDisplay,value=str(data['max cyc']),choices=Choice,
1732                style=wx.CB_READONLY|wx.CB_DROPDOWN)
1733            maxCyc.SetValue(str(data['max cyc']))
1734            maxCyc.Bind(wx.EVT_COMBOBOX, OnMaxCycles)
1735            LSSizer.Add(maxCyc,0,wx.ALIGN_CENTER_VERTICAL)
1736        else:
1737            LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Initial shift factor: '),0,wx.ALIGN_CENTER_VERTICAL)
1738            Factr = wx.TextCtrl(G2frame.dataDisplay,-1,value='%.5f'%(data['shift factor']),style=wx.TE_PROCESS_ENTER)
1739            Factr.Bind(wx.EVT_TEXT_ENTER,OnFactor)
1740            Factr.Bind(wx.EVT_KILL_FOCUS,OnFactor)
1741            LSSizer.Add(Factr,0,wx.ALIGN_CENTER_VERTICAL)
1742        if G2frame.Sngl:
1743            LSSizer.Add((1,0),)
1744            LSSizer.Add((1,0),)
1745            fsqRef = wx.CheckBox(G2frame.dataDisplay,-1,label='Refine HKLF as F^2? ')
1746            fsqRef.SetValue(data['F**2'])
1747            fsqRef.Bind(wx.EVT_CHECKBOX,OnFsqRef)
1748            LSSizer.Add(fsqRef,0,wx.ALIGN_CENTER_VERTICAL)
1749            LSSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,label='Min obs/sig (0-5): '),0,wx.ALIGN_CENTER_VERTICAL)
1750            minSig = wx.TextCtrl(G2frame.dataDisplay,-1,value='%.2f'%(data['minF/sig']),style=wx.TE_PROCESS_ENTER)
1751            minSig.Bind(wx.EVT_TEXT_ENTER,OnMinSig)
1752            minSig.Bind(wx.EVT_KILL_FOCUS,OnMinSig)
1753            LSSizer.Add(minSig,0,wx.ALIGN_CENTER_VERTICAL)
1754        return LSSizer
1755       
1756    if G2frame.dataDisplay:
1757        G2frame.dataDisplay.Destroy()
1758    if not G2frame.dataFrame.GetStatusBar():
1759        Status = G2frame.dataFrame.CreateStatusBar()
1760        Status.SetStatusText('')
1761    G2frame.dataFrame.SetLabel('Controls')
1762    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
1763    SetDataMenuBar(G2frame,G2frame.dataFrame.ControlsMenu)
1764    mainSizer = wx.BoxSizer(wx.VERTICAL)
1765    mainSizer.Add((5,5),0)
1766    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Refinement Controls:'),0,wx.ALIGN_CENTER_VERTICAL)   
1767    mainSizer.Add(LSSizer())
1768    mainSizer.Add((5,5),0)
1769    mainSizer.Add(SeqSizer())
1770    mainSizer.Add((5,5),0)
1771       
1772    mainSizer.Layout()   
1773    G2frame.dataDisplay.SetSizer(mainSizer)
1774    G2frame.dataDisplay.SetSize(mainSizer.Fit(G2frame.dataFrame))
1775    G2frame.dataFrame.setSizePosLeft(mainSizer.Fit(G2frame.dataFrame))
1776     
1777################################################################################
1778#####  Comments
1779################################################################################           
1780       
1781def UpdateComments(G2frame,data):                   
1782
1783    if G2frame.dataDisplay:
1784        G2frame.dataDisplay.Destroy()
1785    G2frame.dataFrame.SetLabel('Comments')
1786    G2frame.dataDisplay = wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
1787        style=wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_DONTWRAP)
1788    for line in data:
1789        G2frame.dataDisplay.AppendText(line+'\n')
1790    G2frame.dataFrame.setSizePosLeft([400,250])
1791           
1792################################################################################
1793#####  Sequential Results
1794################################################################################           
1795       
1796def UpdateSeqResults(G2frame,data):
1797    """
1798    Called when the Sequential Results data tree entry is selected
1799    to show results from a sequential refinement.
1800   
1801    :param wx.Frame G2frame: main GSAS-II data tree windows
1802
1803    :param dict data: a dictionary containing the following items: 
1804
1805            * 'histNames' - list of histogram names in order as processed by Sequential Refinement
1806            * 'varyList' - list of variables - identical over all refinements in sequence
1807            * 'histName' - dictionaries for all data sets processed, which contains:
1808
1809              * 'variables'- result[0] from leastsq call
1810              * 'varyList' - list of variables; same as above
1811              * 'sig' - esds for variables
1812              * 'covMatrix' - covariance matrix from individual refinement
1813              * 'title' - histogram name; same as dict item name
1814              * 'newAtomDict' - new atom parameters after shifts applied
1815              * 'newCellDict' - new cell parameters after shifts to A0-A5 applied'
1816    """
1817    if not data:
1818        print 'No sequential refinement results'
1819        return
1820    histNames = data['histNames']
1821       
1822    def GetSampleParms():
1823        sampleParmDict = {'Temperature':[],'Pressure':[],'Humidity':[],'Voltage':[],'Force':[],}
1824        sampleParm = {}
1825        for name in histNames:
1826            Id = GetPatternTreeItemId(G2frame,G2frame.root,name)
1827            sampleData = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,Id,'Sample Parameters'))
1828            for item in sampleParmDict:
1829                sampleParmDict[item].append(sampleData[item])
1830        for item in sampleParmDict:
1831            frstValue = sampleParmDict[item][0]
1832            if np.any(np.array(sampleParmDict[item])-frstValue):
1833                sampleParm[item] = sampleParmDict[item]           
1834        return sampleParm
1835           
1836    def GetRwps():
1837        Rwps = []
1838        for name in histNames:
1839            Rwps.append(data[name]['Rvals']['Rwp'])
1840        return Rwps
1841           
1842    def GetSigData(parm):
1843        sigData = []
1844        for name in histNames:
1845            sigList = data[name]['sig']
1846            if colLabels[parm] in atomList:
1847                sigData.append(sigList[colLabels.index(atomList[colLabels[parm]])-1])
1848            elif colLabels[parm] in cellList:
1849                sigData.append(sigList[colLabels.index(cellList[colLabels[parm]])-1])
1850            else:
1851                sigData.append(sigList[parm-1])
1852        return sigData
1853   
1854    def Select(event):
1855        cols = G2frame.dataDisplay.GetSelectedCols()
1856        rows = G2frame.dataDisplay.GetSelectedRows()
1857        if cols:
1858            plotData = []
1859            plotSig = []
1860            plotNames = []
1861            for col in cols:
1862                plotData.append(G2frame.SeqTable.GetColValues(col))
1863                if col:     #not Rwp
1864                    plotSig.append(GetSigData(col))
1865                else:
1866                    plotSig.append(0.0)
1867                plotNames.append(G2frame.SeqTable.GetColLabelValue(col))
1868            plotData = np.array(plotData)
1869            G2plt.PlotSeq(G2frame,plotData,plotSig,plotNames,sampleParms)
1870        elif rows:
1871            name = histNames[rows[0]]       #only does 1st one selected
1872            G2plt.PlotCovariance(G2frame,data[name])
1873           
1874    def OnSaveSelSeq(event):       
1875        cols = G2frame.dataDisplay.GetSelectedCols()
1876        if cols:
1877            numRows = G2frame.SeqTable.GetNumberRows()
1878            dataNames = []
1879            saveNames = [G2frame.SeqTable.GetRowLabelValue(r) for r in range(numRows)]
1880            saveData = []
1881            for col in cols:
1882                dataNames.append(G2frame.SeqTable.GetColLabelValue(col))
1883                if col:     #not Rwp
1884                    saveData.append(zip(G2frame.SeqTable.GetColValues(col),GetSigData(col)))
1885                else:
1886                    saveData.append(zip(G2frame.SeqTable.GetColValues(col),0.0))
1887            lenName = len(saveNames[0])
1888            saveData = np.swapaxes(np.array(saveData),0,1)
1889            dlg = wx.FileDialog(G2frame, 'Choose text output file for your selection', '.', '', 
1890                'Text output file (*.txt)|*.txt',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1891            try:
1892                if dlg.ShowModal() == wx.ID_OK:
1893                    SeqTextFile = dlg.GetPath()
1894                    SeqTextFile = G2IO.FileDlgFixExt(dlg,SeqTextFile)
1895                    SeqFile = open(SeqTextFile,'w')
1896                    line = %s  '%('name'.center(lenName))
1897                    for item in dataNames:
1898                        line += ' %12s %12s '%(item.center(12),'esd'.center(12))
1899                    line += '\n'
1900                    SeqFile.write(line)
1901                    for i,item in enumerate(saveData):
1902                        line = " '%s' "%(saveNames[i])
1903                        for val,esd in item:
1904                            line += ' %12.6f %12.6f '%(val,esd)
1905                        line += '\n'
1906                        SeqFile.write(line)
1907                    SeqFile.close()
1908            finally:
1909                dlg.Destroy()
1910           
1911               
1912    if G2frame.dataDisplay:
1913        G2frame.dataDisplay.Destroy()
1914    atomList = {}
1915    newAtomDict = data[histNames[0]]['newAtomDict']
1916    for item in newAtomDict:
1917        if item in data['varyList']:
1918            atomList[newAtomDict[item][0]] = item
1919    cellList = {}
1920    newCellDict = data[histNames[0]]['newCellDict']
1921    for item in newCellDict:
1922        if item in data['varyList']:
1923            cellList[newCellDict[item][0]] = item
1924    sampleParms = GetSampleParms()
1925    Rwps = GetRwps()
1926    SetDataMenuBar(G2frame,G2frame.dataFrame.SequentialMenu)
1927    G2frame.dataFrame.SetLabel('Sequential refinement results')
1928    G2frame.dataFrame.CreateStatusBar()
1929    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveSelSeq, id=wxID_SAVESEQSEL)
1930    colLabels = ['Rwp',]+data['varyList']+atomList.keys()+cellList.keys()
1931    Types = (len(data['varyList']+atomList.keys()+cellList.keys())+1)*[wg.GRID_VALUE_FLOAT,]
1932    seqList = [[Rwps[i],]+list(data[name]['variables']) for i,name in enumerate(histNames)]
1933    for i,item in enumerate(seqList):
1934        newAtomDict = data[histNames[i]]['newAtomDict']
1935        newCellDict = data[histNames[i]]['newCellDict']
1936        item += [newAtomDict[atomList[parm]][1] for parm in atomList.keys()]
1937        item += [newCellDict[cellList[parm]][1] for parm in cellList.keys()]
1938    G2frame.SeqTable = Table(seqList,colLabels=colLabels,rowLabels=histNames,types=Types)
1939    G2frame.dataDisplay = GSGrid(parent=G2frame.dataFrame)
1940    G2frame.dataDisplay.SetTable(G2frame.SeqTable, True)
1941    G2frame.dataDisplay.EnableEditing(False)
1942    G2frame.dataDisplay.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK, Select)
1943    G2frame.dataDisplay.SetRowLabelSize(8*len(histNames[0]))       #pretty arbitrary 8
1944    G2frame.dataDisplay.SetMargins(0,0)
1945    G2frame.dataDisplay.AutoSizeColumns(True)
1946    G2frame.dataFrame.setSizePosLeft([700,350])
1947       
1948################################################################################
1949#####  Main PWDR panel
1950################################################################################           
1951       
1952def UpdatePWHKPlot(G2frame,kind,item):
1953    '''Needs a doc string
1954    '''
1955
1956    def OnErrorAnalysis(event):
1957        G2plt.PlotDeltSig(G2frame,kind)
1958       
1959    def OnWtFactor(event):
1960        try:
1961            val = float(wtval.GetValue())
1962        except ValueError:
1963            val = data[0]['wtFactor']
1964        data[0]['wtFactor'] = val
1965        wtval.SetValue('%.3f'%(val))
1966           
1967    data = G2frame.PatternTree.GetItemPyData(item)
1968    if 'wtFactor' not in data[0]:
1969        data[0] = {'wtFactor':1.0}
1970    if G2frame.dataDisplay:
1971        G2frame.dataDisplay.Destroy()
1972    SetDataMenuBar(G2frame,G2frame.dataFrame.ErrorMenu)
1973    G2frame.dataFrame.Bind(wx.EVT_MENU,OnErrorAnalysis, id=wxID_PWDANALYSIS)
1974    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
1975   
1976    mainSizer = wx.BoxSizer(wx.VERTICAL)
1977    mainSizer.Add((5,5),)
1978    wtSizer = wx.BoxSizer(wx.HORIZONTAL)
1979    wtSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Weight factor: '),0,wx.ALIGN_CENTER_VERTICAL)
1980    wtval = wx.TextCtrl(G2frame.dataDisplay,-1,'%.3f'%(data[0]['wtFactor']),style=wx.TE_PROCESS_ENTER)
1981    wtval.Bind(wx.EVT_TEXT_ENTER,OnWtFactor)
1982    wtval.Bind(wx.EVT_KILL_FOCUS,OnWtFactor)
1983    wtSizer.Add(wtval,0,wx.ALIGN_CENTER_VERTICAL)
1984    mainSizer.Add(wtSizer)
1985    mainSizer.Layout()   
1986    G2frame.dataDisplay.SetSizer(mainSizer)
1987    G2frame.dataFrame.setSizePosLeft(mainSizer.Fit(G2frame.dataFrame))
1988    G2frame.PatternTree.SetItemPyData(item,data)
1989    if kind == 'PWDR':
1990        G2plt.PlotPatterns(G2frame,newPlot=True)
1991    elif kind == 'HKLF':
1992        G2plt.PlotSngl(G2frame,newPlot=True)
1993                 
1994################################################################################
1995#####  HKLF controls
1996################################################################################           
1997       
1998def UpdateHKLControls(G2frame,data):
1999    '''Needs a doc string
2000    '''
2001   
2002    def OnScaleSlider(event):
2003        scale = int(scaleSel.GetValue())/1000.
2004        scaleSel.SetValue(int(scale*1000.))
2005        data['Scale'] = scale*1.
2006        G2plt.PlotSngl(G2frame)
2007       
2008    def OnLayerSlider(event):
2009        layer = layerSel.GetValue()
2010        data['Layer'] = layer
2011        G2plt.PlotSngl(G2frame)
2012       
2013    def OnSelZone(event):
2014        data['Zone'] = zoneSel.GetValue()
2015        izone = zones.index(data['Zone'])
2016        layerSel.SetRange(maxValue=HKLmax[izone],minValue=HKLmin[izone])
2017        G2plt.PlotSngl(G2frame,newPlot=True)
2018       
2019    def OnSelType(event):
2020        data['Type'] = typeSel.GetValue()
2021        G2plt.PlotSngl(G2frame)
2022       
2023    def SetStatusLine():
2024        Status.SetStatusText("")
2025                                     
2026    if G2frame.dataDisplay:
2027        G2frame.dataDisplay.Destroy()
2028    if not G2frame.dataFrame.GetStatusBar():
2029        Status = G2frame.dataFrame.CreateStatusBar()
2030    SetStatusLine()
2031    zones = ['100','010','001']
2032    HKLmax = data['HKLmax']
2033    HKLmin = data['HKLmin']
2034    typeChoices = ['Fosq','Fo','|DFsq|/sig','|DFsq|>sig','|DFsq|>3sig']
2035    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
2036    SetDataMenuBar(G2frame)
2037    G2frame.dataFrame.SetTitle('HKL Plot Controls')
2038    mainSizer = wx.BoxSizer(wx.VERTICAL)
2039    mainSizer.Add((5,10),0)
2040   
2041    scaleSizer = wx.BoxSizer(wx.HORIZONTAL)
2042    scaleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Scale'),0,
2043        wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
2044    scaleSel = wx.Slider(parent=G2frame.dataDisplay,maxValue=1000,minValue=1,
2045        style=wx.SL_HORIZONTAL,value=int(data['Scale']*10))
2046    scaleSizer.Add(scaleSel,1,wx.EXPAND|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
2047    scaleSel.SetLineSize(10)
2048    scaleSel.SetPageSize(10)
2049    scaleSel.Bind(wx.EVT_SLIDER, OnScaleSlider)
2050    mainSizer.Add(scaleSizer,0,wx.EXPAND|wx.RIGHT)
2051    mainSizer.Add((0,10),0)   
2052   
2053    zoneSizer = wx.BoxSizer(wx.HORIZONTAL)
2054    zoneSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Zone  '),0,
2055        wx.ALIGN_CENTER_VERTICAL)
2056    zoneSel = wx.ComboBox(parent=G2frame.dataDisplay,value=data['Zone'],choices=['100','010','001'],
2057        style=wx.CB_READONLY|wx.CB_DROPDOWN)
2058    zoneSel.Bind(wx.EVT_COMBOBOX, OnSelZone)
2059    zoneSizer.Add(zoneSel,0,wx.ALIGN_CENTER_VERTICAL)
2060    zoneSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Plot type  '),0,
2061        wx.ALIGN_CENTER_VERTICAL)       
2062    typeSel = wx.ComboBox(parent=G2frame.dataDisplay,value=data['Type'],choices=typeChoices,
2063        style=wx.CB_READONLY|wx.CB_DROPDOWN)
2064    typeSel.Bind(wx.EVT_COMBOBOX, OnSelType)
2065    zoneSizer.Add(typeSel,0,wx.ALIGN_CENTER_VERTICAL)
2066    zoneSizer.Add((10,0),0)   
2067    mainSizer.Add(zoneSizer,0,wx.EXPAND|wx.RIGHT)
2068    mainSizer.Add((0,10),0)   
2069       
2070    izone = zones.index(data['Zone'])
2071    layerSizer = wx.BoxSizer(wx.HORIZONTAL)
2072    layerSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Layer'),0,
2073        wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
2074    layerSel = wx.Slider(parent=G2frame.dataDisplay,maxValue=HKLmax[izone],minValue=HKLmin[izone],
2075        style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS|wx.SL_LABELS,value=0)
2076    layerSel.SetLineSize(1)
2077    layerSel.SetPageSize(1)
2078    layerSel.Bind(wx.EVT_SLIDER, OnLayerSlider)   
2079    layerSizer.Add(layerSel,1,wx.EXPAND|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
2080    layerSizer.Add((10,0),0)   
2081    mainSizer.Add(layerSizer,1,wx.EXPAND|wx.RIGHT)
2082
2083       
2084    mainSizer.Layout()   
2085    G2frame.dataDisplay.SetSizer(mainSizer)
2086    G2frame.dataDisplay.SetSize(mainSizer.Fit(G2frame.dataFrame))
2087    G2frame.dataFrame.setSizePosLeft(mainSizer.Fit(G2frame.dataFrame))
2088
2089################################################################################
2090#####  Pattern tree routines
2091################################################################################           
2092       
2093def GetPatternTreeDataNames(G2frame,dataTypes):
2094    '''Needs a doc string
2095    '''
2096    names = []
2097    item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)       
2098    while item:
2099        name = G2frame.PatternTree.GetItemText(item)
2100        if name[:4] in dataTypes:
2101            names.append(name)
2102        item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
2103    return names
2104                         
2105def GetPatternTreeItemId(G2frame, parentId, itemText):
2106    '''Needs a doc string
2107    '''
2108    item, cookie = G2frame.PatternTree.GetFirstChild(parentId)
2109    while item:
2110        if G2frame.PatternTree.GetItemText(item) == itemText:
2111            return item
2112        item, cookie = G2frame.PatternTree.GetNextChild(parentId, cookie)
2113    return 0               
2114
2115def MovePatternTreeToGrid(G2frame,item):
2116    '''Needs a doc string
2117    '''
2118   
2119#    print G2frame.PatternTree.GetItemText(item)
2120   
2121    oldPage = None # will be set later if already on a Phase item
2122    if G2frame.dataFrame:
2123        SetDataMenuBar(G2frame)
2124        if G2frame.dataFrame.GetLabel() == 'Comments':
2125            try:
2126                data = [G2frame.dataDisplay.GetValue()]
2127                G2frame.dataDisplay.Clear() 
2128                Id = GetPatternTreeItemId(G2frame,G2frame.root, 'Comments')
2129                if Id: G2frame.PatternTree.SetItemPyData(Id,data)
2130            except:     #clumsy but avoids dead window problem when opening another project
2131                pass
2132        elif G2frame.dataFrame.GetLabel() == 'Notebook':
2133            try:
2134                data = [G2frame.dataDisplay.GetValue()]
2135                G2frame.dataDisplay.Clear() 
2136                Id = GetPatternTreeItemId(G2frame,G2frame.root, 'Notebook')
2137                if Id: G2frame.PatternTree.SetItemPyData(Id,data)
2138            except:     #clumsy but avoids dead window problem when opening another project
2139                pass
2140        elif 'Phase Data for' in G2frame.dataFrame.GetLabel():
2141            if G2frame.dataDisplay: 
2142                oldPage = G2frame.dataDisplay.GetSelection()
2143        G2frame.dataFrame.Clear()
2144        G2frame.dataFrame.SetLabel('')
2145    else:
2146        #create the frame for the data item window
2147        G2frame.dataFrame = DataFrame(parent=G2frame.mainPanel,frame=G2frame)
2148        G2frame.dataFrame.PhaseUserSize = None
2149       
2150    G2frame.dataFrame.Raise()           
2151    G2frame.PickId = 0
2152    parentID = G2frame.root
2153    for i in G2frame.ExportPattern: i.Enable(False)
2154    defWid = [250,150]
2155    if item != G2frame.root:
2156        parentID = G2frame.PatternTree.GetItemParent(item)
2157    if G2frame.PatternTree.GetItemParent(item) == G2frame.root:
2158        G2frame.PatternId = item
2159        G2frame.PickId = item
2160        if G2frame.PatternTree.GetItemText(item) == 'Notebook':
2161            SetDataMenuBar(G2frame,G2frame.dataFrame.DataNotebookMenu)
2162            G2frame.PatternId = 0
2163            for i in G2frame.ExportPattern: i.Enable(False)
2164            data = G2frame.PatternTree.GetItemPyData(item)
2165            UpdateNotebook(G2frame,data)
2166        elif G2frame.PatternTree.GetItemText(item) == 'Controls':
2167            G2frame.PatternId = 0
2168            for i in G2frame.ExportPattern: i.Enable(False)
2169            data = G2frame.PatternTree.GetItemPyData(item)
2170            if not data:           #fill in defaults
2171                data = {
2172                    #least squares controls
2173                    'deriv type':'analytic Hessian','min dM/M':0.0001,'shift factor':1.0,'max cyc':3}
2174                G2frame.PatternTree.SetItemPyData(item,data)                             
2175            for i in G2frame.Refine: i.Enable(True)
2176            for i in G2frame.SeqRefine: i.Enable(True)
2177            UpdateControls(G2frame,data)
2178        elif G2frame.PatternTree.GetItemText(item) == 'Sequential results':
2179            data = G2frame.PatternTree.GetItemPyData(item)
2180            UpdateSeqResults(G2frame,data)           
2181        elif G2frame.PatternTree.GetItemText(item) == 'Covariance':
2182            data = G2frame.PatternTree.GetItemPyData(item)
2183            G2frame.dataFrame.setSizePosLeft(defWid)
2184            text = ''
2185            if 'Rvals' in data:
2186                Nvars = len(data['varyList'])
2187                Rvals = data['Rvals']
2188                text = '\nFinal residuals: \nRw = %.3f%% \nchi**2 = %.1f \nGOF = %.2f'%(Rvals['Rwp'],Rvals['chisq'],Rvals['GOF'])
2189                text += '\nNobs = %d \nNvals = %d'%(Rvals['Nobs'],Nvars)
2190                if 'lamMax' in Rvals:
2191                    text += '\nlog10 MaxLambda = %.1f'%(np.log10(Rvals['lamMax']))
2192            wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
2193                value='See plot window for covariance display'+text,style=wx.TE_MULTILINE)
2194            G2plt.PlotCovariance(G2frame,data)
2195        elif G2frame.PatternTree.GetItemText(item) == 'Constraints':
2196            data = G2frame.PatternTree.GetItemPyData(item)
2197            G2cnstG.UpdateConstraints(G2frame,data)
2198        elif G2frame.PatternTree.GetItemText(item) == 'Rigid bodies':
2199            data = G2frame.PatternTree.GetItemPyData(item)
2200            G2cnstG.UpdateRigidBodies(G2frame,data)
2201        elif G2frame.PatternTree.GetItemText(item) == 'Restraints':
2202            data = G2frame.PatternTree.GetItemPyData(item)
2203            Phases = G2frame.GetPhaseData()
2204            phase = ''
2205            phaseName = ''
2206            if Phases:
2207                phaseName = Phases.keys()[0]
2208            G2frame.dataFrame.setSizePosLeft(defWid)
2209            G2restG.UpdateRestraints(G2frame,data,Phases,phaseName)
2210        elif 'IMG' in G2frame.PatternTree.GetItemText(item):
2211            G2frame.Image = item
2212            G2plt.PlotImage(G2frame,newPlot=True)
2213        elif 'PKS' in G2frame.PatternTree.GetItemText(item):
2214            G2plt.PlotPowderLines(G2frame)
2215        elif 'PWDR' in G2frame.PatternTree.GetItemText(item):
2216            for i in G2frame.ExportPattern: i.Enable(True)
2217            UpdatePWHKPlot(G2frame,'PWDR',item)
2218        elif 'HKLF' in G2frame.PatternTree.GetItemText(item):
2219            G2frame.Sngl = item
2220            UpdatePWHKPlot(G2frame,'HKLF',item)
2221        elif 'PDF' in G2frame.PatternTree.GetItemText(item):
2222            G2frame.PatternId = item
2223            for i in G2frame.ExportPDF: i.Enable(True)
2224            G2plt.PlotISFG(G2frame,type='S(Q)')
2225        elif G2frame.PatternTree.GetItemText(item) == 'Phases':
2226            G2frame.dataFrame.setSizePosLeft(defWid)
2227            wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
2228                value='Select one phase to see its parameters')           
2229    elif 'I(Q)' in G2frame.PatternTree.GetItemText(item):
2230        G2frame.PickId = item
2231        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2232        G2plt.PlotISFG(G2frame,type='I(Q)',newPlot=True)
2233    elif 'S(Q)' in G2frame.PatternTree.GetItemText(item):
2234        G2frame.PickId = item
2235        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2236        G2plt.PlotISFG(G2frame,type='S(Q)',newPlot=True)
2237    elif 'F(Q)' in G2frame.PatternTree.GetItemText(item):
2238        G2frame.PickId = item
2239        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2240        G2plt.PlotISFG(G2frame,type='F(Q)',newPlot=True)
2241    elif 'G(R)' in G2frame.PatternTree.GetItemText(item):
2242        G2frame.PickId = item
2243        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2244        G2plt.PlotISFG(G2frame,type='G(R)',newPlot=True)           
2245    elif G2frame.PatternTree.GetItemText(parentID) == 'Phases':
2246        G2frame.PickId = item
2247        data = G2frame.PatternTree.GetItemPyData(item)
2248        G2phG.UpdatePhaseData(G2frame,item,data,oldPage)
2249    elif G2frame.PatternTree.GetItemText(item) == 'Comments':
2250        SetDataMenuBar(G2frame,G2frame.dataFrame.DataCommentsMenu)
2251        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2252        G2frame.PickId = item
2253        data = G2frame.PatternTree.GetItemPyData(item)
2254        UpdateComments(G2frame,data)
2255    elif G2frame.PatternTree.GetItemText(item) == 'Image Controls':
2256        G2frame.dataFrame.SetTitle('Image Controls')
2257        G2frame.PickId = item
2258        G2frame.Image = G2frame.PatternTree.GetItemParent(item)
2259        masks = G2frame.PatternTree.GetItemPyData(
2260            GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks'))
2261        data = G2frame.PatternTree.GetItemPyData(item)
2262        G2imG.UpdateImageControls(G2frame,data,masks)
2263        G2plt.PlotImage(G2frame)
2264    elif G2frame.PatternTree.GetItemText(item) == 'Masks':
2265        G2frame.dataFrame.SetTitle('Masks')
2266        G2frame.PickId = item
2267        G2frame.Image = G2frame.PatternTree.GetItemParent(item)
2268        data = G2frame.PatternTree.GetItemPyData(item)
2269        G2imG.UpdateMasks(G2frame,data)
2270        G2plt.PlotImage(G2frame)
2271    elif G2frame.PatternTree.GetItemText(item) == 'Stress/Strain':
2272        G2frame.dataFrame.SetTitle('Stress/Strain')
2273        G2frame.PickId = item
2274        G2frame.Image = G2frame.PatternTree.GetItemParent(item)
2275        data = G2frame.PatternTree.GetItemPyData(item)
2276        G2imG.UpdateStressStrain(G2frame,data)
2277        G2plt.PlotImage(G2frame)
2278    elif G2frame.PatternTree.GetItemText(item) == 'HKL Plot Controls':
2279        G2frame.PickId = item
2280        G2frame.Sngl = G2frame.PatternTree.GetItemParent(item)
2281        data = G2frame.PatternTree.GetItemPyData(item)
2282        UpdateHKLControls(G2frame,data)
2283        G2plt.PlotSngl(G2frame)
2284    elif G2frame.PatternTree.GetItemText(item) == 'PDF Controls':
2285        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2286        for i in G2frame.ExportPDF: i.Enable(True)
2287        G2frame.PickId = item
2288        data = G2frame.PatternTree.GetItemPyData(item)
2289        G2pdG.UpdatePDFGrid(G2frame,data)
2290        G2plt.PlotISFG(G2frame,type='I(Q)')
2291        G2plt.PlotISFG(G2frame,type='S(Q)')
2292        G2plt.PlotISFG(G2frame,type='F(Q)')
2293        G2plt.PlotISFG(G2frame,type='G(R)')
2294    elif G2frame.PatternTree.GetItemText(item) == 'Peak List':
2295        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2296        for i in G2frame.ExportPeakList: i.Enable(True)
2297        G2frame.PickId = item
2298        data = G2frame.PatternTree.GetItemPyData(item)
2299        G2pdG.UpdatePeakGrid(G2frame,data)
2300        G2plt.PlotPatterns(G2frame)
2301    elif G2frame.PatternTree.GetItemText(item) == 'Background':
2302        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2303        G2frame.PickId = item
2304        data = G2frame.PatternTree.GetItemPyData(item)
2305        G2pdG.UpdateBackground(G2frame,data)
2306        G2plt.PlotPatterns(G2frame)
2307    elif G2frame.PatternTree.GetItemText(item) == 'Limits':
2308        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2309        G2frame.PickId = item
2310        data = G2frame.PatternTree.GetItemPyData(item)
2311        G2pdG.UpdateLimitsGrid(G2frame,data)
2312        G2plt.PlotPatterns(G2frame)
2313    elif G2frame.PatternTree.GetItemText(item) == 'Instrument Parameters':
2314        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2315        G2frame.PickId = item
2316        data = G2frame.PatternTree.GetItemPyData(item)[0]
2317        G2pdG.UpdateInstrumentGrid(G2frame,data)
2318        G2plt.PlotPeakWidths(G2frame)
2319    elif G2frame.PatternTree.GetItemText(item) == 'Sample Parameters':
2320        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2321        G2frame.PickId = item
2322        data = G2frame.PatternTree.GetItemPyData(item)
2323
2324        if 'Temperature' not in data:           #temp fix for old gpx files
2325            data = {'Scale':[1.0,True],'Type':'Debye-Scherrer','Absorption':[0.0,False],'DisplaceX':[0.0,False],
2326                'DisplaceY':[0.0,False],'Diffuse':[],'Temperature':300.,'Pressure':1.0,'Humidity':0.0,'Voltage':0.0,
2327                'Force':0.0,'Gonio. radius':200.0}
2328            G2frame.PatternTree.SetItemPyData(item,data)
2329   
2330        G2pdG.UpdateSampleGrid(G2frame,data)
2331        G2plt.PlotPatterns(G2frame)
2332    elif G2frame.PatternTree.GetItemText(item) == 'Index Peak List':
2333        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2334        for i in G2frame.ExportPeakList: i.Enable(True)
2335        G2frame.PickId = item
2336        data = G2frame.PatternTree.GetItemPyData(item)
2337        G2pdG.UpdateIndexPeaksGrid(G2frame,data)
2338        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2339            G2plt.PlotPowderLines(G2frame)
2340        else:
2341            G2plt.PlotPatterns(G2frame)
2342    elif G2frame.PatternTree.GetItemText(item) == 'Unit Cells List':
2343        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2344        G2frame.PickId = item
2345        data = G2frame.PatternTree.GetItemPyData(item)
2346        if not data:
2347            data.append([0,0.0,4,25.0,0,'P1',1,1,1,90,90,90]) #zero error flag, zero value, max Nc/No, start volume
2348            data.append([0,0,0,0,0,0,0,0,0,0,0,0,0,0])      #Bravais lattice flags
2349            data.append([])                                 #empty cell list
2350            data.append([])                                 #empty dmin
2351            G2frame.PatternTree.SetItemPyData(item,data)                             
2352        G2pdG.UpdateUnitCellsGrid(G2frame,data)
2353        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2354            G2plt.PlotPowderLines(G2frame)
2355        else:
2356            G2plt.PlotPatterns(G2frame)
2357    elif G2frame.PatternTree.GetItemText(item) == 'Reflection Lists':   #powder reflections
2358        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2359        G2frame.PickId = item
2360        data = G2frame.PatternTree.GetItemPyData(item)
2361        G2frame.RefList = ''
2362        if len(data):
2363            G2frame.RefList = data.keys()[0]
2364        G2pdG.UpdateReflectionGrid(G2frame,data)
2365        G2plt.PlotPatterns(G2frame)
2366    elif G2frame.PatternTree.GetItemText(item) == 'Reflection List':    #HKLF reflections
2367        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2368        name = G2frame.PatternTree.GetItemText(G2frame.PatternId)
2369        data = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)
2370        G2pdG.UpdateReflectionGrid(G2frame,data,HKLF=True,Name=name)
2371
2372def SetDataMenuBar(G2frame,menu=None):
2373    '''Set the menu for the data frame. On the Mac put this
2374    menu for the data tree window instead.
2375
2376    Note that data frame items do not have menus, for these (menu=None)
2377    display a blank menu or on the Mac display the standard menu for
2378    the data tree window.
2379    '''
2380    if sys.platform == "darwin":
2381        if menu is None:
2382            G2frame.SetMenuBar(G2frame.GSASIIMenu)
2383        else:
2384            G2frame.SetMenuBar(menu)
2385    else:
2386        if menu is None:
2387            G2frame.dataFrame.SetMenuBar(G2frame.dataFrame.BlankMenu)
2388        else:
2389            G2frame.dataFrame.SetMenuBar(menu)
2390
2391def HorizontalLine(sizer,parent):
2392    '''Draws a horizontal line as wide as the window.
2393    This shows up on the Mac as a very thin line, no matter what I do
2394    '''
2395    line = wx.StaticLine(parent,-1, size=(-1,3), style=wx.LI_HORIZONTAL)
2396    sizer.Add(line, 0, wx.EXPAND|wx.ALIGN_CENTER|wx.ALL, 10)
2397
Note: See TracBrowser for help on using the repository browser.