source: trunk/GSASIIgrid.py @ 774

Last change on this file since 774 was 774, checked in by vondreele, 11 years ago

Add find equivalent peaks to mappeaks

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