@@ -445,7 +445,9 @@ def __init__(self,parent,loc,key,nDig=None,notBlank=True,xmin=None,xmax=None,
445445 else :
446446 self .invalid = False
447447 self .Bind (wx .EVT_CHAR ,self ._GetStringValue )
448-
448+ # Mac is "special" because backspace etc. does not trigger validator
449+ if sys .platform == "darwin" :
450+ self .Bind (wx .EVT_KEY_DOWN ,self .OnKeyDown )
449451 # When the mouse is moved away or the widget loses focus,
450452 # display the last saved value, if an expression
451453 self .Bind (wx .EVT_LEAVE_WINDOW , self ._onLeaveWindow )
@@ -549,7 +551,7 @@ def OnKeyDown(self,event):
549551 'Special callback for wx 2.9+ on Mac where backspace is not processed by validator'
550552 key = event .GetKeyCode ()
551553 if key in [wx .WXK_BACK , wx .WXK_DELETE ]:
552- if self . Validator : wx .CallAfter (self .Validator . TestValid , self )
554+ wx .CallAfter (self ._TestValidity )
553555 if key == wx .WXK_RETURN or key == wx .WXK_NUMPAD_ENTER :
554556 self ._onLoseFocus (None )
555557 if event : event .Skip ()
@@ -562,24 +564,30 @@ def _onStringKey(self,event):
562564 wx .CallAfter (self .ShowStringValidity ,True ) # was invalid
563565 else :
564566 wx .CallAfter (self .ShowStringValidity ,False ) # was valid
565-
567+
568+ def _TestValidity (self ):
569+ 'Check validity and change colors accordingly'
570+ if self .Validator :
571+ self .Validator .TestValid (self )
572+ self ._IndicateValidity ()
573+
566574 def _IndicateValidity (self ):
567575 'Set the control colors to show invalid input'
568576 if self .invalid :
569577 ins = self .GetInsertionPoint ()
570578 self .SetForegroundColour ("red" )
571579 self .SetBackgroundColour ("yellow" )
572- if not sys .platform .startswith ("linux" ):
573- self .SetFocus ()
580+ # if not sys.platform.startswith("linux"):
581+ # self.SetFocus() # was needed -- now seems to cause problems
574582 self .Refresh () # this selects text on some Linuxes
575583 self .SetSelection (0 ,0 ) # unselect
576584 self .SetInsertionPoint (ins ) # put insertion point back
577585 else : # valid input
578586 self .SetBackgroundColour (wx .SystemSettings .GetColour (wx .SYS_COLOUR_WINDOW ))
579587 self .SetForegroundColour (wx .SystemSettings .GetColour (wx .SYS_COLOUR_BTNTEXT ))
580588 self .Refresh ()
581- if not sys .platform .startswith ("linux" ):
582- self .SetFocus () # seems needed, at least on MacOS to get color change
589+ # if not sys.platform.startswith("linux"):
590+ # self.SetFocus() # seems needed, at least on MacOS to get color change
583591
584592 def _GetNumValue (self ):
585593 'Get and where needed convert string from GetValue into int or float'
@@ -631,10 +639,7 @@ def _SaveStringValue(self):
631639 except RuntimeError : # ignore if control has been deleted
632640 return
633641 # always store the result
634- if self .CIFinput and '2' in platform .python_version_tuple ()[0 ]: # Py2/CIF make results ASCII
635- self .result [self .key ] = val .encode ('ascii' ,'replace' )
636- else :
637- self .result [self .key ] = val
642+ self .result [self .key ] = val
638643
639644 def _onLeaveWindow (self ,event ):
640645 '''If the mouse leaves the text box, save the result, if valid,
@@ -647,10 +652,12 @@ def delayedUpdate():
647652 self ._setValue (self .result [self .key ])
648653 except :
649654 pass
655+ # ignore mouse crusing
656+ if self .result [self .key ] == self .GetValue (): # .IsModified() seems unreliable
657+ return
650658 if self .type is not str :
651659 if not self .IsModified (): return #ignore mouse crusing
652- elif self .result [self .key ] == self .GetValue (): # .IsModified() seems unreliable for str
653- return
660+ wx .CallAfter (self ._TestValidity ) # entry changed, test/show validity
654661 if self .evaluated and not self .invalid : # deal with computed expressions
655662 if self .timer :
656663 self .timer .Restart (self .delay )
@@ -671,17 +678,19 @@ def _onLoseFocus(self,event):
671678 Evaluate and update the current control contents
672679 '''
673680 if event : event .Skip ()
681+ # ignore mouse crusing
682+ if self .result [self .key ] == self .GetValue (): # .IsModified() seems unreliable
683+ return
674684 if self .type is not str :
675685 if not self .IsModified (): return #ignore mouse crusing
676- elif self .result [self .key ] == self .GetValue (): # .IsModified() seems unreliable for str
677- return
686+ wx .CallAfter (self ._TestValidity ) # entry changed, test/show validity
678687 if self .evaluated : # deal with computed expressions
679688 if self .invalid : # don't substitute for an invalid expression
680689 return
681690 self ._setValue (self .result [self .key ])
682691 elif self .result is not None : # show formatted result, as Bob wants
683- self .result [self .key ] = self ._GetNumValue ()
684692 if not self .invalid : # don't update an invalid expression
693+ self .result [self .key ] = self ._GetNumValue ()
685694 self ._setValue (self .result [self .key ])
686695
687696 if self .OnLeave :
@@ -930,10 +939,7 @@ def TestValid(self,tc):
930939 :param wx.TextCtrl tc: A reference to the TextCtrl that the validator
931940 is associated with.
932941 '''
933- if '2' in platform .python_version_tuple ()[0 ]:
934- self .result [self .key ] = tc .GetValue ().encode ('ascii' ,'replace' )
935- else :
936- self .result [self .key ] = tc .GetValue ()
942+ self .result [self .key ] = tc .GetValue ()
937943
938944 def OnChar (self , event ):
939945 '''Called each type a key is pressed
@@ -10129,6 +10135,80 @@ def SelectPkgInstall(event):
1012910135 print ('exiting GSAS-II' )
1013010136 sys .exit ()
1013110137
10138+ def StringSearchTemplate (parent ,title ,prompt ,start ,help = None ):
10139+ '''Dialog to obtain a single string value from user
10140+
10141+ :param wx.Frame parent: name of parent frame
10142+ :param str title: title string for dialog
10143+ :param str prompt: string to tell use what they are inputting
10144+ :param str start: default input value, if any
10145+ :param str help: if supplied, a help button is added to the dialog that
10146+ can be used to display the supplied help text/URL for setting this
10147+ variable. (Default is '', which is ignored.)
10148+ '''
10149+ def on_invalid ():
10150+ G2MessageBox (parent ,
10151+ 'The pattern must retain some non-blank characters from the original string. Resetting so you can start again.' ,'Try again' )
10152+ valItem .SetValue (start )
10153+ return
10154+ def on_char_typed (event ):
10155+ keycode = event .GetKeyCode ()
10156+ if keycode == 32 or keycode == 63 : # ' ' or '?' - replace with '?'
10157+ #has a range been selected?
10158+ sel = valItem .GetSelection ()
10159+ if sel [0 ] == sel [1 ]:
10160+ insertion_point = valItem .GetInsertionPoint ()
10161+ sel = (insertion_point ,insertion_point + 1 )
10162+ for i in range (* sel ):
10163+ valItem .Replace (i , i + 1 , '?' )
10164+ # Move the insertion point forward one character
10165+ valItem .SetInsertionPoint (i + 1 )
10166+ # make sure some characters remain
10167+ if len (valItem .GetValue ().replace ('?' ,'' ).strip ()) == 0 :
10168+ wx .CallAfter (on_invalid )
10169+ event .Skip (False )
10170+ elif keycode >= wx .WXK_SPACE : # anything else printable, ignore
10171+ event .Skip (False )
10172+ else : # arrows etc are processed naturally
10173+ event .Skip (True )
10174+ dlg = wx .Dialog (parent ,wx .ID_ANY ,title ,pos = wx .DefaultPosition ,
10175+ style = wx .DEFAULT_DIALOG_STYLE | wx .RESIZE_BORDER )
10176+ dlg .CenterOnParent ()
10177+ mainSizer = wx .BoxSizer (wx .VERTICAL )
10178+ sizer1 = wx .BoxSizer (wx .HORIZONTAL )
10179+ txt = wx .StaticText (dlg ,wx .ID_ANY ,prompt )
10180+ sizer1 .Add ((10 ,- 1 ),1 ,wx .EXPAND )
10181+ txt .Wrap (500 )
10182+ sizer1 .Add (txt ,0 ,wx .ALIGN_CENTER )
10183+ sizer1 .Add ((10 ,- 1 ),1 ,wx .EXPAND )
10184+ if help :
10185+ sizer1 .Add (HelpButton (dlg ,help ),0 ,wx .ALL )
10186+ mainSizer .Add (sizer1 ,0 ,wx .EXPAND )
10187+ sizer1 = wx .BoxSizer (wx .HORIZONTAL )
10188+ valItem = wx .TextCtrl (dlg ,wx .ID_ANY ,value = start ,style = wx .TE_PROCESS_ENTER )
10189+ valItem .Bind (wx .EVT_CHAR , on_char_typed )
10190+ valItem .Bind (wx .EVT_TEXT_ENTER , lambda event : event .Skip (False ))
10191+ wx .CallAfter (valItem .SetSelection ,0 ,0 ) # clear the initial selection
10192+ mainSizer .Add (valItem ,1 ,wx .EXPAND )
10193+ btnsizer = wx .StdDialogButtonSizer ()
10194+ OKbtn = wx .Button (dlg , wx .ID_OK )
10195+ OKbtn .SetDefault ()
10196+ btnsizer .AddButton (OKbtn )
10197+ btn = wx .Button (dlg , wx .ID_CANCEL )
10198+ btnsizer .AddButton (btn )
10199+ btnsizer .Realize ()
10200+ mainSizer .Add (btnsizer ,0 ,wx .ALIGN_CENTER )
10201+ dlg .SetSizer (mainSizer )
10202+ mainSizer .Fit (dlg )
10203+ ans = dlg .ShowModal ()
10204+ if ans != wx .ID_OK :
10205+ dlg .Destroy ()
10206+ return
10207+ else :
10208+ val = valItem .GetValue ()
10209+ dlg .Destroy ()
10210+ return val
10211+
1013210212if __name__ == '__main__' :
1013310213 app = wx .App ()
1013410214 GSASIIpath .InvokeDebugOpts ()
0 commit comments