source: trunk/GSASIIgrid.py @ 762

Last change on this file since 762 was 762, checked in by toby, 10 years ago

update py files to use native line ends, add update from svn to help menu when svn or svn.exe is in path or ./svn/bin

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