source: trunk/GSASIIgrid.py @ 923

Last change on this file since 923 was 923, checked in by toby, 9 years ago

more doc updates

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