source: trunk/GSASIIgrid.py @ 765

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

refactor menus on Mac, clean up main menu generation

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 116.9 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASII - data display routines
3########### SVN repository information ###################
4# $Date: 2012-09-29 02:25:04 +0000 (Sat, 29 Sep 2012) $
5# $Author: toby $
6# $Revision: 765 $
7# $URL: trunk/GSASIIgrid.py $
8# $Id: GSASIIgrid.py 765 2012-09-29 02:25:04Z toby $
9########### SVN repository information ###################
10import wx
11import wx.grid as wg
12import time
13import cPickle
14import sys
15import numpy as np
16import os.path
17import wx.html        # could postpone this for quicker startup
18import webbrowser     # could postpone this for quicker startup
19import GSASIIpath
20GSASIIpath.SetVersionNumber("$Revision: 765 $")
21import GSASIImath as G2mth
22import GSASIIIO as G2IO
23import GSASIIplot as G2plt
24import GSASIIpwdGUI as G2pdG
25import GSASIIimgGUI as G2imG
26import GSASIIphsGUI as G2phG
27import GSASIIstruct as G2str
28import GSASIImapvars as G2mv
29
30# globals we will use later
31__version__ = None # gets overridden in GSASII.py
32path2GSAS2 = os.path.dirname(os.path.realpath(__file__)) # save location of this file
33helpLocDict = {}
34htmlPanel = None
35htmlFrame = None
36helpMode = 'browser'
37if sys.platform.lower().startswith('win'): helpMode = 'internal' # need a global control to set this
38   
39htmlFirstUse = True
40
41[ wxID_FOURCALC, wxID_FOURSEARCH, wxID_FOURCLEAR, wxID_PEAKSMOVE, wxID_PEAKSCLEAR, 
42    wxID_CHARGEFLIP, wxID_PEAKSUNIQUE, wxID_PEAKSDELETE, wxID_PEAKSDA,
43    wxID_PEAKSDISTVP, wxID_PEAKSVIEWPT,
44] = [wx.NewId() for item in range(11)]
45
46[ wxID_PWDRADD, wxID_HKLFADD, wxID_DATADELETE,
47] = [wx.NewId() for item in range(3)]
48
49[ wxID_ATOMSEDITADD, wxID_ATOMSEDITINSERT, wxID_ATOMSEDITDELETE, wxID_ATOMSREFINE, 
50    wxID_ATOMSMODIFY, wxID_ATOMSTRANSFORM, wxID_ATOMSVIEWADD, wxID_ATOMVIEWINSERT,
51    wxID_RELOADDRAWATOMS,wxID_ATOMSDISAGL,
52] = [wx.NewId() for item in range(10)]
53
54[ wxID_DRAWATOMSTYLE, wxID_DRAWATOMLABEL, wxID_DRAWATOMCOLOR, wxID_DRAWATOMRESETCOLOR, 
55    wxID_DRAWVIEWPOINT, wxID_DRAWTRANSFORM, wxID_DRAWDELETE, wxID_DRAWFILLCELL, 
56    wxID_DRAWADDEQUIV, wxID_DRAWFILLCOORD, wxID_DRAWDISAGLTOR,  wxID_DRAWPLANE,
57    wxID_DRAWDISTVP,
58] = [wx.NewId() for item in range(13)]
59
60[ wxID_DRAWRESTRBOND, wxID_DRAWRESTRANGLE, wxID_DRAWRESTRPLANE, wxID_DRAWRESTRCHIRAL,
61] = [wx.NewId() for item in range(4)]
62
63[ wxID_CLEARTEXTURE,wxID_REFINETEXTURE,
64] = [wx.NewId() for item in range(2)]
65
66[ wxID_PAWLEYLOAD, wxID_PAWLEYDELETE, wxID_PAWLEYESTIMATE,
67    wxID_PAWLEYUPDATE,
68] = [wx.NewId() for item in range(4)]
69
70[ wxID_IMCALIBRATE,wxID_IMRECALIBRATE,wxID_IMINTEGRATE, wxID_IMCLEARCALIB, 
71    wxID_IMCOPYCONTROLS, wxID_INTEGRATEALL, wxID_IMSAVECONTROLS, wxID_IMLOADCONTROLS,
72] = [wx.NewId() for item in range(8)]
73
74[ wxID_MASKCOPY, wxID_MASKSAVE, wxID_MASKLOAD,
75] = [wx.NewId() for item in range(3)]
76
77[ wxID_STRSTACOPY, wxID_STRSTAFIT, wxID_STRSTASAVE, wxID_STRSTALOAD,wxID_APPENDDZERO,
78] = [wx.NewId() for item in range(5)]
79
80[ wxID_BACKCOPY,wxID_LIMITCOPY,wxID_SAMPLECOPY, wxID_BACKFLAGCOPY, wxID_SAMPLEFLAGCOPY,
81    wxID_SAMPLESAVE, wxID_SAMPLELOAD,
82] = [wx.NewId() for item in range(7)]
83
84[ wxID_INSTPRMRESET,wxID_CHANGEWAVETYPE,wxID_INSTCOPY, wxID_INSTFLAGCOPY, wxID_INSTLOAD,
85    wxID_INSTSAVE,
86] = [wx.NewId() for item in range(6)]
87
88[ wxID_UNDO,wxID_LSQPEAKFIT,wxID_LSQONECYCLE,wxID_RESETSIGGAM,wxID_CLEARPEAKS,
89] = [wx.NewId() for item in range(5)]
90
91[  wxID_INDXRELOAD, wxID_INDEXPEAKS, wxID_REFINECELL, wxID_COPYCELL, wxID_MAKENEWPHASE,
92] = [wx.NewId() for item in range(5)]
93
94[ wxID_CONSTRAINTADD,wxID_EQUIVADD,wxID_HOLDADD,wxID_FUNCTADD,
95] = [wx.NewId() for item in range(4)]
96
97[ wxID_RESTRAINTADD,wxID_PWDANALYSIS, wxID_RESTSELPHASE,wxID_RESTDELETE, wxID_RESRCHANGEVAL, 
98    wxID_RESTCHANGEESD,
99] = [wx.NewId() for item in range(6)]
100
101[ wxID_SAVESEQSEL,
102] = [wx.NewId() for item in range(1)]
103
104[ wxID_SELECTPHASE,
105] = [wx.NewId() for item in range(1)]
106
107[ wxID_PDFCOPYCONTROLS, wxID_PDFSAVECONTROLS, wxID_PDFLOADCONTROLS, 
108    wxID_PDFCOMPUTE, wxID_PDFCOMPUTEALL, wxID_PDFADDELEMENT, wxID_PDFDELELEMENT,
109] = [wx.NewId() for item in range(7)]
110
111VERY_LIGHT_GREY = wx.Colour(235,235,235)
112
113def ShowHelp(helpType,frame):
114    '''Called to bring up a web page for documentation.'''
115    global htmlFirstUse
116    # look up a definition for help info from dict
117    helplink = helpLocDict.get(helpType)
118    if helplink is None:
119        # no defined link to use, create a default based on key
120        helplink = 'gsasII.html#'+helpType.replace(' ','_')
121    helplink = os.path.join(path2GSAS2,'help',helplink)
122    if helpMode == 'internal':
123        try:
124            htmlPanel.LoadFile(helplink)
125            htmlFrame.Raise()
126        except:
127            htmlFrame = wx.Frame(frame, -1, size=(610, 510))
128            htmlFrame.Show(True)
129            htmlFrame.SetTitle("HTML Window") # N.B. reset later in LoadFile
130            htmlPanel = MyHtmlPanel(htmlFrame,-1)
131            htmlPanel.LoadFile(helplink)
132    else:
133        if htmlFirstUse:
134            webbrowser.open_new("file://"+helplink)
135            htmlFirstUse = False
136        else:
137            webbrowser.open("file://"+helplink, new=0, autoraise=True)
138
139class MyHelp(wx.Menu):
140    '''This class creates the contents of a help menu.
141    The menu will start with two entries:
142      'Help on <helpType>': where helpType is a reference to an HTML page to
143      be opened
144      About: opens an About dialog using OnHelpAbout. N.B. on the Mac this
145      gets moved to the App menu to be consistent with Apple style.
146    NOTE: the title 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_PEAKSUNIQUE, kind=wx.ITEM_NORMAL,text='Unique peaks', 
763            help='Select unique set')
764        self.MapPeaksEdit.Append(id=wxID_PEAKSDELETE, kind=wx.ITEM_NORMAL,text='Delete peaks', 
765            help='Delete selected peaks')
766        self.MapPeaksEdit.Append(id=wxID_PEAKSCLEAR, kind=wx.ITEM_NORMAL,text='Clear peaks', 
767            help='Clear the map peak list')
768           
769# end of GSAS-II menu definitions
770       
771    def _init_ctrls(self, parent,name=None,size=None,pos=None):
772        wx.Frame.__init__(self,parent=parent,
773            style=wx.DEFAULT_FRAME_STYLE ^ wx.CLOSE_BOX | wx.FRAME_FLOAT_ON_PARENT ,
774            size=size,pos=pos,title='GSAS-II data display')
775        self._init_menus()
776        if name:
777            self.SetLabel(name)
778        self.Show()
779       
780    def __init__(self,parent,frame,data=None,name=None, size=None,pos=None):
781        self.G2frame = frame
782        self._init_ctrls(parent,name,size,pos)
783        self.data = data
784        clientSize = wx.ClientDisplayRect()
785        Size = self.GetSize()
786        xPos = clientSize[2]-Size[0]
787        self.SetPosition(wx.Point(xPos,clientSize[1]+250))
788        self.AtomGrid = []
789        self.selectedRow = 0
790       
791    def setSizePosLeft(self,Width):
792        clientSize = wx.ClientDisplayRect()
793        Width[1] = min(Width[1],clientSize[2]-300)
794        Width[0] = max(Width[0],300)
795        self.SetSize(Width)
796#        self.SetPosition(wx.Point(clientSize[2]-Width[0],clientSize[1]+250))
797       
798    def Clear(self):
799        self.ClearBackground()
800        self.DestroyChildren()
801                   
802################################################################################
803#####  GSNotebook
804################################################################################           
805       
806class GSNoteBook(wx.Notebook):
807    def __init__(self, parent, name='',size = None):
808        wx.Notebook.__init__(self, parent, -1, name=name, style= wx.BK_TOP)
809        if size: self.SetSize(size)
810                                                     
811    def Clear(self):       
812        GSNoteBook.DeleteAllPages(self)
813       
814    def FindPage(self,name):
815        numPage = self.GetPageCount()
816        for page in range(numPage):
817            if self.GetPageText(page) == name:
818                return page
819       
820################################################################################
821#####  GSGrid
822################################################################################           
823       
824class GSGrid(wg.Grid):
825    def __init__(self, parent, name=''):
826        wg.Grid.__init__(self,parent,-1,name=name)                   
827        self.SetSize(parent.GetClientSize())
828           
829    def Clear(self):
830        wg.Grid.ClearGrid(self)
831       
832    def SetCellStyle(self,r,c,color="white",readonly=True):
833        self.SetCellBackgroundColour(r,c,color)
834        self.SetReadOnly(r,c,isReadOnly=readonly)
835       
836    def GetSelection(self):
837        #this is to satisfy structure drawing stuff in G2plt when focus changes
838        return None
839                       
840################################################################################
841#####  Table
842################################################################################           
843       
844class Table(wg.PyGridTableBase):
845    def __init__(self, data=[], rowLabels=None, colLabels=None, types = None):
846        wg.PyGridTableBase.__init__(self)
847        self.colLabels = colLabels
848        self.rowLabels = rowLabels
849        self.dataTypes = types
850        self.data = data
851       
852    def AppendRows(self, numRows=1):
853        self.data.append([])
854        return True
855       
856    def CanGetValueAs(self, row, col, typeName):
857        if self.dataTypes:
858            colType = self.dataTypes[col].split(':')[0]
859            if typeName == colType:
860                return True
861            else:
862                return False
863        else:
864            return False
865
866    def CanSetValueAs(self, row, col, typeName):
867        return self.CanGetValueAs(row, col, typeName)
868
869    def DeleteRow(self,pos):
870        data = self.GetData()
871        self.SetData([])
872        new = []
873        for irow,row in enumerate(data):
874            if irow <> pos:
875                new.append(row)
876        self.SetData(new)
877       
878    def GetColLabelValue(self, col):
879        if self.colLabels:
880            return self.colLabels[col]
881           
882    def GetData(self):
883        data = []
884        for row in range(self.GetNumberRows()):
885            data.append(self.GetRowValues(row))
886        return data
887       
888    def GetNumberCols(self):
889        try:
890            return len(self.colLabels)
891        except TypeError:
892            return None
893       
894    def GetNumberRows(self):
895        return len(self.data)
896       
897    def GetRowLabelValue(self, row):
898        if self.rowLabels:
899            return self.rowLabels[row]
900       
901    def GetColValues(self, col):
902        data = []
903        for row in range(self.GetNumberRows()):
904            data.append(self.GetValue(row, col))
905        return data
906       
907    def GetRowValues(self, row):
908        data = []
909        for col in range(self.GetNumberCols()):
910            data.append(self.GetValue(row, col))
911        return data
912       
913    def GetTypeName(self, row, col):
914        try:
915            return self.dataTypes[col]
916        except TypeError:
917            return None
918
919    def GetValue(self, row, col):
920        try:
921            return self.data[row][col]
922        except IndexError:
923            return None
924           
925    def InsertRows(self, pos, rows):
926        for row in range(rows):
927            self.data.insert(pos,[])
928            pos += 1
929       
930    def IsEmptyCell(self,row,col):
931        try:
932            return not self.data[row][col]
933        except IndexError:
934            return True
935       
936    def OnKeyPress(self, event):
937        dellist = self.GetSelectedRows()
938        if event.GetKeyCode() == wx.WXK_DELETE and dellist:
939            grid = self.GetView()
940            for i in dellist: grid.DeleteRow(i)
941               
942    def SetColLabelValue(self, col, label):
943        numcols = self.GetNumberCols()
944        if col > numcols-1:
945            self.colLabels.append(label)
946        else:
947            self.colLabels[col]=label
948       
949    def SetData(self,data):
950        for row in range(len(data)):
951            self.SetRowValues(row,data[row])
952               
953    def SetRowLabelValue(self, row, label):
954        self.rowLabels[row]=label
955           
956    def SetRowValues(self,row,data):
957        self.data[row] = data
958           
959    def SetValue(self, row, col, value):
960        def innerSetValue(row, col, value):
961            try:
962                self.data[row][col] = value
963            except TypeError:
964                return
965            except IndexError:
966                print row,col,value
967                # add a new row
968                if row > self.GetNumberRows():
969                    self.data.append([''] * self.GetNumberCols())
970                elif col > self.GetNumberCols():
971                    for row in range(self.GetNumberRows):
972                        self.data[row].append('')
973                print self.data
974                self.data[row][col] = value
975        innerSetValue(row, col, value)
976               
977################################################################################
978#####  Notebook
979################################################################################           
980       
981def UpdateNotebook(G2frame,data):       
982    if data:
983        G2frame.dataFrame.SetLabel('Notebook')
984        G2frame.dataDisplay = wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
985            style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER | wx.TE_DONTWRAP)
986        for line in data:
987            G2frame.dataDisplay.AppendText(line+"\n")
988            G2frame.dataDisplay.AppendText('Notebook entry @ '+time.ctime()+"\n")
989           
990################################################################################
991#####  Controls
992################################################################################           
993       
994def UpdateControls(G2frame,data):
995    #patch
996    if 'deriv type' not in data:
997        data = {}
998        data['deriv type'] = 'analytic Hessian'
999        data['min dM/M'] = 0.0001
1000        data['shift factor'] = 1.
1001        data['max cyc'] = 3       
1002        data['F**2'] = True
1003        data['minF/sig'] = 0
1004    if 'shift factor' not in data:
1005        data['shift factor'] = 1.
1006    if 'max cyc' not in data:
1007        data['max cyc'] = 3
1008    if 'F**2' not in data:
1009        data['F**2'] = True
1010        data['minF/sig'] = 0
1011    #end patch
1012
1013    def SeqSizer():
1014       
1015        def OnSelectData(event):
1016            choices = ['All',]+GetPatternTreeDataNames(G2frame,['PWDR',])
1017            sel = []
1018            if 'Seq Data' in data:
1019                for item in data['Seq Data']:
1020                    sel.append(choices.index(item))
1021            names = []
1022            dlg = wx.MultiChoiceDialog(G2frame,'Select data:','Sequential refinement',choices)
1023            dlg.SetSelections(sel)
1024            if dlg.ShowModal() == wx.ID_OK:
1025                sel = dlg.GetSelections()
1026                for i in sel: names.append(choices[i])
1027                if 'All' in names:
1028                    names = choices[1:]
1029                data['Seq Data'] = names               
1030            dlg.Destroy()
1031            reverseSel.Enable(True)
1032           
1033        def OnReverse(event):
1034            data['Reverse Seq'] = reverseSel.GetValue()
1035                   
1036        seqSizer = wx.BoxSizer(wx.HORIZONTAL)
1037        seqSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Sequential Refinement Powder Data: '),0,wx.ALIGN_CENTER_VERTICAL)
1038        selSeqData = wx.Button(G2frame.dataDisplay,-1,label=' Select data')
1039        selSeqData.Bind(wx.EVT_BUTTON,OnSelectData)
1040        seqSizer.Add(selSeqData,0,wx.ALIGN_CENTER_VERTICAL)
1041        seqSizer.Add((5,0),0)
1042        reverseSel = wx.CheckBox(G2frame.dataDisplay,-1,label=' Reverse order?')
1043        reverseSel.Bind(wx.EVT_CHECKBOX,OnReverse)
1044        if 'Seq Data' not in data:
1045            reverseSel.Enable(False)
1046        if 'Reverse Seq' in data:
1047            reverseSel.SetValue(data['Reverse Seq'])
1048        seqSizer.Add(reverseSel,0,wx.ALIGN_CENTER_VERTICAL)
1049        return seqSizer
1050       
1051    def LSSizer():       
1052       
1053        def OnDerivType(event):
1054            data['deriv type'] = derivSel.GetValue()
1055            derivSel.SetValue(data['deriv type'])
1056            wx.CallAfter(UpdateControls,G2frame,data)
1057           
1058        def OnConvergence(event):
1059            try:
1060                value = max(1.e-9,min(1.0,float(Cnvrg.GetValue())))
1061            except ValueError:
1062                value = 0.0001
1063            data['min dM/M'] = value
1064            Cnvrg.SetValue('%.2g'%(value))
1065           
1066        def OnMaxCycles(event):
1067            data['max cyc'] = int(maxCyc.GetValue())
1068            maxCyc.SetValue(str(data['max cyc']))
1069                       
1070        def OnFactor(event):
1071            try:
1072                value = min(max(float(Factr.GetValue()),0.00001),100.)
1073            except ValueError:
1074                value = 1.0
1075            data['shift factor'] = value
1076            Factr.SetValue('%.5f'%(value))
1077           
1078        def OnFsqRef(event):
1079            data['F**2'] = fsqRef.GetValue()
1080       
1081        def OnMinSig(event):
1082            try:
1083                value = min(max(float(minSig.GetValue()),0.),5.)
1084            except ValueError:
1085                value = 1.0
1086            data['minF/sig'] = value
1087            minSig.SetValue('%.2f'%(value))
1088
1089        LSSizer = wx.FlexGridSizer(cols=4,vgap=5,hgap=5)
1090        LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Refinement derivatives: '),0,wx.ALIGN_CENTER_VERTICAL)
1091        Choice=['analytic Jacobian','numeric','analytic Hessian']
1092        derivSel = wx.ComboBox(parent=G2frame.dataDisplay,value=data['deriv type'],choices=Choice,
1093            style=wx.CB_READONLY|wx.CB_DROPDOWN)
1094        derivSel.SetValue(data['deriv type'])
1095        derivSel.Bind(wx.EVT_COMBOBOX, OnDerivType)
1096           
1097        LSSizer.Add(derivSel,0,wx.ALIGN_CENTER_VERTICAL)
1098        LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Min delta-M/M: '),0,wx.ALIGN_CENTER_VERTICAL)
1099        Cnvrg = wx.TextCtrl(G2frame.dataDisplay,-1,value='%.2g'%(data['min dM/M']),style=wx.TE_PROCESS_ENTER)
1100        Cnvrg.Bind(wx.EVT_TEXT_ENTER,OnConvergence)
1101        Cnvrg.Bind(wx.EVT_KILL_FOCUS,OnConvergence)
1102        LSSizer.Add(Cnvrg,0,wx.ALIGN_CENTER_VERTICAL)
1103        if 'Hessian' in data['deriv type']:
1104            LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Max cycles: '),0,wx.ALIGN_CENTER_VERTICAL)
1105            Choice = ['0','1','2','3','5','10','15','20']
1106            maxCyc = wx.ComboBox(parent=G2frame.dataDisplay,value=str(data['max cyc']),choices=Choice,
1107                style=wx.CB_READONLY|wx.CB_DROPDOWN)
1108            maxCyc.SetValue(str(data['max cyc']))
1109            maxCyc.Bind(wx.EVT_COMBOBOX, OnMaxCycles)
1110            LSSizer.Add(maxCyc,0,wx.ALIGN_CENTER_VERTICAL)
1111        else:
1112            LSSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Initial shift factor: '),0,wx.ALIGN_CENTER_VERTICAL)
1113            Factr = wx.TextCtrl(G2frame.dataDisplay,-1,value='%.5f'%(data['shift factor']),style=wx.TE_PROCESS_ENTER)
1114            Factr.Bind(wx.EVT_TEXT_ENTER,OnFactor)
1115            Factr.Bind(wx.EVT_KILL_FOCUS,OnFactor)
1116            LSSizer.Add(Factr,0,wx.ALIGN_CENTER_VERTICAL)
1117        if G2frame.Sngl:
1118            LSSizer.Add((1,0),)
1119            LSSizer.Add((1,0),)
1120            fsqRef = wx.CheckBox(G2frame.dataDisplay,-1,label='Refine HKLF as F^2? ')
1121            fsqRef.SetValue(data['F**2'])
1122            fsqRef.Bind(wx.EVT_CHECKBOX,OnFsqRef)
1123            LSSizer.Add(fsqRef,0,wx.ALIGN_CENTER_VERTICAL)
1124            LSSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,label='Min obs/sig (0-5): '),0,wx.ALIGN_CENTER_VERTICAL)
1125            minSig = wx.TextCtrl(G2frame.dataDisplay,-1,value='%.2f'%(data['minF/sig']),style=wx.TE_PROCESS_ENTER)
1126            minSig.Bind(wx.EVT_TEXT_ENTER,OnMinSig)
1127            minSig.Bind(wx.EVT_KILL_FOCUS,OnMinSig)
1128            LSSizer.Add(minSig,0,wx.ALIGN_CENTER_VERTICAL)
1129        return LSSizer
1130       
1131    if G2frame.dataDisplay:
1132        G2frame.dataDisplay.Destroy()
1133    if not G2frame.dataFrame.GetStatusBar():
1134        Status = G2frame.dataFrame.CreateStatusBar()
1135        Status.SetStatusText('')
1136    G2frame.dataFrame.SetLabel('Controls')
1137    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
1138    SetDataMenuBar(G2frame,G2frame.dataFrame.ControlsMenu)
1139    mainSizer = wx.BoxSizer(wx.VERTICAL)
1140    mainSizer.Add((5,5),0)
1141    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Refinement Controls:'),0,wx.ALIGN_CENTER_VERTICAL)   
1142    mainSizer.Add(LSSizer())
1143    mainSizer.Add((5,5),0)
1144    mainSizer.Add(SeqSizer())
1145    mainSizer.Add((5,5),0)
1146       
1147    mainSizer.Layout()   
1148    G2frame.dataDisplay.SetSizer(mainSizer)
1149    G2frame.dataDisplay.SetSize(mainSizer.Fit(G2frame.dataFrame))
1150    G2frame.dataFrame.setSizePosLeft(mainSizer.Fit(G2frame.dataFrame))
1151     
1152################################################################################
1153#####  Comments
1154################################################################################           
1155       
1156def UpdateComments(G2frame,data):                   
1157    G2frame.dataFrame.SetLabel('Comments')
1158    G2frame.dataDisplay = wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
1159        style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER | wx.TE_DONTWRAP)
1160    for line in data:
1161        if line[-1] == '\n':
1162            G2frame.dataDisplay.AppendText(line)
1163        else:
1164            G2frame.dataDisplay.AppendText(line+'\n')
1165           
1166################################################################################
1167#####  Sequential Results
1168################################################################################           
1169       
1170def UpdateSeqResults(G2frame,data):
1171    """
1172    input:
1173        data - dictionary
1174            'histNames' - list of histogram names in order as processed by Sequential Refinement
1175            'varyList' - list of variables - identical over all refinements insequence
1176            histName - dictionaries for all data sets processed:
1177                'variables'- result[0] from leastsq call
1178                'varyList' - list of variables; same as above
1179                'sig' - esds for variables
1180                'covMatrix' - covariance matrix from individual refinement
1181                'title' - histogram name; same as dict item name
1182                'newAtomDict' - new atom parameters after shifts applied
1183                'newCellDict' - new cell parameters after shifts to A0-A5 applied'
1184    """
1185    if not data:
1186        print 'No sequential refinement results'
1187        return
1188    histNames = data['histNames']
1189       
1190    def GetSampleParms():
1191        sampleParmDict = {'Temperature':[],'Pressure':[],'Humidity':[],'Voltage':[],'Force':[],}
1192        sampleParm = {}
1193        for name in histNames:
1194            Id = GetPatternTreeItemId(G2frame,G2frame.root,name)
1195            sampleData = G2frame.PatternTree.GetItemPyData(GetPatternTreeItemId(G2frame,Id,'Sample Parameters'))
1196            for item in sampleParmDict:
1197                sampleParmDict[item].append(sampleData[item])
1198        for item in sampleParmDict:
1199            frstValue = sampleParmDict[item][0]
1200            if np.any(np.array(sampleParmDict[item])-frstValue):
1201                sampleParm[item] = sampleParmDict[item]           
1202        return sampleParm
1203           
1204    def GetRwps():
1205        Rwps = []
1206        for name in histNames:
1207            Rwps.append(data[name]['Rvals']['Rwp'])
1208        return Rwps
1209           
1210    def GetSigData(parm):
1211        sigData = []
1212        for name in histNames:
1213            sigList = data[name]['sig']
1214            if colLabels[parm] in atomList:
1215                sigData.append(sigList[colLabels.index(atomList[colLabels[parm]])])
1216            elif colLabels[parm] in cellList:
1217                sigData.append(sigList[colLabels.index(cellList[colLabels[parm]])])
1218            else:
1219                sigData.append(sigList[parm])
1220        return sigData
1221   
1222    def Select(event):
1223        cols = G2frame.dataDisplay.GetSelectedCols()
1224        rows = G2frame.dataDisplay.GetSelectedRows()
1225        if cols:
1226            plotData = []
1227            plotSig = []
1228            plotNames = []
1229            for col in cols:
1230                plotData.append(G2frame.SeqTable.GetColValues(col))
1231                plotSig.append(GetSigData(col))
1232                plotNames.append(G2frame.SeqTable.GetColLabelValue(col))
1233            plotData = np.array(plotData)
1234            G2plt.PlotSeq(G2frame,plotData,plotSig,plotNames,sampleParms)
1235        elif rows:
1236            name = histNames[rows[0]]
1237            G2plt.PlotCovariance(G2frame,Data=data[name])
1238           
1239    def OnSaveSelSeq(event):       
1240        cols = G2frame.dataDisplay.GetSelectedCols()
1241        if cols:
1242            numRows = G2frame.SeqTable.GetNumberRows()
1243            dataNames = []
1244            saveNames = [G2frame.SeqTable.GetRowLabelValue(r) for r in range(numRows)]
1245            saveData = []
1246            for col in cols:
1247                dataNames.append(G2frame.SeqTable.GetColLabelValue(col))
1248                saveData.append(zip(G2frame.SeqTable.GetColValues(col),GetSigData(col)))
1249            lenName = len(saveNames[0])
1250            saveData = np.swapaxes(np.array(saveData),0,1)
1251            dlg = wx.FileDialog(G2frame, 'Choose text output file for your selection', '.', '', 
1252                'Text output file (*.txt)|*.txt',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1253            try:
1254                if dlg.ShowModal() == wx.ID_OK:
1255                    SeqTextFile = dlg.GetPath()
1256                    SeqTextFile = G2IO.FileDlgFixExt(dlg,SeqTextFile)
1257                    SeqFile = open(SeqTextFile,'w')
1258                    line = %s  '%('name'.center(lenName))
1259                    for item in dataNames:
1260                        line += ' %12s %12s '%(item.center(12),'esd'.center(12))
1261                    line += '\n'
1262                    SeqFile.write(line)
1263                    for i,item in enumerate(saveData):
1264                        line = " '%s' "%(saveNames[i])
1265                        for val,esd in item:
1266                            line += ' %12.6f %12.6f '%(val,esd)
1267                        line += '\n'
1268                        SeqFile.write(line)
1269                    SeqFile.close()
1270            finally:
1271                dlg.Destroy()
1272           
1273               
1274    if G2frame.dataDisplay:
1275        G2frame.dataDisplay.Destroy()
1276    cellList = {}
1277    newCellDict = data[histNames[0]]['newCellDict']
1278    for item in newCellDict:
1279        if item in data['varyList']:
1280            cellList[newCellDict[item][0]] = item
1281    atomList = {}
1282    newAtomDict = data[histNames[0]]['newAtomDict']
1283    for item in newAtomDict:
1284        if item in data['varyList']:
1285            atomList[newAtomDict[item][0]] = item
1286    sampleParms = GetSampleParms()
1287    Rwps = GetRwps()
1288    SetDataMenuBar(G2frame,G2frame.dataFrame.SequentialMenu)
1289    G2frame.dataFrame.SetLabel('Sequental refinement results')
1290    G2frame.dataFrame.CreateStatusBar()
1291    G2frame.dataFrame.Bind(wx.EVT_MENU, OnSaveSelSeq, id=wxID_SAVESEQSEL)
1292    colLabels = ['Rwp',]+data['varyList']+atomList.keys()+cellList.keys()
1293    Types = (len(data['varyList']+atomList.keys()+cellList.keys())+1)*[wg.GRID_VALUE_FLOAT,]
1294    seqList = [[Rwps[i],]+list(data[name]['variables']) for i,name in enumerate(histNames)]   
1295    for i,item in enumerate(seqList):
1296        newAtomDict = data[histNames[i]]['newAtomDict']
1297        newCellDict = data[histNames[i]]['newCellDict']
1298        item += [newAtomDict[atomList[parm]][1] for parm in atomList.keys()]
1299        item += [newCellDict[cellList[parm]][1] for parm in cellList.keys()]
1300    G2frame.SeqTable = Table(seqList,colLabels=colLabels,rowLabels=histNames,types=Types)
1301    G2frame.dataDisplay = GSGrid(parent=G2frame.dataFrame)
1302    G2frame.dataDisplay.SetTable(G2frame.SeqTable, True)
1303    G2frame.dataDisplay.EnableEditing(False)
1304    G2frame.dataDisplay.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK, Select)
1305    G2frame.dataDisplay.SetRowLabelSize(8*len(histNames[0]))       #pretty arbitrary 8
1306    G2frame.dataDisplay.SetMargins(0,0)
1307    G2frame.dataDisplay.AutoSizeColumns(True)
1308    G2frame.dataFrame.setSizePosLeft([700,350])
1309   
1310################################################################################
1311#####  Constraints
1312################################################################################           
1313       
1314def UpdateConstraints(G2frame,data):
1315    '''Called when Constraints tree item is selected.
1316    Displays the constraints in the data window
1317    '''
1318    if not data:
1319        data.update({'Hist':[],'HAP':[],'Phase':[]})       #empty dict - fill it
1320    Histograms,Phases = G2frame.GetUsedHistogramsAndPhasesfromTree()
1321    AtomDict = dict([Phases[phase]['pId'],Phases[phase]['Atoms']] for phase in Phases)
1322    Natoms,atomIndx,phaseVary,phaseDict,pawleyLookup,FFtable,BLtable = G2str.GetPhaseData(Phases,Print=False)
1323    phaseList = []
1324    for item in phaseDict:
1325        if item.split(':')[2] not in ['Ax','Ay','Az','Amul','AI/A','Atype','SHorder']:
1326            phaseList.append(item)
1327    phaseList.sort()
1328    phaseAtNames = {}
1329    for item in phaseList:
1330        Split = item.split(':')
1331        if Split[2][:2] in ['AU','Af','dA']:
1332            phaseAtNames[item] = AtomDict[int(Split[0])][int(Split[3])][0]
1333        else:
1334            phaseAtNames[item] = ''
1335           
1336    hapVary,hapDict,controlDict = G2str.GetHistogramPhaseData(Phases,Histograms,Print=False)
1337    hapList = hapDict.keys()
1338    hapList.sort()
1339    histVary,histDict,controlDict = G2str.GetHistogramData(Histograms,Print=False)
1340    histList = []
1341    for item in histDict:
1342        if item.split(':')[2] not in ['Omega','Type','Chi','Phi','Azimuth','Gonio. radius','Lam1','Lam2','Back']:
1343            histList.append(item)
1344    histList.sort()
1345    Indx = {}
1346    scope = {}                          #filled out later
1347    G2frame.Page = [0,'phs']
1348   
1349    def GetPHlegends(Phases,Histograms):
1350        plegend = '\n In p::name'
1351        hlegend = '\n In :h:name'
1352        phlegend = '\n In p:h:name'
1353        for phase in Phases:
1354            plegend += '\n p:: = '+str(Phases[phase]['pId'])+':: for '+phase
1355            count = 0
1356            for histogram in Phases[phase]['Histograms']:
1357                if count < 3:
1358                    phlegend += '\n p:h: = '+str(Phases[phase]['pId'])+':'+str(Histograms[histogram]['hId'])+': for '+phase+' in '+histogram
1359                else:
1360                    phlegend += '\n ... etc.'
1361                    break
1362                count += 1
1363        count = 0
1364        for histogram in Histograms:
1365            if count < 3:
1366                hlegend += '\n :h: = :'+str(Histograms[histogram]['hId'])+': for '+histogram
1367            else:
1368                hlegend += '\n ... etc.'
1369                break
1370            count += 1
1371        return plegend,hlegend,phlegend
1372       
1373    def FindEquivVarb(name,nameList):
1374        outList = []
1375        namelist = [name.split(':')[2],]
1376        if 'dA' in name:
1377            namelist = ['dAx','dAy','dAz']
1378        elif 'AU' in name:
1379            namelist = ['AUiso','AU11','AU22','AU33','AU12','AU13','AU23']
1380        for item in nameList:
1381            key = item.split(':')[2]
1382            if key in namelist and item != name:
1383                outList.append(item)
1384        return outList
1385       
1386    def SelectVarbs(page,FrstVarb,varList,legend,constType):
1387        '''Select variables used in Constraints after one variable has
1388        been selected which determines the appropriate variables to be
1389        used here. Then creates the constraint and adds it to the
1390        constraints list.
1391        Called from OnAddEquivalence, OnAddFunction & OnAddConstraint
1392        '''
1393        #future -  add 'all:all:name', '0:all:name', etc. to the varList
1394        if page[1] == 'phs':
1395            atchoice = [item+' for '+phaseAtNames[item] for item in varList]
1396            dlg = wx.MultiChoiceDialog(G2frame,'Select more variables:'+legend,
1397                'Constrain '+FrstVarb+' and...',atchoice)
1398        else:
1399            dlg = wx.MultiChoiceDialog(G2frame,'Select more variables:'+legend,
1400                'Constrain '+FrstVarb+' and...',varList)
1401        varbs = [FrstVarb,]
1402        if dlg.ShowModal() == wx.ID_OK:
1403            sel = dlg.GetSelections()
1404            for x in sel:
1405                varbs.append(varList[x])
1406        dlg.Destroy()
1407        if len(varbs) > 1:
1408            if 'equivalence' in constType:
1409                constr = [[1.0,FrstVarb]]
1410                for item in varbs[1:]:
1411                    constr += [[1.0,item]]
1412                return [constr+[None,None,'e']]      # list of equivalent variables & mults
1413            elif 'function' in constType:
1414                constr = map(list,zip([1.0 for i in range(len(varbs))],varbs))
1415                return [constr+[None,False,'f']]         #just one constraint
1416            else:       #'constraint'
1417                constr = map(list,zip([1.0 for i in range(len(varbs))],varbs))
1418                return [constr+[1.0,None,'c']]          #just one constraint - default sum to one
1419        return []
1420
1421    def CheckAddedConstraint(newcons):
1422        '''Check a new constraint that has just been input.
1423        If there is an error display a message and give the user a
1424        choice to keep or discard the last entry (why keep? -- they
1425        may want to delete something else or edit multipliers).
1426        Since the varylist is not available, no warning messages
1427        should be generated.
1428        Returns True if constraint should be added
1429        '''
1430        allcons = []
1431        for key in 'Hist','HAP','Phase':
1432            allcons += data[key]
1433        allcons += newcons
1434        if not len(allcons): return True
1435        G2mv.InitVars()   
1436        constDictList,fixedList,ignored = G2str.ProcessConstraints(allcons)
1437        errmsg, warnmsg = G2mv.CheckConstraints('',constDictList,fixedList)
1438        if errmsg:
1439            res = G2frame.ErrorDialog('Constraint Error',
1440                'Error with newly added constraint:\n'+errmsg+
1441                '\n\nDiscard newly added constraint?',parent=G2frame.dataFrame,
1442                wtype=wx.YES_NO)
1443            return res != wx.ID_YES
1444        elif warnmsg:
1445            print 'Unexpected contraint warning:\n',warnmsg
1446        return True
1447
1448    def CheckChangedConstraint():
1449        '''Check all constraints after an edit has been made.
1450        If there is an error display a message and give the user a
1451        choice to keep or discard the last edit.
1452        Since the varylist is not available, no warning messages
1453        should be generated.
1454        Returns True if the edit should be retained
1455        '''
1456        allcons = []
1457        for key in 'Hist','HAP','Phase':
1458            allcons += data[key]
1459        if not len(allcons): return True
1460        G2mv.InitVars()   
1461        constDictList,fixedList,ignored = G2str.ProcessConstraints(allcons)
1462        errmsg, warnmsg = G2mv.CheckConstraints('',constDictList,fixedList)
1463        if errmsg:
1464            res = G2frame.ErrorDialog('Constraint Error',
1465                'Error after editing constraint:\n'+errmsg+
1466                '\n\nDiscard last constraint edit?',parent=G2frame.dataFrame,
1467                wtype=wx.YES_NO)
1468            return res != wx.ID_YES
1469        elif warnmsg:
1470            print 'Unexpected contraint warning:\n',warnmsg
1471        return True
1472             
1473    def OnAddHold(event):
1474        '''add a Hold constraint'''
1475        for phase in Phases:
1476            Phase = Phases[phase]
1477            Atoms = Phase['Atoms']
1478        constr = []
1479        page = G2frame.Page
1480        choice = scope[page[1]]
1481        if page[1] == 'phs':
1482            atchoice = [item+' for '+phaseAtNames[item] for item in choice[2]]
1483            dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],atchoice)
1484        else:   
1485            dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],choice[2])
1486        if dlg.ShowModal() == wx.ID_OK:
1487            sel = dlg.GetSelection()
1488            FrstVarb = choice[2][sel]
1489            newcons = [[[0.0,FrstVarb],None,None,'h']]
1490            if CheckAddedConstraint(newcons):
1491                data[choice[3]] += newcons
1492        dlg.Destroy()
1493        choice[4]()
1494       
1495    def OnAddEquivalence(event):
1496        '''add an Equivalence constraint'''
1497        constr = []
1498        page = G2frame.Page
1499        choice = scope[page[1]]
1500        if page[1] == 'phs':
1501            atchoice = [item+' for '+phaseAtNames[item] for item in choice[2]]
1502            dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],atchoice)
1503        else:   
1504            dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],choice[2])
1505        if dlg.ShowModal() == wx.ID_OK:
1506            sel = dlg.GetSelection()
1507            FrstVarb = choice[2][sel]
1508            moreVarb = FindEquivVarb(FrstVarb,choice[2])
1509            newcons = SelectVarbs(page,FrstVarb,moreVarb,choice[1],'equivalence')
1510            if len(newcons) > 0:
1511                if CheckAddedConstraint(newcons):
1512                    data[choice[3]] += newcons
1513        dlg.Destroy()
1514        choice[4]()
1515   
1516    def OnAddFunction(event):
1517        '''add a Function (new variable) constraint'''
1518        constr = []
1519        page = G2frame.Page
1520        choice = scope[page[1]]
1521        if page[1] == 'phs':
1522            atchoice = [item+' for '+phaseAtNames[item] for item in choice[2]]
1523            dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],atchoice)
1524        else:   
1525            dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],choice[2])
1526        if dlg.ShowModal() == wx.ID_OK:
1527            sel = dlg.GetSelection()
1528            FrstVarb = choice[2][sel]
1529            moreVarb = FindEquivVarb(FrstVarb,choice[2])
1530            newcons = SelectVarbs(page,FrstVarb,moreVarb,choice[1],'function')
1531            if len(newcons) > 0:
1532                if CheckAddedConstraint(newcons):
1533                    data[choice[3]] += newcons
1534        dlg.Destroy()
1535        choice[4]()
1536                       
1537    def OnAddConstraint(event):
1538        '''add a constraint equation to the constraints list'''
1539        constr = []
1540        page = G2frame.Page
1541        choice = scope[page[1]]
1542        if page[1] == 'phs':
1543            atchoice = [item+' for '+phaseAtNames[item] for item in choice[2]]
1544            dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],atchoice)
1545        else:   
1546            dlg = wx.SingleChoiceDialog(G2frame,'Select 1st variable:'+choice[1],choice[0],choice[2])
1547        if dlg.ShowModal() == wx.ID_OK:
1548            sel = dlg.GetSelection()
1549            FrstVarb = choice[2][sel]
1550            moreVarb = FindEquivVarb(FrstVarb,choice[2])
1551            newcons = SelectVarbs(page,FrstVarb,moreVarb,choice[1],'constraint')
1552            if len(newcons) > 0:
1553                if CheckAddedConstraint(newcons):
1554                    data[choice[3]] += newcons
1555        dlg.Destroy()
1556        choice[4]()
1557                       
1558    def ConstSizer(name,pageDisplay):
1559        '''This creates a sizer displaying all of the constraints entered
1560        '''
1561        constSizer = wx.FlexGridSizer(1,4,0,0)
1562        maxlen = 70 # characters before wrapping a constraint
1563        for Id,item in enumerate(data[name]):
1564            eqString = ['',]
1565            if item[-1] == 'h':
1566                constSizer.Add((5,5),0)              # blank space for edit button
1567                typeString = ' FIXED   '
1568                eqString[-1] = item[0][1]+'   '
1569            elif isinstance(item[-1],str):
1570                constEdit = wx.Button(pageDisplay,-1,'Edit',style=wx.BU_EXACTFIT)
1571                constEdit.Bind(wx.EVT_BUTTON,OnConstEdit)
1572                constSizer.Add(constEdit)            # edit button
1573                Indx[constEdit.GetId()] = [Id,name]
1574                if item[-1] == 'f':
1575                    for term in item[:-3]:
1576                        if len(eqString[-1]) > maxlen:
1577                            eqString.append(' ')
1578                        m = term[0]
1579                        if eqString[-1] != '':
1580                            if m >= 0:
1581                                eqString[-1] += ' + '
1582                            else:
1583                                eqString[-1] += ' - '
1584                                m = abs(m)
1585                        eqString[-1] += '%.3f*%s '%(m,term[1])
1586                    typeString = ' NEWVAR  '
1587                    eqString[-1] += ' = New Variable   '
1588                elif item[-1] == 'c':
1589                    for term in item[:-3]:
1590                        if len(eqString[-1]) > maxlen:
1591                            eqString.append(' ')
1592                        if eqString[-1] != '':
1593                            if term[0] > 0:
1594                                eqString[-1] += ' + '
1595                            else:
1596                                eqString[-1] += ' - '
1597                        eqString[-1] += '%.3f*%s '%(abs(term[0]),term[1])
1598                    typeString = ' CONSTR  '
1599                    eqString[-1] += ' = %.3f'%(item[-3])+'  '
1600                elif item[-1] == 'e':
1601                    for term in item[:-3]:
1602                        if term[0] == 0: term[0] = 1.0
1603                        if len(eqString[-1]) > maxlen:
1604                            eqString.append(' ')
1605                        if eqString[-1] == '':
1606                            eqString[-1] += '%s '%(term[1])
1607                            first = term[0]
1608                        else:
1609                            eqString[-1] += ' = %.3f*%s '%(first/term[0],term[1])
1610                    typeString = ' EQUIV   '
1611                else:
1612                    print 'Unexpected constraint',item
1613            else:
1614                print 'Removing old-style constraints'
1615                data[name] = []
1616                return constSizer
1617            constDel = wx.Button(pageDisplay,-1,'Delete',style=wx.BU_EXACTFIT)
1618            constDel.Bind(wx.EVT_BUTTON,OnConstDel)
1619            Indx[constDel.GetId()] = [Id,name]
1620            constSizer.Add(constDel)             # delete button
1621            constSizer.Add(wx.StaticText(pageDisplay,-1,typeString),0,wx.ALIGN_CENTER_VERTICAL)
1622            EqSizer = wx.BoxSizer(wx.VERTICAL)
1623            for s in eqString:
1624                EqSizer.Add(wx.StaticText(pageDisplay,-1,s),0,wx.ALIGN_CENTER_VERTICAL)
1625            constSizer.Add(EqSizer,0,wx.ALIGN_CENTER_VERTICAL)
1626            # if item[-1] == 'f':
1627            #     constRef = wx.CheckBox(pageDisplay,-1,label=' Refine?')
1628            #     constRef.SetValue(item[-2])
1629            #     constRef.Bind(wx.EVT_CHECKBOX,OnConstRef)
1630            #     Indx[constRef.GetId()] = item
1631            #     constSizer.Add(constRef)
1632            # else:
1633            #     constSizer.Add((5,5),0)
1634        return constSizer
1635               
1636    # def OnConstRef(event):
1637    #     Obj = event.GetEventObject()
1638    #     Indx[Obj.GetId()][-2] = Obj.GetValue()
1639       
1640    def OnConstDel(event):
1641        Obj = event.GetEventObject()
1642        Id,name = Indx[Obj.GetId()]
1643        del(data[name][Id])
1644        OnPageChanged(None)       
1645       
1646    def OnConstEdit(event):
1647        '''Called to edit an individual contraint by the Edit button'''
1648        Obj = event.GetEventObject()
1649        Id,name = Indx[Obj.GetId()]
1650        sep = '*'
1651        if data[name][Id][-1] == 'f':
1652            items = data[name][Id][:-3]+[[],]
1653            constType = 'New Variable'
1654            lbl = 'Enter value for each term in constraint; sum = new variable'
1655        elif data[name][Id][-1] == 'c':
1656            items = data[name][Id][:-3]+[
1657                [data[name][Id][-3],'fixed value ='],[]]
1658            constType = 'Constraint'
1659            lbl = 'Edit value for each term in constant constraint sum'
1660        elif data[name][Id][-1] == 'e':
1661            items = data[name][Id][:-3]+[[],]
1662            constType = 'Equivalence'
1663            lbl = 'The following terms are set to be equal:'
1664            sep = '/'
1665        else:
1666            return
1667        dlg = G2frame.ConstraintDialog(G2frame.dataFrame,constType,lbl,items,sep)
1668        try:
1669            if dlg.ShowModal() == wx.ID_OK:
1670                prev = data[name][Id]
1671                result = dlg.GetData()
1672                if data[name][Id][-1] == 'c':
1673                    data[name][Id][:-3] = result[:-2]
1674                    data[name][Id][-3] = result[-2][0]
1675                else:
1676                    data[name][Id][:-3] = result[:-1]
1677                if not CheckChangedConstraint():
1678                    data[name][Id] = prev
1679        except:
1680            import traceback
1681            print traceback.format_exc()
1682        finally:
1683            dlg.Destroy()           
1684        OnPageChanged(None)                     
1685   
1686    def UpdateHAPConstr():
1687        '''Responds to press on Histogram/Phase Constraints tab,
1688        shows constraints in data window'''
1689        HAPConstr.DestroyChildren()
1690        HAPDisplay = wx.Panel(HAPConstr)
1691        HAPSizer = wx.BoxSizer(wx.VERTICAL)
1692        HAPSizer.Add((5,5),0)
1693        HAPSizer.Add(ConstSizer('HAP',HAPDisplay))
1694        HAPDisplay.SetSizer(HAPSizer,True)
1695        Size = HAPSizer.GetMinSize()
1696        Size[0] += 40
1697        Size[1] = max(Size[1],250) + 20
1698        HAPDisplay.SetSize(Size)
1699        # scroll bar not working, at least not on Mac
1700        HAPConstr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
1701        Size[1] = min(Size[1],250)
1702        G2frame.dataFrame.setSizePosLeft(Size)
1703       
1704    def UpdateHistConstr():
1705        '''Responds to press on Histogram Constraints tab,
1706        shows constraints in data window'''
1707        HistConstr.DestroyChildren()
1708        HistDisplay = wx.Panel(HistConstr)
1709        HistSizer = wx.BoxSizer(wx.VERTICAL)
1710        HistSizer.Add((5,5),0)       
1711        HistSizer.Add(ConstSizer('Hist',HistDisplay))
1712        HistDisplay.SetSizer(HistSizer,True)
1713        Size = HistSizer.GetMinSize()
1714        Size[0] += 40
1715        Size[1] = max(Size[1],250) + 20
1716        HistDisplay.SetSize(Size)
1717        HistConstr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
1718        Size[1] = min(Size[1],250)
1719        G2frame.dataFrame.setSizePosLeft(Size)
1720       
1721    def UpdatePhaseConstr():
1722        '''Responds to press on Phase Constraint tab,
1723        shows constraints in data window'''
1724        PhaseConstr.DestroyChildren()
1725        PhaseDisplay = wx.Panel(PhaseConstr)
1726        PhaseSizer = wx.BoxSizer(wx.VERTICAL)
1727        PhaseSizer.Add((5,5),0)       
1728        PhaseSizer.Add(ConstSizer('Phase',PhaseDisplay))
1729        PhaseDisplay.SetSizer(PhaseSizer,True)
1730        Size = PhaseSizer.GetMinSize()
1731        Size[0] += 40
1732        Size[1] = max(Size[1],250) + 20
1733        PhaseDisplay.SetSize(Size)
1734        PhaseConstr.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
1735        Size[1] = min(Size[1],250)
1736        G2frame.dataFrame.setSizePosLeft(Size)
1737   
1738    def OnPageChanged(event):
1739        if event:       #page change event!
1740            page = event.GetSelection()
1741        else:
1742            page = G2frame.dataDisplay.GetSelection()
1743        oldPage = G2frame.dataDisplay.ChangeSelection(page)
1744        text = G2frame.dataDisplay.GetPageText(page)
1745        if text == 'Histogram/Phase constraints':
1746            G2frame.Page = [page,'hap']
1747            UpdateHAPConstr()
1748        elif text == 'Histogram constraints':
1749            G2frame.Page = [page,'hst']
1750            UpdateHistConstr()
1751        elif text == 'Phase constraints':
1752            G2frame.Page = [page,'phs']
1753            UpdatePhaseConstr()
1754
1755    def SetStatusLine(text):
1756        Status.SetStatusText(text)                                     
1757       
1758    plegend,hlegend,phlegend = GetPHlegends(Phases,Histograms)
1759    scope = {'hst':['Histogram contraints:',hlegend,histList,'Hist',UpdateHistConstr],
1760        'hap':['Histogram * Phase contraints:',phlegend,hapList,'HAP',UpdateHAPConstr],
1761        'phs':['Phase contraints:',plegend,phaseList,'Phase',UpdatePhaseConstr]}
1762    if G2frame.dataDisplay:
1763        G2frame.dataDisplay.Destroy()
1764    SetDataMenuBar(G2frame,G2frame.dataFrame.ConstraintMenu)
1765    G2frame.dataFrame.SetLabel('Constraints')
1766    if not G2frame.dataFrame.GetStatusBar():
1767        Status = G2frame.dataFrame.CreateStatusBar()
1768    SetStatusLine('')
1769   
1770    SetDataMenuBar(G2frame,G2frame.dataFrame.ConstraintMenu)
1771    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddConstraint, id=wxID_CONSTRAINTADD)
1772    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddFunction, id=wxID_FUNCTADD)
1773    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddEquivalence, id=wxID_EQUIVADD)
1774    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddHold, id=wxID_HOLDADD)
1775    G2frame.dataDisplay = GSNoteBook(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize())
1776   
1777    PhaseConstr = wx.ScrolledWindow(G2frame.dataDisplay)
1778    G2frame.dataDisplay.AddPage(PhaseConstr,'Phase constraints')
1779    HAPConstr = wx.ScrolledWindow(G2frame.dataDisplay)
1780    G2frame.dataDisplay.AddPage(HAPConstr,'Histogram/Phase constraints')
1781    HistConstr = wx.ScrolledWindow(G2frame.dataDisplay)
1782    G2frame.dataDisplay.AddPage(HistConstr,'Histogram constraints')
1783    UpdatePhaseConstr()
1784
1785    G2frame.dataDisplay.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, OnPageChanged)
1786    # validate all the constrants -- should not see any errors here normally
1787    allcons = []
1788    for key in 'Hist','HAP','Phase':
1789        allcons += data[key]
1790    if not len(allcons): return
1791    G2mv.InitVars()   
1792    constDictList,fixedList,ignored = G2str.ProcessConstraints(allcons)
1793    errmsg, warnmsg = G2mv.CheckConstraints('',constDictList,fixedList)
1794    if errmsg:
1795        G2frame.ErrorDialog('Constraint Error','Error in constraints:\n'+errmsg,
1796            parent=G2frame.dataFrame)
1797    elif warnmsg:
1798        print 'Unexpected contraint warning:\n',warnmsg
1799       
1800################################################################################
1801#####  Restraints
1802################################################################################           
1803       
1804def UpdateRestraints(G2frame,data,Phases,phaseName):
1805    if not len(Phases):
1806        print 'There are no phases to form restraints'
1807        return
1808    phasedata = Phases[phaseName]
1809    if phaseName not in data:
1810        data[phaseName] = {}
1811    restrData = data[phaseName]
1812    if 'Bond' not in restrData:
1813        restrData['Bond'] = {'wtFactor':1.0,'Bonds':[],'Use':True}
1814    if 'Angle' not in restrData:
1815        restrData['Angle'] = {'wtFactor':1.0,'Angles':[],'Use':True}
1816    if 'Plane' not in restrData:
1817        restrData['Plane'] = {'wtFactor':1.0,'Planes':[],'Use':True}
1818    if 'Chiral' not in restrData:
1819        restrData['Chiral'] = {'wtFactor':1.0,'Volumes':[],'Use':True}
1820   
1821    def OnSelectPhase(event):
1822        dlg = wx.SingleChoiceDialog(G2frame,'Select','Phase',Phases.keys())
1823        try:
1824            if dlg.ShowModal() == wx.ID_OK:
1825                phaseName = Phases.keys()[dlg.GetSelection()]
1826                UpdateRestraints(G2frame,data,Phases,phaseName)
1827        finally:
1828            dlg.Destroy()
1829   
1830    def OnAddRestraint(event):
1831        page = G2frame.dataDisplay.GetSelection()
1832        if 'Bond' in G2frame.dataDisplay.GetPageText(page):
1833            AddBondRestraint()
1834        elif 'Angle' in G2frame.dataDisplay.GetPageText(page):
1835            AddAngleRestraint()
1836        elif 'Plane' in G2frame.dataDisplay.GetPageText(page):
1837            AddPlaneRestraint()
1838        elif 'Chiral' in G2frame.dataDisplay.GetPageText(page):
1839            AddChiralRestraint()
1840           
1841    def AddBondRestraint():
1842        print 'Bond restraint'
1843
1844    def AddAngleRestraint():
1845        print 'Angle restraint'
1846
1847    def AddPlaneRestraint():
1848        print 'Plane restraint'
1849
1850    def AddChiralRestraint():
1851        print 'Chiral restraint'
1852       
1853    def WtBox(wind,restData):
1854       
1855        def OnWtFactor(event):
1856            try:
1857                value = float(wtfactor.GetValue())
1858            except ValueError:
1859                value = 1.0
1860            restData['wtFactor'] = value
1861            wtfactor.SetValue('%.2f'%(value))
1862           
1863        def OnUseData(event):
1864            restData['Use'] = Obj.GetValue()
1865
1866        wtBox = wx.BoxSizer(wx.HORIZONTAL)
1867        wtBox.Add(wx.StaticText(wind,-1,'Restraint weight factor:'),0,wx.ALIGN_CENTER_VERTICAL)
1868        wtfactor = wx.TextCtrl(wind,-1,value='%.2f'%(restData['wtFactor']),style=wx.TE_PROCESS_ENTER)
1869        wtfactor.Bind(wx.EVT_TEXT_ENTER,OnWtFactor)
1870        wtfactor.Bind(wx.EVT_KILL_FOCUS,OnWtFactor)
1871        wtBox.Add(wtfactor,0,wx.ALIGN_CENTER_VERTICAL)
1872        useData = wx.CheckBox(wind,-1,label=' Use?')
1873        useData.Bind(wx.EVT_CHECKBOX, OnUseData)
1874        useData.SetValue(restData['Use'])       
1875        wtBox.Add(useData,0,wx.ALIGN_CENTER_VERTICAL)
1876        return wtBox
1877       
1878    def UpdateBondRestr(bondRestData):
1879       
1880        def OnColSort(event):
1881            r,c = event.GetRow(),event.GetCol()
1882            if r < 0 and c == 0:
1883                names = G2mth.sortArray(table,0)
1884                bonds = []
1885                for name in names:
1886                    idx = table.index(name)
1887                    bonds.append(bondList[idx])
1888                bondRestData['Bonds'] = bonds
1889                UpdateBondRestr(bondRestData)               
1890       
1891        def OnChangeValue(event):
1892            rows = Bonds.GetSelectedRows()
1893            if not rows:
1894                return
1895            Bonds.ClearSelection()
1896            val = bondList[rows[0]][4]
1897            dlg = G2phG.SingleFloatDialog(G2frame,'New value','Enter new value for bond',val,[0.,5.])
1898            if dlg.ShowModal() == wx.ID_OK:
1899                parm = dlg.GetValue()
1900                for r in rows:
1901                    bondList[r][4] = parm
1902            dlg.Destroy()
1903            UpdateBondRestr(bondRestData)               
1904
1905        def OnChangeEsd(event):
1906            rows = Bonds.GetSelectedRows()
1907            if not rows:
1908                return
1909            Bonds.ClearSelection()
1910            val = bondList[rows[0]][5]
1911            dlg = G2phG.SingleFloatDialog(G2frame,'New value','Enter new esd for bond',val,[0.,1.])
1912            if dlg.ShowModal() == wx.ID_OK:
1913                parm = dlg.GetValue()
1914                for r in rows:
1915                    bondList[r][5] = parm
1916            dlg.Destroy()
1917            UpdateBondRestr(bondRestData)               
1918                               
1919        def OnDeleteRestraint(event):
1920            rows = Bonds.GetSelectedRows()
1921            if not rows:
1922                return
1923            Bonds.ClearSelection()
1924            rows.sort()
1925            rows.reverse()
1926            for row in rows:
1927                bondList.remove(bondList[row])
1928            UpdateBondRestr(bondRestData)               
1929           
1930        BondRestr.DestroyChildren()
1931        dataDisplay = wx.Panel(BondRestr)
1932        mainSizer = wx.BoxSizer(wx.VERTICAL)
1933        mainSizer.Add((5,5),0)
1934        mainSizer.Add(WtBox(BondRestr,bondRestData),0,wx.ALIGN_CENTER_VERTICAL)
1935
1936        bondList = bondRestData['Bonds']
1937        if len(bondList):
1938            table = []
1939            rowLabels = []
1940            colLabels = ['A+SymOp  B+SymOp','d-calc','d-obs','esd']
1941            Types = [wg.GRID_VALUE_STRING,]+3*[wg.GRID_VALUE_FLOAT+':10,3',]
1942            for i,[atoms,ops,indx,dcalc,dobs,esd] in enumerate(bondList):
1943                table.append([atoms[0]+'+ ('+ops[0]+')  '+atoms[1]+'+ ('+ops[1]+')',dcalc,dobs,esd])
1944                rowLabels.append(str(i))
1945            bondTable = Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
1946            Bonds = GSGrid(BondRestr)
1947            Bonds.SetTable(bondTable, True)
1948            Bonds.AutoSizeColumns(False)
1949            for r in range(len(bondList)):
1950                for c in range(2):
1951                    Bonds.SetReadOnly(r,c,True)
1952                    Bonds.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
1953            Bonds.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK,OnColSort)
1954            G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=wxID_RESTDELETE)
1955            G2frame.dataFrame.Bind(wx.EVT_MENU, OnChangeValue, id=wxID_RESRCHANGEVAL)
1956            G2frame.dataFrame.Bind(wx.EVT_MENU, OnChangeEsd, id=wxID_RESTCHANGEESD)
1957            mainSizer.Add(Bonds,0,)
1958        else:
1959            mainSizer.Add(wx.StaticText(BondRestr,-1,'No bond distance restraints for this phase'),0,)
1960
1961        BondRestr.SetSizer(mainSizer)
1962        Size = mainSizer.Fit(G2frame.dataFrame)
1963        Size[0] += 5
1964        Size[1] += 25       #make room for tab
1965        BondRestr.SetSize(Size)
1966        G2frame.dataFrame.setSizePosLeft(Size)
1967       
1968    def UpdateAngleRestr(angleRestData):
1969       
1970        def OnColSort(event):
1971            r,c = event.GetRow(),event.GetCol()
1972            if r < 0 and c == 0:
1973                names = G2mth.sortArray(table,0)
1974                angles = []
1975                for name in names:
1976                    idx = table.index(name)
1977                    angles.append(angleList[idx])
1978                angleRestData['Angles'] = angles
1979                UpdateAngleRestr(angleRestData)               
1980       
1981        def OnChangeValue(event):
1982            rows = Angles.GetSelectedRows()
1983            if not rows:
1984                return
1985            Angles.ClearSelection()
1986            val = angleList[rows[0]][4]
1987            dlg = G2phG.SingleFloatDialog(G2frame,'New value','Enter new value for angle',val,[0.,360.])
1988            if dlg.ShowModal() == wx.ID_OK:
1989                parm = dlg.GetValue()
1990                for r in rows:
1991                    angleList[r][4] = parm
1992            dlg.Destroy()
1993            UpdateAngleRestr(angleRestData)               
1994
1995        def OnChangeEsd(event):
1996            rows = Angles.GetSelectedRows()
1997            if not rows:
1998                return
1999            Angles.ClearSelection()
2000            val = angleList[rows[0]][5]
2001            dlg = G2phG.SingleFloatDialog(G2frame,'New value','Enter new esd for angle',val,[0.,5.])
2002            if dlg.ShowModal() == wx.ID_OK:
2003                parm = dlg.GetValue()
2004                for r in rows:
2005                    angleList[r][5] = parm
2006            dlg.Destroy()
2007            UpdateAngleRestr(angleRestData)               
2008                                           
2009        def OnDeleteRestraint(event):
2010            rows = Angles.GetSelectedRows()
2011            if not rows:
2012                return
2013            rows.sort()
2014            rows.reverse()
2015            for row in rows:
2016                angleList.remove(angleList[row])
2017            UpdateAngleRestr(angleRestData)               
2018           
2019        AngleRestr.DestroyChildren()
2020        dataDisplay = wx.Panel(AngleRestr)
2021        mainSizer = wx.BoxSizer(wx.VERTICAL)
2022        mainSizer.Add((5,5),0)
2023        mainSizer.Add(WtBox(AngleRestr,angleRestData),0,wx.ALIGN_CENTER_VERTICAL)
2024
2025        angleList = angleRestData['Angles']
2026        if len(angleList):
2027            table = []
2028            rowLabels = []
2029            colLabels = ['A+SymOp  B+SymOp  C+SymOp','calc','obs','esd']
2030            Types = [wg.GRID_VALUE_STRING,]+3*[wg.GRID_VALUE_FLOAT+':10,2',]
2031            for i,[atoms,ops,indx,dcalc,dobs,esd] in enumerate(angleList):
2032                table.append([atoms[0]+'+ ('+ops[0]+')  '+atoms[1]+'+ ('+ops[1]+')  '+atoms[2]+ \
2033                '+ ('+ops[2]+')',dcalc,dobs,esd])
2034                rowLabels.append(str(i))
2035            angleTable = Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
2036            Angles = GSGrid(AngleRestr)
2037            Angles.SetTable(angleTable, True)
2038            Angles.AutoSizeColumns(False)
2039            for r in range(len(angleList)):
2040                for c in range(2):
2041                    Angles.SetReadOnly(r,c,True)
2042                    Angles.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
2043            Angles.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK,OnColSort)
2044            G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=wxID_RESTDELETE)
2045            G2frame.dataFrame.Bind(wx.EVT_MENU, OnChangeValue, id=wxID_RESRCHANGEVAL)
2046            G2frame.dataFrame.Bind(wx.EVT_MENU, OnChangeEsd, id=wxID_RESTCHANGEESD)
2047            mainSizer.Add(Angles,0,)
2048        else:
2049            mainSizer.Add(wx.StaticText(AngleRestr,-1,'No bond angle restraints for this phase'),0,)
2050
2051        AngleRestr.SetSizer(mainSizer)
2052        Size = mainSizer.Fit(G2frame.dataFrame)
2053        Size[0] += 5
2054        Size[1] += 25       #make room for tab
2055        AngleRestr.SetSize(Size)
2056        G2frame.dataFrame.setSizePosLeft(Size)
2057   
2058    def UpdatePlaneRestr(planeRestData):
2059       
2060        items = G2frame.dataFrame.RestraintEdit.GetMenuItems()
2061        for item in items:
2062            if item.GetLabel() in ['Change value']:
2063                item.Enable(False)
2064
2065        def OnDeleteRestraint(event):
2066            rows = Planes.GetSelectedRows()
2067            if not rows:
2068                return
2069            rows.sort()
2070            rows.reverse()
2071            for row in rows:
2072                planeList.remove(planeList[row])
2073            UpdatePlaneRestr(planeRestData)               
2074           
2075        PlaneRestr.DestroyChildren()
2076        dataDisplay = wx.Panel(PlaneRestr)
2077        mainSizer = wx.BoxSizer(wx.VERTICAL)
2078        mainSizer.Add((5,5),0)
2079        mainSizer.Add(WtBox(PlaneRestr,planeRestData),0,wx.ALIGN_CENTER_VERTICAL)
2080
2081        planeList = planeRestData['Planes']
2082        if len(planeList):
2083            table = []
2084            rowLabels = []
2085            colLabels = ['atom+SymOp','calc','obs','esd']
2086            Types = [wg.GRID_VALUE_STRING,]+3*[wg.GRID_VALUE_FLOAT+':10,2',]
2087            for i,[atoms,ops,indx,dcalc,dobs,esd] in enumerate(planeList):
2088                atString = ''
2089                for a,atom in enumerate(atoms):
2090                    atString += atom+'+ ('+ops[a]+'),'
2091                    if (a+1)%3 == 0:
2092                        atString += '\n'
2093                table.append([atString[:-1],dcalc,dobs,esd])
2094                rowLabels.append(str(i))
2095            planeTable = Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
2096            Planes = GSGrid(PlaneRestr)
2097            Planes.SetTable(planeTable, True)
2098            Planes.AutoSizeColumns(False)
2099            Planes.AutoSizeRows(False)
2100            for r in range(len(planeList)):
2101                for c in range(3):
2102                    Planes.SetReadOnly(r,c,True)
2103                    Planes.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
2104            G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=wxID_RESTDELETE)
2105            mainSizer.Add(Planes,0,)
2106        else:
2107            mainSizer.Add(wx.StaticText(PlaneRestr,-1,'No plane restraints for this phase'),0,)
2108
2109        PlaneRestr.SetSizer(mainSizer)
2110        Size = mainSizer.Fit(G2frame.dataFrame)
2111        Size[0] += 5
2112        Size[1] += 25       #make room for tab
2113        PlaneRestr.SetSize(Size)
2114        G2frame.dataFrame.setSizePosLeft(Size)
2115   
2116    def UpdateChiralRestr(chiralRestData):
2117
2118        def OnDeleteRestraint(event):
2119            rows = Volumes.GetSelectedRows()
2120            if not rows:
2121                return
2122            rows.sort()
2123            rows.reverse()
2124            for row in rows:
2125                volumeList.remove(volumeList[row])
2126            UpdateChiralRestr(chiralRestData)               
2127           
2128        ChiralRestr.DestroyChildren()
2129        dataDisplay = wx.Panel(ChiralRestr)
2130        mainSizer = wx.BoxSizer(wx.VERTICAL)
2131        mainSizer.Add((5,5),0)
2132        mainSizer.Add(WtBox(ChiralRestr,chiralRestData),0,wx.ALIGN_CENTER_VERTICAL)
2133
2134        volumeList = chiralRestData['Volumes']
2135        if len(volumeList):
2136            table = []
2137            rowLabels = []
2138            colLabels = ['O+SymOp  A+SymOp  B+SymOp  C+SymOp','calc','obs','esd']
2139            Types = [wg.GRID_VALUE_STRING,]+3*[wg.GRID_VALUE_FLOAT+':10,2',]
2140            for i,[atoms,ops,indx,dcalc,dobs,esd] in enumerate(volumeList):
2141                table.append([atoms[0]+'+ ('+ops[0]+') '+atoms[1]+'+ ('+ops[1]+') '+atoms[2]+ \
2142                '+ ('+ops[2]+') '+atoms[3]+'+ ('+ops[3]+')',dcalc,dobs,esd])
2143                rowLabels.append(str(i))
2144            volumeTable = Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
2145            Volumes = GSGrid(ChiralRestr)
2146            Volumes.SetTable(volumeTable, True)
2147            Volumes.AutoSizeColumns(False)
2148            for r in range(len(volumeList)):
2149                for c in range(2):
2150                    Volumes.SetReadOnly(r,c,True)
2151                    Volumes.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
2152            G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteRestraint, id=wxID_RESTDELETE)
2153            mainSizer.Add(Volumes,0,)
2154        else:
2155            mainSizer.Add(wx.StaticText(ChiralRestr,-1,'No chiral volume restraints for this phase'),0,)
2156
2157        ChiralRestr.SetSizer(mainSizer)
2158        Size = mainSizer.Fit(G2frame.dataFrame)
2159        Size[0] += 5
2160        Size[1] += 25       #make room for tab
2161        ChiralRestr.SetSize(Size)
2162        G2frame.dataFrame.setSizePosLeft(Size)
2163   
2164    def OnPageChanged(event):
2165        page = event.GetSelection()
2166        text = G2frame.dataDisplay.GetPageText(page)
2167        if text == 'Bond restraints':
2168            SetDataMenuBar(G2frame,G2frame.dataFrame.RestraintMenu)
2169            bondRestData = restrData['Bond']
2170            UpdateBondRestr(bondRestData)
2171        elif text == 'Angle restraints':
2172            SetDataMenuBar(G2frame,G2frame.dataFrame.RestraintMenu)
2173            angleRestData = restrData['Angle']
2174            UpdateAngleRestr(angleRestData)
2175        elif text == 'Plane restraints':
2176            SetDataMenuBar(G2frame,G2frame.dataFrame.RestraintMenu)
2177            planeRestData = restrData['Plane']
2178            UpdatePlaneRestr(planeRestData)
2179        elif text == 'Chiral restraints':
2180            SetDataMenuBar(G2frame,G2frame.dataFrame.RestraintMenu)
2181            chiralRestData = restrData['Chiral']
2182            UpdateChiralRestr(chiralRestData)
2183        event.Skip()
2184
2185    if G2frame.dataDisplay:
2186        G2frame.dataDisplay.Destroy()
2187       
2188    SetDataMenuBar(G2frame,G2frame.dataFrame.RestraintMenu)
2189    G2frame.dataFrame.SetLabel('restraints for '+phaseName)
2190    G2frame.dataFrame.RestraintEdit.Enable(wxID_RESTSELPHASE,False)
2191    if len(Phases) > 1:
2192        G2frame.dataFrame.RestraintEdit.Enable(wxID_RESTSELPHASE,True)
2193        G2frame.dataFrame.Bind(wx.EVT_MENU, OnSelectPhase, id=wxID_RESTSELPHASE)
2194    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddRestraint, id=wxID_RESTRAINTADD)
2195    G2frame.dataDisplay = GSNoteBook(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize())
2196   
2197    BondRestr = wx.ScrolledWindow(G2frame.dataDisplay)
2198    G2frame.dataDisplay.AddPage(BondRestr,'Bond restraints')
2199    AngleRestr = wx.ScrolledWindow(G2frame.dataDisplay)
2200    G2frame.dataDisplay.AddPage(AngleRestr,'Angle restraints')
2201    PlaneRestr = wx.ScrolledWindow(G2frame.dataDisplay)
2202    G2frame.dataDisplay.AddPage(PlaneRestr,'Plane restraints')
2203    ChiralRestr = wx.ScrolledWindow(G2frame.dataDisplay)
2204    G2frame.dataDisplay.AddPage(ChiralRestr,'Chiral restraints')
2205    UpdateBondRestr(restrData['Bond'])
2206
2207    G2frame.dataDisplay.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, OnPageChanged)
2208   
2209################################################################################
2210#####  Main PWDR panel
2211################################################################################           
2212       
2213def UpdatePWHKPlot(G2frame,kind,item):
2214
2215    def OnErrorAnalysis(event):
2216        G2plt.PlotDeltSig(G2frame,kind)
2217       
2218    def OnWtFactor(event):
2219        try:
2220            val = float(wtval.GetValue())
2221        except ValueError:
2222            val = data[0]['wtFactor']
2223        data[0]['wtFactor'] = val
2224        wtval.SetValue('%.3f'%(val))
2225           
2226    data = G2frame.PatternTree.GetItemPyData(item)
2227    if 'wtFactor' not in data[0]:
2228        data[0] = {'wtFactor':1.0}
2229    if G2frame.dataDisplay:
2230        G2frame.dataDisplay.Destroy()
2231    SetDataMenuBar(G2frame,G2frame.dataFrame.ErrorMenu)
2232    G2frame.dataFrame.Bind(wx.EVT_MENU,OnErrorAnalysis, id=wxID_PWDANALYSIS)
2233    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
2234   
2235    mainSizer = wx.BoxSizer(wx.VERTICAL)
2236    mainSizer.Add((5,5),)
2237    wtSizer = wx.BoxSizer(wx.HORIZONTAL)
2238    wtSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Weight factor: '),0,wx.ALIGN_CENTER_VERTICAL)
2239    wtval = wx.TextCtrl(G2frame.dataDisplay,-1,'%.3f'%(data[0]['wtFactor']),style=wx.TE_PROCESS_ENTER)
2240    wtval.Bind(wx.EVT_TEXT_ENTER,OnWtFactor)
2241    wtval.Bind(wx.EVT_KILL_FOCUS,OnWtFactor)
2242    wtSizer.Add(wtval,0,wx.ALIGN_CENTER_VERTICAL)
2243    mainSizer.Add(wtSizer)
2244    mainSizer.Layout()   
2245    G2frame.dataDisplay.SetSizer(mainSizer)
2246    G2frame.dataFrame.setSizePosLeft(mainSizer.Fit(G2frame.dataFrame))
2247    G2frame.PatternTree.SetItemPyData(item,data)
2248    if kind == 'PWDR':
2249        G2plt.PlotPatterns(G2frame,newPlot=True)
2250    elif kind == 'HKLF':
2251        G2plt.PlotSngl(G2frame,newPlot=True)
2252                 
2253################################################################################
2254#####  HKLF controls
2255################################################################################           
2256       
2257def UpdateHKLControls(G2frame,data):
2258   
2259    def OnScaleSlider(event):
2260        scale = int(scaleSel.GetValue())/1000.
2261        scaleSel.SetValue(int(scale*1000.))
2262        data['Scale'] = scale*10.
2263        G2plt.PlotSngl(G2frame)
2264       
2265    def OnLayerSlider(event):
2266        layer = layerSel.GetValue()
2267        data['Layer'] = layer
2268        G2plt.PlotSngl(G2frame)
2269       
2270    def OnSelZone(event):
2271        data['Zone'] = zoneSel.GetValue()
2272        izone = zones.index(data['Zone'])
2273        layerSel.SetRange(maxValue=HKLmax[izone],minValue=HKLmin[izone])
2274        G2plt.PlotSngl(G2frame,newPlot=True)
2275       
2276    def OnSelType(event):
2277        data['Type'] = typeSel.GetValue()
2278        G2plt.PlotSngl(G2frame)
2279       
2280    def SetStatusLine():
2281        Status.SetStatusText("")
2282                                     
2283    if G2frame.dataDisplay:
2284        G2frame.dataDisplay.Destroy()
2285    if not G2frame.dataFrame.GetStatusBar():
2286        Status = G2frame.dataFrame.CreateStatusBar()
2287    SetStatusLine()
2288    zones = ['100','010','001']
2289    HKLmax = data['HKLmax']
2290    HKLmin = data['HKLmin']
2291    if data['ifFc']:
2292        typeChoices = ['Fosq','Fo','|DFsq|/sig','|DFsq|>sig','|DFsq|>3sig']
2293    else:
2294        typeChoices = ['Fosq','Fo']
2295    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
2296    SetDataMenuBar(G2frame)
2297    G2frame.dataFrame.SetTitle('HKL Plot Controls')
2298    mainSizer = wx.BoxSizer(wx.VERTICAL)
2299    mainSizer.Add((5,10),0)
2300   
2301    scaleSizer = wx.BoxSizer(wx.HORIZONTAL)
2302    scaleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Scale'),0,
2303        wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
2304    scaleSel = wx.Slider(parent=G2frame.dataDisplay,maxValue=1000,minValue=1,
2305        style=wx.SL_HORIZONTAL,value=int(data['Scale']*100))
2306    scaleSizer.Add(scaleSel,1,wx.EXPAND|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
2307    scaleSel.SetLineSize(10)
2308    scaleSel.SetPageSize(10)
2309    scaleSel.Bind(wx.EVT_SLIDER, OnScaleSlider)
2310    mainSizer.Add(scaleSizer,0,wx.EXPAND|wx.RIGHT)
2311    mainSizer.Add((0,10),0)   
2312   
2313    zoneSizer = wx.BoxSizer(wx.HORIZONTAL)
2314    zoneSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Zone  '),0,
2315        wx.ALIGN_CENTER_VERTICAL)
2316    zoneSel = wx.ComboBox(parent=G2frame.dataDisplay,value=data['Zone'],choices=['100','010','001'],
2317        style=wx.CB_READONLY|wx.CB_DROPDOWN)
2318    zoneSel.Bind(wx.EVT_COMBOBOX, OnSelZone)
2319    zoneSizer.Add(zoneSel,0,wx.ALIGN_CENTER_VERTICAL)
2320    zoneSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Plot type  '),0,
2321        wx.ALIGN_CENTER_VERTICAL)       
2322    typeSel = wx.ComboBox(parent=G2frame.dataDisplay,value=data['Type'],choices=typeChoices,
2323        style=wx.CB_READONLY|wx.CB_DROPDOWN)
2324    typeSel.Bind(wx.EVT_COMBOBOX, OnSelType)
2325    zoneSizer.Add(typeSel,0,wx.ALIGN_CENTER_VERTICAL)
2326    zoneSizer.Add((10,0),0)   
2327    mainSizer.Add(zoneSizer,0,wx.EXPAND|wx.RIGHT)
2328    mainSizer.Add((0,10),0)   
2329       
2330    izone = zones.index(data['Zone'])
2331    layerSizer = wx.BoxSizer(wx.HORIZONTAL)
2332    layerSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Layer'),0,
2333        wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
2334    layerSel = wx.Slider(parent=G2frame.dataDisplay,maxValue=HKLmax[izone],minValue=HKLmin[izone],
2335        style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS|wx.SL_LABELS,value=0)
2336    layerSel.SetLineSize(1)
2337    layerSel.SetPageSize(1)
2338    layerSel.Bind(wx.EVT_SLIDER, OnLayerSlider)   
2339    layerSizer.Add(layerSel,1,wx.EXPAND|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
2340    layerSizer.Add((10,0),0)   
2341    mainSizer.Add(layerSizer,1,wx.EXPAND|wx.RIGHT)
2342
2343       
2344    mainSizer.Layout()   
2345    G2frame.dataDisplay.SetSizer(mainSizer)
2346    G2frame.dataDisplay.SetSize(mainSizer.Fit(G2frame.dataFrame))
2347    G2frame.dataFrame.setSizePosLeft(mainSizer.Fit(G2frame.dataFrame))
2348
2349################################################################################
2350#####  Pattern tree routines
2351################################################################################           
2352       
2353def GetPatternTreeDataNames(G2frame,dataTypes):
2354    names = []
2355    item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)       
2356    while item:
2357        name = G2frame.PatternTree.GetItemText(item)
2358        if name[:4] in dataTypes:
2359            names.append(name)
2360        item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
2361    return names
2362                         
2363def GetPatternTreeItemId(G2frame, parentId, itemText):
2364    item, cookie = G2frame.PatternTree.GetFirstChild(parentId)
2365    while item:
2366        if G2frame.PatternTree.GetItemText(item) == itemText:
2367            return item
2368        item, cookie = G2frame.PatternTree.GetNextChild(parentId, cookie)
2369    return 0               
2370
2371def MovePatternTreeToGrid(G2frame,item):
2372   
2373#    print G2frame.PatternTree.GetItemText(item)
2374   
2375    oldPage = 0
2376    if G2frame.dataFrame:
2377        SetDataMenuBar(G2frame)
2378        if G2frame.dataFrame.GetLabel() == 'Comments':
2379            data = [G2frame.dataDisplay.GetValue()]
2380            G2frame.dataDisplay.Clear() 
2381            Id = GetPatternTreeItemId(G2frame,G2frame.root, 'Comments')
2382            if Id: G2frame.PatternTree.SetItemPyData(Id,data)
2383        elif G2frame.dataFrame.GetLabel() == 'Notebook':
2384            data = [G2frame.dataDisplay.GetValue()]
2385            G2frame.dataDisplay.Clear() 
2386            Id = GetPatternTreeItemId(G2frame,G2frame.root, 'Notebook')
2387            if Id: G2frame.PatternTree.SetItemPyData(Id,data)
2388        elif 'Phase Data for' in G2frame.dataFrame.GetLabel():
2389            if G2frame.dataDisplay: 
2390                oldPage = G2frame.dataDisplay.GetSelection()
2391        G2frame.dataFrame.Clear()
2392        G2frame.dataFrame.SetLabel('')
2393    else:
2394        #create the frame for the data item window
2395        G2frame.dataFrame = DataFrame(parent=G2frame.mainPanel,frame=G2frame)
2396
2397    G2frame.dataFrame.Raise()           
2398    G2frame.PickId = 0
2399    parentID = G2frame.root
2400    for i in G2frame.ExportPattern: i.Enable(False)
2401    defWid = [250,150]
2402    if item != G2frame.root:
2403        parentID = G2frame.PatternTree.GetItemParent(item)
2404    if G2frame.PatternTree.GetItemParent(item) == G2frame.root:
2405        G2frame.PatternId = item
2406        G2frame.PickId = item
2407        if G2frame.PatternTree.GetItemText(item) == 'Notebook':
2408            SetDataMenuBar(G2frame,G2frame.dataFrame.DataNotebookMenu)
2409            G2frame.PatternId = 0
2410            for i in G2frame.ExportPattern: i.Enable(False)
2411            data = G2frame.PatternTree.GetItemPyData(item)
2412            UpdateNotebook(G2frame,data)
2413        elif G2frame.PatternTree.GetItemText(item) == 'Controls':
2414            G2frame.PatternId = 0
2415            for i in G2frame.ExportPattern: i.Enable(False)
2416            data = G2frame.PatternTree.GetItemPyData(item)
2417            if not data:           #fill in defaults
2418                data = {
2419                    #least squares controls
2420                    'deriv type':'analytic Hessian','min dM/M':0.0001,'shift factor':1.0,'max cyc':3}
2421                G2frame.PatternTree.SetItemPyData(item,data)                             
2422            for i in G2frame.Refine: i.Enable(True)
2423            for i in G2frame.SeqRefine: i.Enable(True)
2424            UpdateControls(G2frame,data)
2425        elif G2frame.PatternTree.GetItemText(item) == 'Sequental results':
2426            data = G2frame.PatternTree.GetItemPyData(item)
2427            UpdateSeqResults(G2frame,data)           
2428        elif G2frame.PatternTree.GetItemText(item) == 'Covariance':
2429            data = G2frame.PatternTree.GetItemPyData(item)
2430            G2frame.dataFrame.setSizePosLeft(defWid)
2431            text = ''
2432            if 'Rvals' in data:
2433                Nvars = len(data['varyList'])
2434                Rvals = data['Rvals']
2435                text = '\nFinal residuals: \nRwp = %.3f%% \nchi**2 = %.1f \nGOF = %.2f'%(Rvals['Rwp'],Rvals['chisq'],Rvals['GOF'])
2436                text += '\nNobs = %d \nNvals = %d'%(Rvals['Nobs'],Nvars)
2437                if 'lamMax' in Rvals:
2438                    text += '\nlog10 MaxLambda = %.1f'%(np.log10(Rvals['lamMax']))
2439            wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
2440                value='See plot window for covariance display'+text,style=wx.TE_MULTILINE)
2441            G2plt.PlotCovariance(G2frame)
2442        elif G2frame.PatternTree.GetItemText(item) == 'Constraints':
2443            data = G2frame.PatternTree.GetItemPyData(item)
2444            UpdateConstraints(G2frame,data)
2445        elif G2frame.PatternTree.GetItemText(item) == 'Restraints':
2446            data = G2frame.PatternTree.GetItemPyData(item)
2447            Phases = G2frame.GetPhaseData()
2448            phase = ''
2449            phaseName = ''
2450            if Phases:
2451                phaseName = Phases.keys()[0]
2452            UpdateRestraints(G2frame,data,Phases,phaseName)
2453        elif 'IMG' in G2frame.PatternTree.GetItemText(item):
2454            G2frame.Image = item
2455            G2plt.PlotImage(G2frame,newPlot=True)
2456        elif 'PKS' in G2frame.PatternTree.GetItemText(item):
2457            G2plt.PlotPowderLines(G2frame)
2458        elif 'PWDR' in G2frame.PatternTree.GetItemText(item):
2459            for i in G2frame.ExportPattern: i.Enable(True)
2460            UpdatePWHKPlot(G2frame,'PWDR',item)
2461        elif 'HKLF' in G2frame.PatternTree.GetItemText(item):
2462            G2frame.Sngl = item
2463            UpdatePWHKPlot(G2frame,'HKLF',item)
2464        elif 'PDF' in G2frame.PatternTree.GetItemText(item):
2465            G2frame.PatternId = item
2466            for i in G2frame.ExportPDF: i.Enable(True)
2467            G2plt.PlotISFG(G2frame,type='S(Q)')
2468        elif G2frame.PatternTree.GetItemText(item) == 'Phases':
2469            G2frame.dataFrame.setSizePosLeft(defWid)
2470            wx.TextCtrl(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize(),
2471                value='Select one phase to see its parameters')           
2472    elif 'I(Q)' in G2frame.PatternTree.GetItemText(item):
2473        G2frame.PickId = item
2474        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2475        G2plt.PlotISFG(G2frame,type='I(Q)',newPlot=True)
2476    elif 'S(Q)' in G2frame.PatternTree.GetItemText(item):
2477        G2frame.PickId = item
2478        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2479        G2plt.PlotISFG(G2frame,type='S(Q)',newPlot=True)
2480    elif 'F(Q)' in G2frame.PatternTree.GetItemText(item):
2481        G2frame.PickId = item
2482        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2483        G2plt.PlotISFG(G2frame,type='F(Q)',newPlot=True)
2484    elif 'G(R)' in G2frame.PatternTree.GetItemText(item):
2485        G2frame.PickId = item
2486        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2487        G2plt.PlotISFG(G2frame,type='G(R)',newPlot=True)           
2488    elif G2frame.PatternTree.GetItemText(parentID) == 'Phases':
2489        G2frame.PickId = item
2490        data = G2frame.PatternTree.GetItemPyData(item)
2491        G2phG.UpdatePhaseData(G2frame,item,data,oldPage)
2492    elif G2frame.PatternTree.GetItemText(item) == 'Comments':
2493        SetDataMenuBar(G2frame,G2frame.dataFrame.DataCommentsMenu)
2494        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2495        G2frame.PickId = item
2496        data = G2frame.PatternTree.GetItemPyData(item)
2497        UpdateComments(G2frame,data)
2498    elif G2frame.PatternTree.GetItemText(item) == 'Image Controls':
2499        G2frame.dataFrame.SetTitle('Image Controls')
2500        G2frame.PickId = item
2501        G2frame.Image = G2frame.PatternTree.GetItemParent(item)
2502        masks = G2frame.PatternTree.GetItemPyData(
2503            GetPatternTreeItemId(G2frame,G2frame.Image, 'Masks'))
2504        data = G2frame.PatternTree.GetItemPyData(item)
2505        G2imG.UpdateImageControls(G2frame,data,masks)
2506        G2plt.PlotImage(G2frame)
2507    elif G2frame.PatternTree.GetItemText(item) == 'Masks':
2508        G2frame.dataFrame.SetTitle('Masks')
2509        G2frame.PickId = item
2510        G2frame.Image = G2frame.PatternTree.GetItemParent(item)
2511        data = G2frame.PatternTree.GetItemPyData(item)
2512        G2imG.UpdateMasks(G2frame,data)
2513        G2plt.PlotImage(G2frame)
2514    elif G2frame.PatternTree.GetItemText(item) == 'Stress/Strain':
2515        G2frame.dataFrame.SetTitle('Stress/Strain')
2516        G2frame.PickId = item
2517        G2frame.Image = G2frame.PatternTree.GetItemParent(item)
2518        data = G2frame.PatternTree.GetItemPyData(item)
2519        G2imG.UpdateStressStrain(G2frame,data)
2520        G2plt.PlotImage(G2frame)
2521    elif G2frame.PatternTree.GetItemText(item) == 'HKL Plot Controls':
2522        G2frame.PickId = item
2523        G2frame.Sngl = G2frame.PatternTree.GetItemParent(item)
2524        data = G2frame.PatternTree.GetItemPyData(item)
2525        UpdateHKLControls(G2frame,data)
2526        G2plt.PlotSngl(G2frame)
2527    elif G2frame.PatternTree.GetItemText(item) == 'PDF Controls':
2528        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2529        for i in G2frame.ExportPDF: i.Enable(True)
2530        G2frame.PickId = item
2531        data = G2frame.PatternTree.GetItemPyData(item)
2532        G2pdG.UpdatePDFGrid(G2frame,data)
2533        G2plt.PlotISFG(G2frame,type='I(Q)')
2534        G2plt.PlotISFG(G2frame,type='S(Q)')
2535        G2plt.PlotISFG(G2frame,type='F(Q)')
2536        G2plt.PlotISFG(G2frame,type='G(R)')
2537    elif G2frame.PatternTree.GetItemText(item) == 'Peak List':
2538        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2539        for i in G2frame.ExportPeakList: i.Enable(True)
2540        G2frame.PickId = item
2541        data = G2frame.PatternTree.GetItemPyData(item)
2542        G2pdG.UpdatePeakGrid(G2frame,data)
2543        G2plt.PlotPatterns(G2frame)
2544    elif G2frame.PatternTree.GetItemText(item) == 'Background':
2545        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2546        G2frame.PickId = item
2547        data = G2frame.PatternTree.GetItemPyData(item)
2548        G2pdG.UpdateBackground(G2frame,data)
2549        G2plt.PlotPatterns(G2frame)
2550    elif G2frame.PatternTree.GetItemText(item) == 'Limits':
2551        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2552        G2frame.PickId = item
2553        data = G2frame.PatternTree.GetItemPyData(item)
2554        G2pdG.UpdateLimitsGrid(G2frame,data)
2555        G2plt.PlotPatterns(G2frame)
2556    elif G2frame.PatternTree.GetItemText(item) == 'Instrument Parameters':
2557        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2558        G2frame.PickId = item
2559        data = G2frame.PatternTree.GetItemPyData(item)
2560        G2pdG.UpdateInstrumentGrid(G2frame,data)
2561        G2plt.PlotPeakWidths(G2frame)
2562    elif G2frame.PatternTree.GetItemText(item) == 'Sample Parameters':
2563        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2564        G2frame.PickId = item
2565        data = G2frame.PatternTree.GetItemPyData(item)
2566
2567        if 'Temperature' not in data:           #temp fix for old gpx files
2568            data = {'Scale':[1.0,True],'Type':'Debye-Scherrer','Absorption':[0.0,False],'DisplaceX':[0.0,False],
2569                'DisplaceY':[0.0,False],'Diffuse':[],'Temperature':300.,'Pressure':1.0,'Humidity':0.0,'Voltage':0.0,
2570                'Force':0.0,'Gonio. radius':200.0}
2571            G2frame.PatternTree.SetItemPyData(item,data)
2572   
2573        G2pdG.UpdateSampleGrid(G2frame,data)
2574        G2plt.PlotPatterns(G2frame)
2575    elif G2frame.PatternTree.GetItemText(item) == 'Index Peak List':
2576        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2577        for i in G2frame.ExportPeakList: i.Enable(True)
2578        G2frame.PickId = item
2579        data = G2frame.PatternTree.GetItemPyData(item)
2580        G2pdG.UpdateIndexPeaksGrid(G2frame,data)
2581        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2582            G2plt.PlotPowderLines(G2frame)
2583        else:
2584            G2plt.PlotPatterns(G2frame)
2585    elif G2frame.PatternTree.GetItemText(item) == 'Unit Cells List':
2586        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2587        G2frame.PickId = item
2588        data = G2frame.PatternTree.GetItemPyData(item)
2589        if not data:
2590            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
2591            data.append([0,0,0,0,0,0,0,0,0,0,0,0,0,0])      #Bravais lattice flags
2592            data.append([])                                 #empty cell list
2593            data.append([])                                 #empty dmin
2594            G2frame.PatternTree.SetItemPyData(item,data)                             
2595        G2pdG.UpdateUnitCellsGrid(G2frame,data)
2596        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2597            G2plt.PlotPowderLines(G2frame)
2598        else:
2599            G2plt.PlotPatterns(G2frame)
2600    elif G2frame.PatternTree.GetItemText(item) == 'Reflection Lists':   #powder reflections
2601        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2602        G2frame.PickId = item
2603        data = G2frame.PatternTree.GetItemPyData(item)
2604        G2frame.RefList = ''
2605        if len(data):
2606            G2frame.RefList = data.keys()[0]
2607        G2pdG.UpdateReflectionGrid(G2frame,data)
2608        G2plt.PlotPatterns(G2frame)
2609    elif G2frame.PatternTree.GetItemText(item) == 'Reflection List':    #HKLF reflections
2610        G2frame.PatternId = G2frame.PatternTree.GetItemParent(item)
2611        name = G2frame.PatternTree.GetItemText(G2frame.PatternId)
2612        data = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)
2613        G2pdG.UpdateReflectionGrid(G2frame,data,HKLF=True,Name=name)
2614
2615def SetDataMenuBar(G2frame,menu=None):
2616        '''Set the menu for the data frame. On the Mac put this
2617        menu for the data tree window instead.
2618
2619        Note that data frame items do not have menus, for these (menu=None)
2620        display a blank menu or on the Mac display the standard menu for
2621        the data tree window.
2622        '''
2623        if sys.platform == "darwin":
2624            if menu is None:
2625                G2frame.SetMenuBar(G2frame.GSASIIMenu)
2626            else:
2627                G2frame.SetMenuBar(menu)
2628        else:
2629            if menu is None:
2630                G2frame.dataFrame.SetMenuBar(G2frame.dataFrame.BlankMenu)
2631            else:
2632                G2frame.dataFrame.SetMenuBar(menu)
Note: See TracBrowser for help on using the repository browser.