Added new MaskedEditControl code from Will Sadkin. The modules are
now locaed in their own sub-package, wx.lib.masked. Demos updated. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@26874 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
		| @@ -4,9 +4,8 @@ import  sys | ||||
| import  traceback | ||||
|  | ||||
| import  wx | ||||
| import  wx.lib.maskededit       as  med | ||||
| import  wx.lib.maskedctrl       as  mctl | ||||
| import  wx.lib.scrolledpanel    as  scroll | ||||
| import  wx.lib.masked             as  masked | ||||
| import  wx.lib.scrolledpanel      as  scroll | ||||
|  | ||||
|  | ||||
| class demoMixin: | ||||
| @@ -18,7 +17,7 @@ class demoMixin: | ||||
|         mask        = wx.StaticText( self, -1, "Mask Value" ) | ||||
|         formatcode  = wx.StaticText( self, -1, "Format" ) | ||||
|         regex       = wx.StaticText( self, -1, "Regexp Validator(opt.)" ) | ||||
|         ctrl        = wx.StaticText( self, -1, "MaskedTextCtrl" ) | ||||
|         ctrl        = wx.StaticText( self, -1, "Masked TextCtrl" ) | ||||
|  | ||||
|         description.SetFont( wx.Font(9, wx.SWISS, wx.NORMAL, wx.BOLD)) | ||||
|         mask.SetFont( wx.Font(9, wx.SWISS, wx.NORMAL, wx.BOLD)) | ||||
| @@ -41,7 +40,7 @@ class demoMixin: | ||||
|             sizer.Add( wx.StaticText( self, -1, control[4]) ) | ||||
|  | ||||
|             if control in controls: | ||||
|                 newControl  = med.MaskedTextCtrl( self, -1, "", | ||||
|                 newControl  = masked.TextCtrl( self, -1, "", | ||||
|                                                 mask         = control[1], | ||||
|                                                 excludeChars = control[2], | ||||
|                                                 formatcodes  = control[3], | ||||
| @@ -79,7 +78,7 @@ class demoPage1(scroll.ScrolledPanel, demoMixin): | ||||
|         self.editList  = [] | ||||
|  | ||||
|         label = wx.StaticText( self, -1, """\ | ||||
| Here are some basic MaskedTextCtrls to give you an idea of what you can do | ||||
| Here are some basic masked TextCtrls to give you an idea of what you can do | ||||
| with this control.  Note that all controls have been auto-sized by including 'F' in | ||||
| the format codes. | ||||
|  | ||||
| @@ -152,8 +151,8 @@ class demoPage2(scroll.ScrolledPanel, demoMixin): | ||||
|  | ||||
|         label = wx.StaticText( self, -1, """\ | ||||
| All these controls have been created by passing a single parameter, the autoformat code, | ||||
| and use the factory class MaskedCtrl with its default controlType. | ||||
| The maskededit module contains an internal dictionary of types and formats (autoformats). | ||||
| and use the factory class masked.Ctrl with its default controlType. | ||||
| The masked package contains an internal dictionary of types and formats (autoformats). | ||||
| Many of these already do complicated validation; To see some examples, try | ||||
| 29 Feb 2002 vs. 2004 for the date formats, or email address validation. | ||||
| """) | ||||
| @@ -163,7 +162,7 @@ Many of these already do complicated validation; To see some examples, try | ||||
|  | ||||
|         description = wx.StaticText( self, -1, "Description") | ||||
|         autofmt     = wx.StaticText( self, -1, "AutoFormat Code") | ||||
|         ctrl        = wx.StaticText( self, -1, "MaskedCtrl") | ||||
|         ctrl        = wx.StaticText( self, -1, "Masked Ctrl") | ||||
|  | ||||
|         description.SetFont( wx.Font( 9, wx.SWISS, wx.NORMAL, wx.BOLD ) ) | ||||
|         autofmt.SetFont( wx.Font( 9, wx.SWISS, wx.NORMAL, wx.BOLD ) ) | ||||
| @@ -174,10 +173,10 @@ Many of these already do complicated validation; To see some examples, try | ||||
|         grid.Add( autofmt,     0, wx.ALIGN_LEFT ) | ||||
|         grid.Add( ctrl,        0, wx.ALIGN_LEFT ) | ||||
|  | ||||
|         for autoformat, desc in med.autoformats: | ||||
|         for autoformat, desc in masked.autoformats: | ||||
|             grid.Add( wx.StaticText( self, -1, desc), 0, wx.ALIGN_LEFT ) | ||||
|             grid.Add( wx.StaticText( self, -1, autoformat), 0, wx.ALIGN_LEFT ) | ||||
|             grid.Add( mctl.MaskedCtrl( self, -1, "", | ||||
|             grid.Add( masked.Ctrl( self, -1, "", | ||||
|                                     autoformat       = autoformat, | ||||
|                                     demo             = True, | ||||
|                                     name             = autoformat), | ||||
| @@ -197,7 +196,7 @@ class demoPage3(scroll.ScrolledPanel, demoMixin): | ||||
|         self.editList  = [] | ||||
|  | ||||
|         label = wx.StaticText( self, -1, """\ | ||||
| Here MaskedTextCtrls that have default values.  The states | ||||
| Here masked TextCtrls that have default values.  The states | ||||
| control has a list of valid values, and the unsigned integer | ||||
| has a legal range specified. | ||||
| """) | ||||
| @@ -215,7 +214,7 @@ has a legal range specified. | ||||
|  | ||||
|         controls = [ | ||||
|         #description        mask                    excl format     regexp                              range,list,initial | ||||
|        ("U.S. State (2 char)",      "AA",            "", 'F!_',       "[A-Z]{2}",                         '',med.states, med.states[0]), | ||||
|        ("U.S. State (2 char)",      "AA",            "", 'F!_',       "[A-Z]{2}",                         '', masked.states, masked.states[0]), | ||||
|        ("Integer (signed)",         "#{6}",          "", 'F-_',       "",                                 '','', ' 0    '), | ||||
|        ("Integer (unsigned)\n(1-399)","######",      "", 'F_',        "",                                 (1,399),'', '1     '), | ||||
|        ("Float (signed)",           "#{6}.#{9}",     "", 'F-_R',      "",                                 '','', '000000.000000000'), | ||||
| @@ -256,7 +255,7 @@ Page Up and Shift-Up arrow will similarly cycle backwards through the list. | ||||
|         description  = wx.StaticText( self, -1, "Description" ) | ||||
|         autofmt      = wx.StaticText( self, -1, "AutoFormat Code" ) | ||||
|         fields       = wx.StaticText( self, -1, "Field Objects" ) | ||||
|         ctrl         = wx.StaticText( self, -1, "MaskedTextCtrl" ) | ||||
|         ctrl         = wx.StaticText( self, -1, "Masked TextCtrl" ) | ||||
|  | ||||
|         description.SetFont( wx.Font( 9, wx.SWISS, wx.NORMAL, wx.BOLD ) ) | ||||
|         autofmt.SetFont( wx.Font( 9, wx.SWISS, wx.NORMAL, wx.BOLD ) ) | ||||
| @@ -270,7 +269,7 @@ Page Up and Shift-Up arrow will similarly cycle backwards through the list. | ||||
|         grid.Add( ctrl,        0, wx.ALIGN_LEFT ) | ||||
|  | ||||
|         autoformat = "USPHONEFULLEXT" | ||||
|         fieldsDict = {0: med.Field(choices=["617","781","508","978","413"], choiceRequired=True)} | ||||
|         fieldsDict = {0: masked.Field(choices=["617","781","508","978","413"], choiceRequired=True)} | ||||
|         fieldsLabel = """\ | ||||
| {0: Field(choices=[ | ||||
|             "617","781", | ||||
| @@ -279,7 +278,7 @@ Page Up and Shift-Up arrow will similarly cycle backwards through the list. | ||||
|         grid.Add( wx.StaticText( self, -1, "Restricted Area Code"), 0, wx.ALIGN_LEFT ) | ||||
|         grid.Add( wx.StaticText( self, -1, autoformat), 0, wx.ALIGN_LEFT ) | ||||
|         grid.Add( wx.StaticText( self, -1, fieldsLabel), 0, wx.ALIGN_LEFT ) | ||||
|         grid.Add( med.MaskedTextCtrl( self, -1, "", | ||||
|         grid.Add( masked.TextCtrl( self, -1, "", | ||||
|                                     autoformat       = autoformat, | ||||
|                                     fields           = fieldsDict, | ||||
|                                     demo             = True, | ||||
| @@ -287,12 +286,12 @@ Page Up and Shift-Up arrow will similarly cycle backwards through the list. | ||||
|                   0, wx.ALIGN_LEFT ) | ||||
|  | ||||
|         autoformat = "EXPDATEMMYY" | ||||
|         fieldsDict = {1: med.Field(choices=["03", "04", "05"], choiceRequired=True)} | ||||
|         fieldsDict = {1: masked.Field(choices=["03", "04", "05"], choiceRequired=True)} | ||||
|         fieldsLabel = """\ | ||||
| {1: Field(choices=[ | ||||
|             "03", "04", "05"], | ||||
|           choiceRequired=True)}""" | ||||
|         exp =  med.MaskedTextCtrl( self, -1, "", | ||||
|         exp =  masked.TextCtrl( self, -1, "", | ||||
|                                  autoformat       = autoformat, | ||||
|                                  fields           = fieldsDict, | ||||
|                                  demo             = True, | ||||
| @@ -303,15 +302,15 @@ Page Up and Shift-Up arrow will similarly cycle backwards through the list. | ||||
|         grid.Add( wx.StaticText( self, -1, fieldsLabel), 0, wx.ALIGN_LEFT ) | ||||
|         grid.Add( exp, 0, wx.ALIGN_LEFT ) | ||||
|  | ||||
|         fieldsDict = {0: med.Field(choices=["02134","02155"], choiceRequired=True), | ||||
|                       1: med.Field(choices=["1234", "5678"],  choiceRequired=False)} | ||||
|         fieldsDict = {0: masked.Field(choices=["02134","02155"], choiceRequired=True), | ||||
|                       1: masked.Field(choices=["1234", "5678"],  choiceRequired=False)} | ||||
|         fieldsLabel = """\ | ||||
| {0: Field(choices=["02134","02155"], | ||||
|           choiceRequired=True), | ||||
|  1: Field(choices=["1234", "5678"], | ||||
|           choiceRequired=False)}""" | ||||
|         autoformat = "USZIPPLUS4" | ||||
|         zip =  med.MaskedTextCtrl( self, -1, "", | ||||
|         zip =  masked.TextCtrl( self, -1, "", | ||||
|                                  autoformat       = autoformat, | ||||
|                                  fields           = fieldsDict, | ||||
|                                  demo             = True, | ||||
| @@ -336,7 +335,7 @@ class demoPage5(scroll.ScrolledPanel, demoMixin): | ||||
|  | ||||
|  | ||||
|         labelMaskedCombos = wx.StaticText( self, -1, """\ | ||||
| These are some examples of MaskedComboBox:""") | ||||
| These are some examples of masked.ComboBox:""") | ||||
|         labelMaskedCombos.SetForegroundColour( "Blue" ) | ||||
|  | ||||
|  | ||||
| @@ -344,8 +343,8 @@ These are some examples of MaskedComboBox:""") | ||||
| A state selector; only | ||||
| "legal" values can be | ||||
| entered:""") | ||||
|         statecode = med.MaskedComboBox( self, -1, med.states[0], | ||||
|                                   choices = med.states, | ||||
|         statecode = masked.ComboBox( self, -1, masked.states[0], | ||||
|                                   choices = masked.states, | ||||
|                                   autoformat="USSTATE") | ||||
|  | ||||
|         label_statename = wx.StaticText( self, -1, """\ | ||||
| @@ -353,9 +352,9 @@ A state name selector, | ||||
| with auto-select:""") | ||||
|  | ||||
|         # Create this one using factory function: | ||||
|         statename = mctl.MaskedCtrl( self, -1, med.state_names[0], | ||||
|                                   controlType = mctl.controlTypes.MASKEDCOMBO, | ||||
|                                   choices = med.state_names, | ||||
|         statename = masked.Ctrl( self, -1, masked.state_names[0], | ||||
|                                   controlType = masked.controlTypes.COMBO, | ||||
|                                   choices = masked.state_names, | ||||
|                                   autoformat="USSTATENAME", | ||||
|                                   autoSelect=True) | ||||
|         statename.SetCtrlParameters(formatcodes = 'F!V_') | ||||
| @@ -363,8 +362,8 @@ with auto-select:""") | ||||
|  | ||||
|         numerators = [ str(i) for i in range(1, 4) ] | ||||
|         denominators = [ string.ljust(str(i), 2) for i in [2,3,4,5,8,16,32,64] ] | ||||
|         fieldsDict = {0: med.Field(choices=numerators, choiceRequired=False), | ||||
|                       1: med.Field(choices=denominators, choiceRequired=True)} | ||||
|         fieldsDict = {0: masked.Field(choices=numerators, choiceRequired=False), | ||||
|                       1: masked.Field(choices=denominators, choiceRequired=True)} | ||||
|         choices = [] | ||||
|         for n in numerators: | ||||
|             for d in denominators: | ||||
| @@ -377,8 +376,8 @@ A masked ComboBox for fraction selection. | ||||
| Choices for each side of the fraction can | ||||
| be selected with PageUp/Down:""") | ||||
|  | ||||
|         fraction = mctl.MaskedCtrl( self, -1, "", | ||||
|                                  controlType = mctl.MASKEDCOMBO, | ||||
|         fraction = masked.Ctrl( self, -1, "", | ||||
|                                  controlType = masked.controlTypes.COMBO, | ||||
|                                  choices = choices, | ||||
|                                  choiceRequired = True, | ||||
|                                  mask = "#/##", | ||||
| @@ -392,7 +391,7 @@ A masked ComboBox to validate | ||||
| text from a list of numeric codes:""") | ||||
|  | ||||
|         choices = ["91", "136", "305", "4579"] | ||||
|         code = med.MaskedComboBox( self, -1, choices[0], | ||||
|         code = masked.ComboBox( self, -1, choices[0], | ||||
|                                  choices = choices, | ||||
|                                  choiceRequired = True, | ||||
|                                  formatcodes = "F_r", | ||||
| @@ -402,8 +401,8 @@ text from a list of numeric codes:""") | ||||
| Programmatically set | ||||
| choice sets:""") | ||||
|         self.list_selector = wx.ComboBox(self, -1, '', choices = ['list1', 'list2', 'list3']) | ||||
|         self.dynamicbox = mctl.MaskedCtrl( self, -1, '    ', | ||||
|                                       controlType = mctl.controlTypes.MASKEDCOMBO, | ||||
|         self.dynamicbox = masked.Ctrl( self, -1, '    ', | ||||
|                                       controlType = masked.controlTypes.COMBO, | ||||
|                                       mask =    'XXXX', | ||||
|                                       formatcodes = 'F_', | ||||
|                                       # these are to give dropdown some initial height, | ||||
| @@ -415,23 +414,23 @@ choice sets:""") | ||||
|  | ||||
|  | ||||
|         labelIpAddrs = wx.StaticText( self, -1, """\ | ||||
| Here are some examples of IpAddrCtrl, a control derived from MaskedTextCtrl:""") | ||||
| Here are some examples of IpAddrCtrl, a control derived from masked.TextCtrl:""") | ||||
|         labelIpAddrs.SetForegroundColour( "Blue" ) | ||||
|  | ||||
|  | ||||
|         label_ipaddr1 = wx.StaticText( self, -1, "An empty control:") | ||||
|         ipaddr1 = med.IpAddrCtrl( self, -1, style = wx.TE_PROCESS_TAB ) | ||||
|         ipaddr1 = masked.IpAddrCtrl( self, -1, style = wx.TE_PROCESS_TAB ) | ||||
|  | ||||
|  | ||||
|         label_ipaddr2 = wx.StaticText( self, -1, "A restricted mask:") | ||||
|         ipaddr2 = med.IpAddrCtrl( self, -1, mask=" 10.  1.109.###" ) | ||||
|         ipaddr2 = masked.IpAddrCtrl( self, -1, mask=" 10.  1.109.###" ) | ||||
|  | ||||
|  | ||||
|         label_ipaddr3 = wx.StaticText( self, -1, """\ | ||||
| A control with restricted legal values: | ||||
| 10. (1|2) . (129..255) . (0..255)""") | ||||
|         ipaddr3 = mctl.MaskedCtrl( self, -1, | ||||
|                                 controlType = mctl.controlTypes.IPADDR, | ||||
|         ipaddr3 = masked.Ctrl( self, -1, | ||||
|                                 controlType = masked.controlTypes.IPADDR, | ||||
|                                 mask=" 10.  #.###.###") | ||||
|         ipaddr3.SetFieldParameters(0, validRegex="1|2",validRequired=False )   # requires entry to match or not allowed | ||||
|  | ||||
| @@ -441,22 +440,22 @@ A control with restricted legal values: | ||||
|  | ||||
|  | ||||
|         labelNumerics = wx.StaticText( self, -1, """\ | ||||
| Here are some useful configurations of a MaskedTextCtrl for integer and floating point input that still treat | ||||
| the control as a text control.  (For a true numeric control, check out the MaskedNumCtrl class!)""") | ||||
| Here are some useful configurations of a masked.TextCtrl for integer and floating point input that still treat | ||||
| the control as a text control.  (For a true numeric control, check out the masked.NumCtrl class!)""") | ||||
|         labelNumerics.SetForegroundColour( "Blue" ) | ||||
|  | ||||
|         label_intctrl1 = wx.StaticText( self, -1, """\ | ||||
| An integer entry control with | ||||
| shifting insert enabled:""") | ||||
|         self.intctrl1 = med.MaskedTextCtrl(self, -1, name='intctrl', mask="#{9}", formatcodes = '_-,F>') | ||||
|         self.intctrl1 = masked.TextCtrl(self, -1, name='intctrl', mask="#{9}", formatcodes = '_-,F>') | ||||
|         label_intctrl2 = wx.StaticText( self, -1, """\ | ||||
|      Right-insert integer entry:""") | ||||
|         self.intctrl2 = med.MaskedTextCtrl(self, -1, name='intctrl', mask="#{9}", formatcodes = '_-,Fr') | ||||
|         self.intctrl2 = masked.TextCtrl(self, -1, name='intctrl', mask="#{9}", formatcodes = '_-,Fr') | ||||
|  | ||||
|         label_floatctrl = wx.StaticText( self, -1, """\ | ||||
| A floating point entry control | ||||
| with right-insert for ordinal:""") | ||||
|         self.floatctrl = med.MaskedTextCtrl(self, -1, name='floatctrl', mask="#{9}.#{2}", formatcodes="F,_-R", useParensForNegatives=False) | ||||
|         self.floatctrl = masked.TextCtrl(self, -1, name='floatctrl', mask="#{9}.#{2}", formatcodes="F,_-R", useParensForNegatives=False) | ||||
|         self.floatctrl.SetFieldParameters(0, formatcodes='r<', validRequired=True)  # right-insert, require explicit cursor movement to change fields | ||||
|         self.floatctrl.SetFieldParameters(1, defaultValue='00')                     # don't allow blank fraction | ||||
|  | ||||
| @@ -588,7 +587,7 @@ with right-insert for ordinal:""") | ||||
|             formatcodes += 'r' | ||||
|             mask = '###' | ||||
|         else: | ||||
|             choices = med.states | ||||
|             choices = masked.states | ||||
|             mask = 'AA' | ||||
|             formatcodes += '!' | ||||
|         self.dynamicbox.SetCtrlParameters( mask = mask, | ||||
| @@ -628,15 +627,15 @@ def runTest(frame, nb, log): | ||||
|  | ||||
| def RunStandalone(): | ||||
|     app = wx.PySimpleApp() | ||||
|     frame = wx.Frame(None, -1, "Test MaskedTextCtrl", size=(640, 480)) | ||||
|     frame = wx.Frame(None, -1, "Test MaskedEditCtrls", size=(640, 480)) | ||||
|     win = TestMaskedTextCtrls(frame, -1, sys.stdout) | ||||
|     frame.Show(True) | ||||
|     app.MainLoop() | ||||
| #---------------------------------------------------------------------------- | ||||
|  | ||||
| import wx.lib.masked.maskededit as maskededit | ||||
| overview = """<html> | ||||
| <PRE><FONT SIZE=-1> | ||||
| """ + med.__doc__ + """ | ||||
| """ + maskededit.__doc__ + """ | ||||
| </FONT></PRE> | ||||
| """ | ||||
|  | ||||
|   | ||||
| @@ -4,8 +4,8 @@ import  sys | ||||
| import  traceback | ||||
|  | ||||
| import  wx | ||||
| import  wx.lib.maskededit       as me | ||||
| import  wx.lib.maskednumctrl    as mnum | ||||
| from    wx.lib import masked | ||||
|  | ||||
| #---------------------------------------------------------------------- | ||||
|  | ||||
| class TestPanel( wx.Panel ): | ||||
| @@ -16,40 +16,40 @@ class TestPanel( wx.Panel ): | ||||
|         panel = wx.Panel( self, -1 ) | ||||
|  | ||||
|         header = wx.StaticText(panel, -1, """\ | ||||
| This shows the various options for MaskedNumCtrl. | ||||
| This shows the various options for masked.NumCtrl. | ||||
| The controls at the top reconfigure the resulting control at the bottom. | ||||
| """) | ||||
|         header.SetForegroundColour( "Blue" ) | ||||
|  | ||||
|         intlabel = wx.StaticText( panel, -1, "Integer width:" ) | ||||
|         self.integerwidth = mnum.MaskedNumCtrl( | ||||
|         self.integerwidth = masked.NumCtrl( | ||||
|                                 panel, value=10, integerWidth=2, allowNegative=False | ||||
|                                 ) | ||||
|  | ||||
|         fraclabel = wx.StaticText( panel, -1, "Fraction width:" ) | ||||
|         self.fractionwidth = mnum.MaskedNumCtrl( | ||||
|         self.fractionwidth = masked.NumCtrl( | ||||
|                                 panel, value=0, integerWidth=2, allowNegative=False | ||||
|                                 ) | ||||
|  | ||||
|         groupcharlabel = wx.StaticText( panel,-1, "Grouping char:" ) | ||||
|         self.groupchar = me.MaskedTextCtrl(  | ||||
|         self.groupchar = masked.TextCtrl( | ||||
|                                 panel, -1, value=',', mask='&', excludeChars = '-()', | ||||
|                                 formatcodes='F', emptyInvalid=True, validRequired=True | ||||
|                                 ) | ||||
|  | ||||
|         decimalcharlabel = wx.StaticText( panel,-1, "Decimal char:" ) | ||||
|         self.decimalchar = me.MaskedTextCtrl(  | ||||
|         self.decimalchar = masked.TextCtrl( | ||||
|                                 panel, -1, value='.', mask='&', excludeChars = '-()', | ||||
|                                 formatcodes='F', emptyInvalid=True, validRequired=True | ||||
|                                 ) | ||||
|  | ||||
|         self.set_min = wx.CheckBox( panel, -1, "Set minimum value:" ) | ||||
|         # Create this MaskedNumCtrl using factory, to show how: | ||||
|         self.min = mnum.MaskedNumCtrl( panel, integerWidth=5, fractionWidth=2 ) | ||||
|         # Create this masked.NumCtrl using factory, to show how: | ||||
|         self.min = masked.Ctrl( panel, integerWidth=5, fractionWidth=2, controlType=masked.controlTypes.NUMBER ) | ||||
|         self.min.Enable( False ) | ||||
|  | ||||
|         self.set_max = wx.CheckBox( panel, -1, "Set maximum value:" ) | ||||
|         self.max = mnum.MaskedNumCtrl( panel, integerWidth=5, fractionWidth=2 ) | ||||
|         self.max = masked.NumCtrl( panel, integerWidth=5, fractionWidth=2 ) | ||||
|         self.max.Enable( False ) | ||||
|  | ||||
|  | ||||
| @@ -68,7 +68,7 @@ The controls at the top reconfigure the resulting control at the bottom. | ||||
|         font.SetWeight(wx.BOLD) | ||||
|         label.SetFont(font) | ||||
|  | ||||
|         self.target_ctl = mnum.MaskedNumCtrl( panel, -1, name="target control" ) | ||||
|         self.target_ctl = masked.NumCtrl( panel, -1, name="target control" ) | ||||
|  | ||||
|         label_numselect = wx.StaticText( panel, -1, """\ | ||||
| Programmatically set the above | ||||
| @@ -141,15 +141,15 @@ value entry ctrl:""") | ||||
|         panel.Move( (50,10) ) | ||||
|         self.panel = panel | ||||
|  | ||||
|         self.Bind(mnum.EVT_MASKEDNUM, self.OnSetIntWidth, self.integerwidth ) | ||||
|         self.Bind(mnum.EVT_MASKEDNUM, self.OnSetFractionWidth, self.fractionwidth ) | ||||
|         self.Bind(masked.EVT_NUM, self.OnSetIntWidth, self.integerwidth ) | ||||
|         self.Bind(masked.EVT_NUM, self.OnSetFractionWidth, self.fractionwidth ) | ||||
|         self.Bind(wx.EVT_TEXT, self.OnSetGroupChar, self.groupchar ) | ||||
|         self.Bind(wx.EVT_TEXT, self.OnSetDecimalChar, self.decimalchar ) | ||||
|  | ||||
|         self.Bind(wx.EVT_CHECKBOX, self.OnSetMin, self.set_min ) | ||||
|         self.Bind(wx.EVT_CHECKBOX, self.OnSetMax, self.set_max ) | ||||
|         self.Bind(mnum.EVT_MASKEDNUM, self.SetTargetMinMax, self.min ) | ||||
|         self.Bind(mnum.EVT_MASKEDNUM, self.SetTargetMinMax, self.max ) | ||||
|         self.Bind(masked.EVT_NUM, self.SetTargetMinMax, self.min ) | ||||
|         self.Bind(masked.EVT_NUM, self.SetTargetMinMax, self.max ) | ||||
|  | ||||
|         self.Bind(wx.EVT_CHECKBOX, self.SetTargetMinMax, self.limit_target ) | ||||
|         self.Bind(wx.EVT_CHECKBOX, self.OnSetAllowNone, self.allow_none ) | ||||
| @@ -158,7 +158,7 @@ value entry ctrl:""") | ||||
|         self.Bind(wx.EVT_CHECKBOX, self.OnSetUseParens, self.use_parens ) | ||||
|         self.Bind(wx.EVT_CHECKBOX, self.OnSetSelectOnEntry, self.select_on_entry ) | ||||
|  | ||||
|         self.Bind(mnum.EVT_MASKEDNUM, self.OnTargetChange, self.target_ctl ) | ||||
|         self.Bind(masked.EVT_NUM, self.OnTargetChange, self.target_ctl ) | ||||
|         self.Bind(wx.EVT_COMBOBOX, self.OnNumberSelect, self.numselect ) | ||||
|  | ||||
|  | ||||
| @@ -323,6 +323,7 @@ def runTest( frame, nb, log ): | ||||
|     return win | ||||
|  | ||||
| #---------------------------------------------------------------------- | ||||
| import wx.lib.masked.numctrl as mnum | ||||
| overview = mnum.__doc__ | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|   | ||||
| @@ -4,9 +4,9 @@ | ||||
| # o presense of spin control causing probs (see spin ctrl demo for details) | ||||
| # | ||||
|  | ||||
| import  wx | ||||
| import  wx.lib.timectrl         as  timectl | ||||
| import  wx.lib.scrolledpanel    as  scrolled | ||||
| import wx | ||||
| import wx.lib.scrolledpanel    as scrolled | ||||
| import wx.lib.masked           as masked | ||||
|  | ||||
| #---------------------------------------------------------------------- | ||||
|  | ||||
| @@ -18,19 +18,19 @@ class TestPanel( scrolled.ScrolledPanel ): | ||||
|  | ||||
|  | ||||
|         text1 = wx.StaticText( self, -1, "12-hour format:") | ||||
|         self.time12 = timectl.TimeCtrl( self, -1, name="12 hour control" ) | ||||
|         self.time12 = masked.TimeCtrl( self, -1, name="12 hour control" ) | ||||
|         spin1 = wx.SpinButton( self, -1, wx.DefaultPosition, (-1,20), 0 ) | ||||
|         self.time12.BindSpinButton( spin1 ) | ||||
|  | ||||
|         text2 = wx.StaticText( self, -1, "24-hour format:") | ||||
|         spin2 = wx.SpinButton( self, -1, wx.DefaultPosition, (-1,20), 0 ) | ||||
|         self.time24 = timectl.TimeCtrl( | ||||
|         self.time24 = masked.TimeCtrl( | ||||
|                         self, -1, name="24 hour control", fmt24hr=True, | ||||
|                         spinButton = spin2 | ||||
|                         ) | ||||
|  | ||||
|         text3 = wx.StaticText( self, -1, "No seconds\nor spin button:") | ||||
|         self.spinless_ctrl = timectl.TimeCtrl( | ||||
|         self.spinless_ctrl = masked.TimeCtrl( | ||||
|                                 self, -1, name="spinless control", | ||||
|                                 display_seconds = False | ||||
|                                 ) | ||||
| @@ -86,17 +86,17 @@ class TestPanel( scrolled.ScrolledPanel ): | ||||
|         self.set_bounds = wx.CheckBox( self, -1, "Set time bounds:" ) | ||||
|  | ||||
|         minlabel = wx.StaticText( self, -1, "minimum time:" ) | ||||
|         self.min = timectl.TimeCtrl( self, -1, name="min", display_seconds = False ) | ||||
|         self.min = masked.TimeCtrl( self, -1, name="min", display_seconds = False ) | ||||
|         self.min.Enable( False ) | ||||
|  | ||||
|         maxlabel = wx.StaticText( self, -1, "maximum time:" ) | ||||
|         self.max = timectl.TimeCtrl( self, -1, name="max", display_seconds = False ) | ||||
|         self.max = masked.TimeCtrl( self, -1, name="max", display_seconds = False ) | ||||
|         self.max.Enable( False ) | ||||
|  | ||||
|         self.limit_check = wx.CheckBox( self, -1, "Limit control" ) | ||||
|  | ||||
|         label = wx.StaticText( self, -1, "Resulting time control:" ) | ||||
|         self.target_ctrl = timectl.TimeCtrl( self, -1, name="new" ) | ||||
|         self.target_ctrl = masked.TimeCtrl( self, -1, name="new" ) | ||||
|  | ||||
|         grid2 = wx.FlexGridSizer( 0, 2, 0, 0 ) | ||||
|         grid2.Add( (20, 0), 0, wx.ALIGN_LEFT|wx.ALL, 5 ) | ||||
| @@ -142,14 +142,14 @@ class TestPanel( scrolled.ScrolledPanel ): | ||||
|         self.SetupScrolling() | ||||
|  | ||||
|         self.Bind(wx.EVT_BUTTON, self.OnButtonClick, buttonChange ) | ||||
|         self.Bind(timectl.EVT_TIMEUPDATE, self.OnTimeChange, self.time12 ) | ||||
|         self.Bind(timectl.EVT_TIMEUPDATE, self.OnTimeChange, self.time24 ) | ||||
|         self.Bind(timectl.EVT_TIMEUPDATE, self.OnTimeChange, self.spinless_ctrl ) | ||||
|         self.Bind(masked.EVT_TIMEUPDATE, self.OnTimeChange, self.time12 ) | ||||
|         self.Bind(masked.EVT_TIMEUPDATE, self.OnTimeChange, self.time24 ) | ||||
|         self.Bind(masked.EVT_TIMEUPDATE, self.OnTimeChange, self.spinless_ctrl ) | ||||
|         self.Bind(wx.EVT_CHECKBOX, self.OnBoundsCheck, self.set_bounds ) | ||||
|         self.Bind(wx.EVT_CHECKBOX, self.SetTargetMinMax, self.limit_check ) | ||||
|         self.Bind(timectl.EVT_TIMEUPDATE, self.SetTargetMinMax, self.min ) | ||||
|         self.Bind(timectl.EVT_TIMEUPDATE, self.SetTargetMinMax, self.max ) | ||||
|         self.Bind(timectl.EVT_TIMEUPDATE, self.OnTimeChange, self.target_ctrl ) | ||||
|         self.Bind(masked.EVT_TIMEUPDATE, self.SetTargetMinMax, self.min ) | ||||
|         self.Bind(masked.EVT_TIMEUPDATE, self.SetTargetMinMax, self.max ) | ||||
|         self.Bind(masked.EVT_TIMEUPDATE, self.OnTimeChange, self.target_ctrl ) | ||||
|  | ||||
|  | ||||
|     def OnTimeChange( self, event ): | ||||
| @@ -204,7 +204,7 @@ class TestPanel( scrolled.ScrolledPanel ): | ||||
|             min, max = None, None | ||||
|  | ||||
|         cur_min, cur_max = self.target_ctrl.GetBounds() | ||||
|  | ||||
|         print cur_min, min | ||||
|         if min and (min != cur_min): self.target_ctrl.SetMin( min ) | ||||
|         if max and (max != cur_max): self.target_ctrl.SetMax( max ) | ||||
|  | ||||
| @@ -225,11 +225,11 @@ def runTest( frame, nb, log ): | ||||
|     return win | ||||
|  | ||||
| #---------------------------------------------------------------------- | ||||
|  | ||||
| import wx.lib.masked.timectrl as timectl | ||||
| overview = timectl.__doc__ | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     import sys,os | ||||
|     import run | ||||
|     run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) | ||||
|     run.main(['', os.path.basename(sys.argv[0])]) | ||||
|  | ||||
|   | ||||
| @@ -17,6 +17,9 @@ Added some convenience methods to wx.Bitmap: SetSize, GetSize, and | ||||
| wx.EmptyBitmap can be called with a wx.Size (or a 2-element sequence) | ||||
| object too.  Similar changes were done for wx.Image as well. | ||||
|  | ||||
| Added new MaskedEditControl code from Will Sadkin.  The modules are | ||||
| now locaed in their own sub-package, wx.lib.masked.  Demos updated. | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -619,6 +619,14 @@ Similarly, the wxSystemSettings backwards compatibiility aliases for | ||||
| GetSystemColour, GetSystemFont and GetSystemMetric have also gone into | ||||
| the bit-bucket.  Use GetColour, GetFont and GetMetric instead. | ||||
|  | ||||
| Use the Python True/False constants instead of the true, TRUE, false, | ||||
| FALSE that used to be provided with wxPython. | ||||
|  | ||||
| Use None instead of the ancient and should have been removed a long | ||||
| time ago wx.NULL alias. | ||||
|  | ||||
| wx.TreeCtrl no longer needs to be passed the cookie variable as the | ||||
| 2nd parameter.  It still returns it though, for use with GetNextChild. | ||||
|  | ||||
| The wx.NO_FULL_REPAINT_ON_RESIZE style is now the default style for | ||||
| all windows.  The name still exists for compatibility, but it is set | ||||
| @@ -667,3 +675,8 @@ functions in wxPython for parameters that are expecting an integer. | ||||
| If the object is not already an integer then it will be asked to | ||||
| convert itself to one.  A similar conversion fragment is in place for | ||||
| parameters that expect floating point values. | ||||
|  | ||||
| **[Changed in 2.5.1.6]**  The MaskedEditCtrl modules have been moved | ||||
| to their own sub-package, wx.lib.masked.  See the docstrings and demo | ||||
| for changes in capabilities, usage, etc. | ||||
|  | ||||
|   | ||||
							
								
								
									
										20
									
								
								wxPython/wx/lib/masked/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								wxPython/wx/lib/masked/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| #---------------------------------------------------------------------- | ||||
| # Name:        wxPython.lib.masked | ||||
| # Purpose:     A package containing the masked edit controls | ||||
| # | ||||
| # Author:      Will Sadkin, Jeff Childers | ||||
| # | ||||
| # Created:     6-Mar-2004 | ||||
| # RCS-ID:      $Id$ | ||||
| # Copyright:   (c) 2004 | ||||
| # License:     wxWidgets license | ||||
| #---------------------------------------------------------------------- | ||||
|  | ||||
| # import relevant external symbols into package namespace: | ||||
| from maskededit import * | ||||
| from textctrl   import BaseMaskedTextCtrl, TextCtrl | ||||
| from combobox   import BaseMaskedComboBox, ComboBox, MaskedComboBoxSelectEvent | ||||
| from numctrl    import NumCtrl, wxEVT_COMMAND_MASKED_NUMBER_UPDATED, EVT_NUM, NumberUpdatedEvent | ||||
| from timectrl   import TimeCtrl, wxEVT_TIMEVAL_UPDATED, EVT_TIMEUPDATE, TimeUpdatedEvent | ||||
| from ipaddrctrl import IpAddrCtrl | ||||
| from ctrl       import Ctrl, controlTypes | ||||
							
								
								
									
										540
									
								
								wxPython/wx/lib/masked/combobox.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										540
									
								
								wxPython/wx/lib/masked/combobox.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,540 @@ | ||||
| #---------------------------------------------------------------------------- | ||||
| # Name:         masked.combobox.py | ||||
| # Authors:      Will Sadkin | ||||
| # Email:        wsadkin@nameconnector.com | ||||
| # Created:      02/11/2003 | ||||
| # Copyright:    (c) 2003 by Will Sadkin, 2003 | ||||
| # RCS-ID:       $Id$ | ||||
| # License:      wxWidgets license | ||||
| #---------------------------------------------------------------------------- | ||||
| # | ||||
| # This masked edit class allows for the semantics of masked controls | ||||
| # to be applied to combo boxes. | ||||
| # | ||||
| #---------------------------------------------------------------------------- | ||||
|  | ||||
| import  wx | ||||
| from wx.lib.masked import * | ||||
|  | ||||
| # jmg 12/9/03 - when we cut ties with Py 2.2 and earlier, this would | ||||
| # be a good place to implement the 2.3 logger class | ||||
| from wx.tools.dbg import Logger | ||||
| dbg = Logger() | ||||
| ##dbg(enable=0) | ||||
|  | ||||
| ## ---------- ---------- ---------- ---------- ---------- ---------- ---------- | ||||
| ## Because calling SetSelection programmatically does not fire EVT_COMBOBOX | ||||
| ## events, we have to do it ourselves when we auto-complete. | ||||
| class MaskedComboBoxSelectEvent(wx.PyCommandEvent): | ||||
|     def __init__(self, id, selection = 0, object=None): | ||||
|         wx.PyCommandEvent.__init__(self, wx.wxEVT_COMMAND_COMBOBOX_SELECTED, id) | ||||
|  | ||||
|         self.__selection = selection | ||||
|         self.SetEventObject(object) | ||||
|  | ||||
|     def GetSelection(self): | ||||
|         """Retrieve the value of the control at the time | ||||
|         this event was generated.""" | ||||
|         return self.__selection | ||||
|  | ||||
|  | ||||
| class BaseMaskedComboBox( wx.ComboBox, MaskedEditMixin ): | ||||
|     """ | ||||
|     This masked edit control adds the ability to use a masked input | ||||
|     on a combobox, and do auto-complete of such values. | ||||
|     """ | ||||
|     def __init__( self, parent, id=-1, value = '', | ||||
|                   pos = wx.DefaultPosition, | ||||
|                   size = wx.DefaultSize, | ||||
|                   choices = [], | ||||
|                   style = wx.CB_DROPDOWN, | ||||
|                   validator = wx.DefaultValidator, | ||||
|                   name = "maskedComboBox", | ||||
|                   setupEventHandling = True,        ## setup event handling by default): | ||||
|                   **kwargs): | ||||
|  | ||||
|  | ||||
|         # This is necessary, because wxComboBox currently provides no | ||||
|         # method for determining later if this was specified in the | ||||
|         # constructor for the control... | ||||
|         self.__readonly = style & wx.CB_READONLY == wx.CB_READONLY | ||||
|  | ||||
|         kwargs['choices'] = choices                 ## set up maskededit to work with choice list too | ||||
|  | ||||
|         ## Since combobox completion is case-insensitive, always validate same way | ||||
|         if not kwargs.has_key('compareNoCase'): | ||||
|             kwargs['compareNoCase'] = True | ||||
|  | ||||
|         MaskedEditMixin.__init__( self, name, **kwargs ) | ||||
|  | ||||
|         self._choices = self._ctrl_constraints._choices | ||||
| ##        dbg('self._choices:', self._choices) | ||||
|  | ||||
|         if self._ctrl_constraints._alignRight: | ||||
|             choices = [choice.rjust(self._masklength) for choice in choices] | ||||
|         else: | ||||
|             choices = [choice.ljust(self._masklength) for choice in choices] | ||||
|  | ||||
|         wx.ComboBox.__init__(self, parent, id, value='', | ||||
|                             pos=pos, size = size, | ||||
|                             choices=choices, style=style|wx.WANTS_CHARS, | ||||
|                             validator=validator, | ||||
|                             name=name) | ||||
|  | ||||
|         self.controlInitialized = True | ||||
|  | ||||
|         # Set control font - fixed width by default | ||||
|         self._setFont() | ||||
|  | ||||
|         if self._autofit: | ||||
|             self.SetClientSize(self._CalcSize()) | ||||
|  | ||||
|         if value: | ||||
|             # ensure value is width of the mask of the control: | ||||
|             if self._ctrl_constraints._alignRight: | ||||
|                 value = value.rjust(self._masklength) | ||||
|             else: | ||||
|                 value = value.ljust(self._masklength) | ||||
|  | ||||
|         if self.__readonly: | ||||
|             self.SetStringSelection(value) | ||||
|         else: | ||||
|             self._SetInitialValue(value) | ||||
|  | ||||
|  | ||||
|         self._SetKeycodeHandler(wx.WXK_UP, self.OnSelectChoice) | ||||
|         self._SetKeycodeHandler(wx.WXK_DOWN, self.OnSelectChoice) | ||||
|  | ||||
|         if setupEventHandling: | ||||
|             ## Setup event handlers | ||||
|             self.Bind(wx.EVT_SET_FOCUS, self._OnFocus )         ## defeat automatic full selection | ||||
|             self.Bind(wx.EVT_KILL_FOCUS, self._OnKillFocus )    ## run internal validator | ||||
|             self.Bind(wx.EVT_LEFT_DCLICK, self._OnDoubleClick)  ## select field under cursor on dclick | ||||
|             self.Bind(wx.EVT_RIGHT_UP, self._OnContextMenu )    ## bring up an appropriate context menu | ||||
|             self.Bind(wx.EVT_CHAR, self._OnChar )               ## handle each keypress | ||||
|             self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown )         ## for special processing of up/down keys | ||||
|             self.Bind(wx.EVT_KEY_DOWN, self._OnKeyDown )        ## for processing the rest of the control keys | ||||
|                                                                 ## (next in evt chain) | ||||
|             self.Bind(wx.EVT_TEXT, self._OnTextChange )         ## color control appropriately & keep | ||||
|                                                                 ## track of previous value for undo | ||||
|  | ||||
|  | ||||
|  | ||||
|     def __repr__(self): | ||||
|         return "<MaskedComboBox: %s>" % self.GetValue() | ||||
|  | ||||
|  | ||||
|     def _CalcSize(self, size=None): | ||||
|         """ | ||||
|         Calculate automatic size if allowed; augment base mixin function | ||||
|         to account for the selector button. | ||||
|         """ | ||||
|         size = self._calcSize(size) | ||||
|         return (size[0]+20, size[1]) | ||||
|  | ||||
|  | ||||
|     def _GetSelection(self): | ||||
|         """ | ||||
|         Allow mixin to get the text selection of this control. | ||||
|         REQUIRED by any class derived from MaskedEditMixin. | ||||
|         """ | ||||
|         return self.GetMark() | ||||
|  | ||||
|     def _SetSelection(self, sel_start, sel_to): | ||||
|         """ | ||||
|         Allow mixin to set the text selection of this control. | ||||
|         REQUIRED by any class derived from MaskedEditMixin. | ||||
|         """ | ||||
|         return self.SetMark( sel_start, sel_to ) | ||||
|  | ||||
|  | ||||
|     def _GetInsertionPoint(self): | ||||
|         return self.GetInsertionPoint() | ||||
|  | ||||
|     def _SetInsertionPoint(self, pos): | ||||
|         self.SetInsertionPoint(pos) | ||||
|  | ||||
|  | ||||
|     def _GetValue(self): | ||||
|         """ | ||||
|         Allow mixin to get the raw value of the control with this function. | ||||
|         REQUIRED by any class derived from MaskedEditMixin. | ||||
|         """ | ||||
|         return self.GetValue() | ||||
|  | ||||
|     def _SetValue(self, value): | ||||
|         """ | ||||
|         Allow mixin to set the raw value of the control with this function. | ||||
|         REQUIRED by any class derived from MaskedEditMixin. | ||||
|         """ | ||||
|         # For wxComboBox, ensure that values are properly padded so that | ||||
|         # if varying length choices are supplied, they always show up | ||||
|         # in the window properly, and will be the appropriate length | ||||
|         # to match the mask: | ||||
|         if self._ctrl_constraints._alignRight: | ||||
|             value = value.rjust(self._masklength) | ||||
|         else: | ||||
|             value = value.ljust(self._masklength) | ||||
|  | ||||
|         # Record current selection and insertion point, for undo | ||||
|         self._prevSelection = self._GetSelection() | ||||
|         self._prevInsertionPoint = self._GetInsertionPoint() | ||||
|         wx.ComboBox.SetValue(self, value) | ||||
|         # text change events don't always fire, so we check validity here | ||||
|         # to make certain formatting is applied: | ||||
|         self._CheckValid() | ||||
|  | ||||
|     def SetValue(self, value): | ||||
|         """ | ||||
|         This function redefines the externally accessible .SetValue to be | ||||
|         a smart "paste" of the text in question, so as not to corrupt the | ||||
|         masked control.  NOTE: this must be done in the class derived | ||||
|         from the base wx control. | ||||
|         """ | ||||
|         if not self._mask: | ||||
|             wx.ComboBox.SetValue(value)   # revert to base control behavior | ||||
|             return | ||||
|         # else... | ||||
|         # empty previous contents, replacing entire value: | ||||
|         self._SetInsertionPoint(0) | ||||
|         self._SetSelection(0, self._masklength) | ||||
|  | ||||
|         if( len(value) < self._masklength                # value shorter than control | ||||
|             and (self._isFloat or self._isInt)            # and it's a numeric control | ||||
|             and self._ctrl_constraints._alignRight ):   # and it's a right-aligned control | ||||
|             # try to intelligently "pad out" the value to the right size: | ||||
|             value = self._template[0:self._masklength - len(value)] + value | ||||
| ##            dbg('padded value = "%s"' % value) | ||||
|  | ||||
|         # For wxComboBox, ensure that values are properly padded so that | ||||
|         # if varying length choices are supplied, they always show up | ||||
|         # in the window properly, and will be the appropriate length | ||||
|         # to match the mask: | ||||
|         elif self._ctrl_constraints._alignRight: | ||||
|             value = value.rjust(self._masklength) | ||||
|         else: | ||||
|             value = value.ljust(self._masklength) | ||||
|  | ||||
|  | ||||
|         # make SetValue behave the same as if you had typed the value in: | ||||
|         try: | ||||
|             value = self._Paste(value, raise_on_invalid=True, just_return_value=True) | ||||
|             if self._isFloat: | ||||
|                 self._isNeg = False     # (clear current assumptions) | ||||
|                 value = self._adjustFloat(value) | ||||
|             elif self._isInt: | ||||
|                 self._isNeg = False     # (clear current assumptions) | ||||
|                 value = self._adjustInt(value) | ||||
|             elif self._isDate and not self.IsValid(value) and self._4digityear: | ||||
|                 value = self._adjustDate(value, fixcentury=True) | ||||
|         except ValueError: | ||||
|             # If date, year might be 2 digits vs. 4; try adjusting it: | ||||
|             if self._isDate and self._4digityear: | ||||
|                 dateparts = value.split(' ') | ||||
|                 dateparts[0] = self._adjustDate(dateparts[0], fixcentury=True) | ||||
|                 value = string.join(dateparts, ' ') | ||||
| ##                dbg('adjusted value: "%s"' % value) | ||||
|                 value = self._Paste(value, raise_on_invalid=True, just_return_value=True) | ||||
|             else: | ||||
|                 raise | ||||
|  | ||||
|         self._SetValue(value) | ||||
| ####        dbg('queuing insertion after .SetValue', self._masklength) | ||||
|         wx.CallAfter(self._SetInsertionPoint, self._masklength) | ||||
|         wx.CallAfter(self._SetSelection, self._masklength, self._masklength) | ||||
|  | ||||
|  | ||||
|     def _Refresh(self): | ||||
|         """ | ||||
|         Allow mixin to refresh the base control with this function. | ||||
|         REQUIRED by any class derived from MaskedEditMixin. | ||||
|         """ | ||||
|         wx.ComboBox.Refresh(self) | ||||
|  | ||||
|     def Refresh(self): | ||||
|         """ | ||||
|         This function redefines the externally accessible .Refresh() to | ||||
|         validate the contents of the masked control as it refreshes. | ||||
|         NOTE: this must be done in the class derived from the base wx control. | ||||
|         """ | ||||
|         self._CheckValid() | ||||
|         self._Refresh() | ||||
|  | ||||
|  | ||||
|     def _IsEditable(self): | ||||
|         """ | ||||
|         Allow mixin to determine if the base control is editable with this function. | ||||
|         REQUIRED by any class derived from MaskedEditMixin. | ||||
|         """ | ||||
|         return not self.__readonly | ||||
|  | ||||
|  | ||||
|     def Cut(self): | ||||
|         """ | ||||
|         This function redefines the externally accessible .Cut to be | ||||
|         a smart "erase" of the text in question, so as not to corrupt the | ||||
|         masked control.  NOTE: this must be done in the class derived | ||||
|         from the base wx control. | ||||
|         """ | ||||
|         if self._mask: | ||||
|             self._Cut()             # call the mixin's Cut method | ||||
|         else: | ||||
|             wx.ComboBox.Cut(self)    # else revert to base control behavior | ||||
|  | ||||
|  | ||||
|     def Paste(self): | ||||
|         """ | ||||
|         This function redefines the externally accessible .Paste to be | ||||
|         a smart "paste" of the text in question, so as not to corrupt the | ||||
|         masked control.  NOTE: this must be done in the class derived | ||||
|         from the base wx control. | ||||
|         """ | ||||
|         if self._mask: | ||||
|             self._Paste()           # call the mixin's Paste method | ||||
|         else: | ||||
|             wx.ComboBox.Paste(self)  # else revert to base control behavior | ||||
|  | ||||
|  | ||||
|     def Undo(self): | ||||
|         """ | ||||
|         This function defines the undo operation for the control. (The default | ||||
|         undo is 1-deep.) | ||||
|         """ | ||||
|         if self._mask: | ||||
|             self._Undo() | ||||
|         else: | ||||
|             wx.ComboBox.Undo()       # else revert to base control behavior | ||||
|  | ||||
|  | ||||
|     def Append( self, choice, clientData=None ): | ||||
|         """ | ||||
|         This function override is necessary so we can keep track of any additions to the list | ||||
|         of choices, because wxComboBox doesn't have an accessor for the choice list. | ||||
|         The code here is the same as in the SetParameters() mixin function, but is | ||||
|         done for the individual value as appended, so the list can be built incrementally | ||||
|         without speed penalty. | ||||
|         """ | ||||
|         if self._mask: | ||||
|             if type(choice) not in (types.StringType, types.UnicodeType): | ||||
|                 raise TypeError('%s: choices must be a sequence of strings' % str(self._index)) | ||||
|             elif not self.IsValid(choice): | ||||
|                 raise ValueError('%s: "%s" is not a valid value for the control as specified.' % (str(self._index), choice)) | ||||
|  | ||||
|             if not self._ctrl_constraints._choices: | ||||
|                 self._ctrl_constraints._compareChoices = [] | ||||
|                 self._ctrl_constraints._choices = [] | ||||
|                 self._hasList = True | ||||
|  | ||||
|             compareChoice = choice.strip() | ||||
|  | ||||
|             if self._ctrl_constraints._compareNoCase: | ||||
|                 compareChoice = compareChoice.lower() | ||||
|  | ||||
|             if self._ctrl_constraints._alignRight: | ||||
|                 choice = choice.rjust(self._masklength) | ||||
|             else: | ||||
|                 choice = choice.ljust(self._masklength) | ||||
|             if self._ctrl_constraints._fillChar != ' ': | ||||
|                 choice = choice.replace(' ', self._fillChar) | ||||
| ##            dbg('updated choice:', choice) | ||||
|  | ||||
|  | ||||
|             self._ctrl_constraints._compareChoices.append(compareChoice) | ||||
|             self._ctrl_constraints._choices.append(choice) | ||||
|             self._choices = self._ctrl_constraints._choices     # (for shorthand) | ||||
|  | ||||
|             if( not self.IsValid(choice) and | ||||
|                (not self._ctrl_constraints.IsEmpty(choice) or | ||||
|                 (self._ctrl_constraints.IsEmpty(choice) and self._ctrl_constraints._validRequired) ) ): | ||||
|                 raise ValueError('"%s" is not a valid value for the control "%s" as specified.' % (choice, self.name)) | ||||
|  | ||||
|         wx.ComboBox.Append(self, choice, clientData) | ||||
|  | ||||
|  | ||||
|  | ||||
|     def Clear( self ): | ||||
|         """ | ||||
|         This function override is necessary so we can keep track of any additions to the list | ||||
|         of choices, because wxComboBox doesn't have an accessor for the choice list. | ||||
|         """ | ||||
|         if self._mask: | ||||
|             self._choices = [] | ||||
|             self._ctrl_constraints._autoCompleteIndex = -1 | ||||
|             if self._ctrl_constraints._choices: | ||||
|                 self.SetCtrlParameters(choices=[]) | ||||
|         wx.ComboBox.Clear(self) | ||||
|  | ||||
|  | ||||
|     def _OnCtrlParametersChanged(self): | ||||
|         """ | ||||
|         Override mixin's default OnCtrlParametersChanged to detect changes in choice list, so | ||||
|         we can update the base control: | ||||
|         """ | ||||
|         if self.controlInitialized and self._choices != self._ctrl_constraints._choices: | ||||
|             wx.ComboBox.Clear(self) | ||||
|             self._choices = self._ctrl_constraints._choices | ||||
|             for choice in self._choices: | ||||
|                 wx.ComboBox.Append( self, choice ) | ||||
|  | ||||
|  | ||||
|     def GetMark(self): | ||||
|         """ | ||||
|         This function is a hack to make up for the fact that wxComboBox has no | ||||
|         method for returning the selected portion of its edit control.  It | ||||
|         works, but has the nasty side effect of generating lots of intermediate | ||||
|         events. | ||||
|         """ | ||||
| ##        dbg(suspend=1)  # turn off debugging around this function | ||||
| ##        dbg('MaskedComboBox::GetMark', indent=1) | ||||
|         if self.__readonly: | ||||
| ##            dbg(indent=0) | ||||
|             return 0, 0 # no selection possible for editing | ||||
| ##        sel_start, sel_to = wxComboBox.GetMark(self)        # what I'd *like* to have! | ||||
|         sel_start = sel_to = self.GetInsertionPoint() | ||||
| ##        dbg("current sel_start:", sel_start) | ||||
|         value = self.GetValue() | ||||
| ##        dbg('value: "%s"' % value) | ||||
|  | ||||
|         self._ignoreChange = True               # tell _OnTextChange() to ignore next event (if any) | ||||
|  | ||||
|         wx.ComboBox.Cut(self) | ||||
|         newvalue = self.GetValue() | ||||
| ##        dbg("value after Cut operation:", newvalue) | ||||
|  | ||||
|         if newvalue != value:                   # something was selected; calculate extent | ||||
| ##            dbg("something selected") | ||||
|             sel_to = sel_start + len(value) - len(newvalue) | ||||
|             wx.ComboBox.SetValue(self, value)    # restore original value and selection (still ignoring change) | ||||
|             wx.ComboBox.SetInsertionPoint(self, sel_start) | ||||
|             wx.ComboBox.SetMark(self, sel_start, sel_to) | ||||
|  | ||||
|         self._ignoreChange = False              # tell _OnTextChange() to pay attn again | ||||
|  | ||||
| ##        dbg('computed selection:', sel_start, sel_to, indent=0, suspend=0) | ||||
|         return sel_start, sel_to | ||||
|  | ||||
|  | ||||
|     def SetSelection(self, index): | ||||
|         """ | ||||
|         Necessary for bookkeeping on choice selection, to keep current value | ||||
|         current. | ||||
|         """ | ||||
| ##        dbg('MaskedComboBox::SetSelection(%d)' % index) | ||||
|         if self._mask: | ||||
|             self._prevValue = self._curValue | ||||
|             self._curValue = self._choices[index] | ||||
|             self._ctrl_constraints._autoCompleteIndex = index | ||||
|         wx.ComboBox.SetSelection(self, index) | ||||
|  | ||||
|  | ||||
|     def OnKeyDown(self, event): | ||||
|         """ | ||||
|         This function is necessary because navigation and control key | ||||
|         events do not seem to normally be seen by the wxComboBox's | ||||
|         EVT_CHAR routine.  (Tabs don't seem to be visible no matter | ||||
|         what... {:-( ) | ||||
|         """ | ||||
|         if event.GetKeyCode() in self._nav + self._control: | ||||
|             self._OnChar(event) | ||||
|             return | ||||
|         else: | ||||
|             event.Skip()    # let mixin default KeyDown behavior occur | ||||
|  | ||||
|  | ||||
|     def OnSelectChoice(self, event): | ||||
|         """ | ||||
|         This function appears to be necessary, because the processing done | ||||
|         on the text of the control somehow interferes with the combobox's | ||||
|         selection mechanism for the arrow keys. | ||||
|         """ | ||||
| ##        dbg('MaskedComboBox::OnSelectChoice', indent=1) | ||||
|  | ||||
|         if not self._mask: | ||||
|             event.Skip() | ||||
|             return | ||||
|  | ||||
|         value = self.GetValue().strip() | ||||
|  | ||||
|         if self._ctrl_constraints._compareNoCase: | ||||
|             value = value.lower() | ||||
|  | ||||
|         if event.GetKeyCode() == wx.WXK_UP: | ||||
|             direction = -1 | ||||
|         else: | ||||
|             direction = 1 | ||||
|         match_index, partial_match = self._autoComplete( | ||||
|                                                 direction, | ||||
|                                                 self._ctrl_constraints._compareChoices, | ||||
|                                                 value, | ||||
|                                                 self._ctrl_constraints._compareNoCase, | ||||
|                                                 current_index = self._ctrl_constraints._autoCompleteIndex) | ||||
|         if match_index is not None: | ||||
| ##            dbg('setting selection to', match_index) | ||||
|             # issue appropriate event to outside: | ||||
|             self._OnAutoSelect(self._ctrl_constraints, match_index=match_index) | ||||
|             self._CheckValid() | ||||
|             keep_processing = False | ||||
|         else: | ||||
|             pos = self._adjustPos(self._GetInsertionPoint(), event.GetKeyCode()) | ||||
|             field = self._FindField(pos) | ||||
|             if self.IsEmpty() or not field._hasList: | ||||
| ##                dbg('selecting 1st value in list') | ||||
|                 self._OnAutoSelect(self._ctrl_constraints, match_index=0) | ||||
|                 self._CheckValid() | ||||
|                 keep_processing = False | ||||
|             else: | ||||
|                 # attempt field-level auto-complete | ||||
| ##                dbg(indent=0) | ||||
|                 keep_processing = self._OnAutoCompleteField(event) | ||||
| ##        dbg('keep processing?', keep_processing, indent=0) | ||||
|         return keep_processing | ||||
|  | ||||
|  | ||||
|     def _OnAutoSelect(self, field, match_index): | ||||
|         """ | ||||
|         Override mixin (empty) autocomplete handler, so that autocompletion causes | ||||
|         combobox to update appropriately. | ||||
|         """ | ||||
| ##        dbg('MaskedComboBox::OnAutoSelect', field._index, indent=1) | ||||
| ##        field._autoCompleteIndex = match_index | ||||
|         if field == self._ctrl_constraints: | ||||
|             self.SetSelection(match_index) | ||||
| ##            dbg('issuing combo selection event') | ||||
|             self.GetEventHandler().ProcessEvent( | ||||
|                 MaskedComboBoxSelectEvent( self.GetId(), match_index, self ) ) | ||||
|         self._CheckValid() | ||||
| ##        dbg('field._autoCompleteIndex:', match_index) | ||||
| ##        dbg('self.GetSelection():', self.GetSelection()) | ||||
| ##        dbg(indent=0) | ||||
|  | ||||
|  | ||||
|     def _OnReturn(self, event): | ||||
|         """ | ||||
|         For wxComboBox, it seems that if you hit return when the dropdown is | ||||
|         dropped, the event that dismisses the dropdown will also blank the | ||||
|         control, because of the implementation of wxComboBox.  So here, | ||||
|         we look and if the selection is -1, and the value according to | ||||
|         (the base control!) is a value in the list, then we schedule a | ||||
|         programmatic wxComboBox.SetSelection() call to pick the appropriate | ||||
|         item in the list. (and then do the usual OnReturn bit.) | ||||
|         """ | ||||
| ##        dbg('MaskedComboBox::OnReturn', indent=1) | ||||
| ##        dbg('current value: "%s"' % self.GetValue(), 'current index:', self.GetSelection()) | ||||
|         if self.GetSelection() == -1 and self.GetValue().lower().strip() in self._ctrl_constraints._compareChoices: | ||||
|             wx.CallAfter(self.SetSelection, self._ctrl_constraints._autoCompleteIndex) | ||||
|  | ||||
|         event.m_keyCode = wx.WXK_TAB | ||||
|         event.Skip() | ||||
| ##        dbg(indent=0) | ||||
|  | ||||
|  | ||||
| class ComboBox( BaseMaskedComboBox, MaskedEditAccessorsMixin ): | ||||
|     """ | ||||
|     This extra level of inheritance allows us to add the generic set of | ||||
|     masked edit parameters only to this class while allowing other | ||||
|     classes to derive from the "base" masked combobox control, and provide | ||||
|     a smaller set of valid accessor functions. | ||||
|     """ | ||||
|     pass | ||||
|  | ||||
|  | ||||
| @@ -1,5 +1,5 @@ | ||||
| #---------------------------------------------------------------------------- | ||||
| # Name:         wxPython.lib.maskedctrl.py | ||||
| # Name:         wxPython.lib.masked.ctrl.py | ||||
| # Author:       Will Sadkin | ||||
| # Created:      09/24/2003 | ||||
| # Copyright:   (c) 2003 by Will Sadkin | ||||
| @@ -17,24 +17,24 @@ | ||||
| 
 | ||||
| """<html><body> | ||||
| <P> | ||||
| <B>MaskedCtrl</B> is actually a factory function for several types of | ||||
| <B>masked.Ctrl</B> is actually a factory function for several types of | ||||
| masked edit controls: | ||||
| <P> | ||||
| <UL> | ||||
|     <LI><b>MaskedTextCtrl</b> - standard masked edit text box</LI> | ||||
|     <LI><b>MaskedComboBox</b> - adds combobox capabilities</LI> | ||||
|     <LI><b>IpAddrCtrl</b> - adds logical input semantics for IP address entry</LI> | ||||
|     <LI><b>TimeCtrl</b> - special subclass handling lots of time formats as values</LI> | ||||
|     <LI><b>MaskedNumCtrl</b> - special subclass handling numeric values</LI> | ||||
|     <LI><b>masked.TextCtrl</b>   - standard masked edit text box</LI> | ||||
|     <LI><b>masked.ComboBox</b>   - adds combobox capabilities</LI> | ||||
|     <LI><b>masked.IpAddrCtrl</b> - adds logical input semantics for IP address entry</LI> | ||||
|     <LI><b>masked.TimeCtrl</b>   - special subclass handling lots of time formats as values</LI> | ||||
|     <LI><b>masked.NumCtrl</b>    - special subclass handling numeric values</LI> | ||||
| </UL> | ||||
| <P> | ||||
| <B>MaskedCtrl</B> works by looking for a special <b><i>controlType</i></b> | ||||
| <B>masked.Ctrl</B> works by looking for a special <b><i>controlType</i></b> | ||||
| parameter in the variable arguments of the control, to determine | ||||
| what kind of instance to return. | ||||
| controlType can be one of: | ||||
| <PRE><FONT SIZE=-1> | ||||
|     controlTypes.MASKEDTEXT | ||||
|     controlTypes.MASKEDCOMBO | ||||
|     controlTypes.TEXT | ||||
|     controlTypes.COMBO | ||||
|     controlTypes.IPADDR | ||||
|     controlTypes.TIME | ||||
|     controlTypes.NUMBER | ||||
| @@ -42,56 +42,56 @@ controlType can be one of: | ||||
| These constants are also available individually, ie, you can | ||||
| use either of the following: | ||||
| <PRE><FONT SIZE=-1> | ||||
|     from wxPython.wx.lib.maskedctrl import MaskedCtrl, MASKEDCOMBO, MASKEDTEXT, NUMBER | ||||
|     from wxPython.wx.lib.maskedctrl import MaskedCtrl, controlTypes | ||||
|     from wxPython.wx.lib.masked import Ctrl, COMBO, TEXT, NUMBER, TIME | ||||
|     from wxPython.wx.lib.masked import Ctrl, controlTypes | ||||
| </FONT></PRE> | ||||
| If not specified as a keyword argument, the default controlType is | ||||
| controlTypes.MASKEDTEXT. | ||||
| controlTypes.TEXT. | ||||
| <P> | ||||
| Each of the above classes has its own unique arguments, but MaskedCtrl | ||||
| provides a single "unified" interface for masked controls.  MaskedTextCtrl, | ||||
| MaskedComboBox and IpAddrCtrl are all documented below; the others have | ||||
| provides a single "unified" interface for masked controls.  Masked.TextCtrl, | ||||
| masked.ComboBox and masked.IpAddrCtrl are all documented below; the others have | ||||
| their own demo pages and interface descriptions. | ||||
| </body></html> | ||||
| """ | ||||
| 
 | ||||
| from wx.lib.maskededit      import MaskedTextCtrl, MaskedComboBox, IpAddrCtrl | ||||
| from wx.lib.maskednumctrl   import MaskedNumCtrl | ||||
| from wx.lib.timectrl        import TimeCtrl | ||||
| from wx.lib.masked   import TextCtrl, ComboBox, IpAddrCtrl | ||||
| from wx.lib.masked   import NumCtrl | ||||
| from wx.lib.masked   import TimeCtrl | ||||
| 
 | ||||
| 
 | ||||
| # "type" enumeration for class instance factory function | ||||
| MASKEDTEXT  = 0 | ||||
| MASKEDCOMBO = 1 | ||||
| TEXT        = 0 | ||||
| COMBO       = 1 | ||||
| IPADDR      = 2 | ||||
| TIME        = 3 | ||||
| NUMBER      = 4 | ||||
| 
 | ||||
| # for ease of import | ||||
| class controlTypes: | ||||
|     MASKEDTEXT  = MASKEDTEXT | ||||
|     MASKEDCOMBO = MASKEDCOMBO | ||||
|     TEXT        = TEXT | ||||
|     COMBO       = COMBO | ||||
|     IPADDR      = IPADDR | ||||
|     TIME        = TIME | ||||
|     NUMBER      = NUMBER | ||||
| 
 | ||||
| 
 | ||||
| def MaskedCtrl( *args, **kwargs): | ||||
| def Ctrl( *args, **kwargs): | ||||
|     """ | ||||
|     Actually a factory function providing a unifying | ||||
|     interface for generating masked controls. | ||||
|     """ | ||||
|     if not kwargs.has_key('controlType'): | ||||
|         controlType = MASKEDTEXT | ||||
|         controlType = TEXT | ||||
|     else: | ||||
|         controlType = kwargs['controlType'] | ||||
|         del kwargs['controlType'] | ||||
| 
 | ||||
|     if controlType == MASKEDTEXT: | ||||
|         return MaskedTextCtrl(*args, **kwargs) | ||||
|     if controlType == TEXT: | ||||
|         return TextCtrl(*args, **kwargs) | ||||
| 
 | ||||
|     elif controlType == MASKEDCOMBO: | ||||
|         return MaskedComboBox(*args, **kwargs) | ||||
|     elif controlType == COMBO: | ||||
|         return ComboBox(*args, **kwargs) | ||||
| 
 | ||||
|     elif controlType == IPADDR: | ||||
|         return IpAddrCtrl(*args, **kwargs) | ||||
| @@ -100,7 +100,7 @@ def MaskedCtrl( *args, **kwargs): | ||||
|         return TimeCtrl(*args, **kwargs) | ||||
| 
 | ||||
|     elif controlType == NUMBER: | ||||
|         return MaskedNumCtrl(*args, **kwargs) | ||||
|         return NumCtrl(*args, **kwargs) | ||||
| 
 | ||||
|     else: | ||||
|         raise AttributeError( | ||||
							
								
								
									
										187
									
								
								wxPython/wx/lib/masked/ipaddrctrl.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								wxPython/wx/lib/masked/ipaddrctrl.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,187 @@ | ||||
| #---------------------------------------------------------------------------- | ||||
| # Name:         masked.ipaddrctrl.py | ||||
| # Authors:      Will Sadkin | ||||
| # Email:        wsadkin@nameconnector.com | ||||
| # Created:      02/11/2003 | ||||
| # Copyright:    (c) 2003 by Will Sadkin, 2003 | ||||
| # RCS-ID:       $Id$ | ||||
| # License:      wxWidgets license | ||||
| #---------------------------------------------------------------------------- | ||||
| # NOTE: | ||||
| #   Masked.IpAddrCtrl is a minor modification to masked.TextCtrl, that is | ||||
| #   specifically tailored for entering IP addresses.  It allows for | ||||
| #   right-insert fields and provides an accessor to obtain the entered | ||||
| #   address with extra whitespace removed. | ||||
| # | ||||
| #---------------------------------------------------------------------------- | ||||
|  | ||||
| import  wx | ||||
| from wx.lib.masked import BaseMaskedTextCtrl | ||||
|  | ||||
| # jmg 12/9/03 - when we cut ties with Py 2.2 and earlier, this would | ||||
| # be a good place to implement the 2.3 logger class | ||||
| from wx.tools.dbg import Logger | ||||
| dbg = Logger() | ||||
| ##dbg(enable=0) | ||||
|  | ||||
| class IpAddrCtrlAccessorsMixin: | ||||
|     # Define IpAddrCtrl's list of attributes having their own | ||||
|     # Get/Set functions, exposing only those that make sense for | ||||
|     # an IP address control. | ||||
|  | ||||
|     exposed_basectrl_params = ( | ||||
|         'fields', | ||||
|         'retainFieldValidation', | ||||
|         'formatcodes', | ||||
|         'fillChar', | ||||
|         'defaultValue', | ||||
|         'description', | ||||
|  | ||||
|         'useFixedWidthFont', | ||||
|         'signedForegroundColour', | ||||
|         'emptyBackgroundColour', | ||||
|         'validBackgroundColour', | ||||
|         'invalidBackgroundColour', | ||||
|  | ||||
|         'emptyInvalid', | ||||
|         'validFunc', | ||||
|         'validRequired', | ||||
|         ) | ||||
|  | ||||
|     for param in exposed_basectrl_params: | ||||
|         propname = param[0].upper() + param[1:] | ||||
|         exec('def Set%s(self, value): self.SetCtrlParameters(%s=value)' % (propname, param)) | ||||
|         exec('def Get%s(self): return self.GetCtrlParameter("%s")''' % (propname, param)) | ||||
|  | ||||
|         if param.find('Colour') != -1: | ||||
|             # add non-british spellings, for backward-compatibility | ||||
|             propname.replace('Colour', 'Color') | ||||
|  | ||||
|             exec('def Set%s(self, value): self.SetCtrlParameters(%s=value)' % (propname, param)) | ||||
|             exec('def Get%s(self): return self.GetCtrlParameter("%s")''' % (propname, param)) | ||||
|  | ||||
|  | ||||
| class IpAddrCtrl( BaseMaskedTextCtrl, IpAddrCtrlAccessorsMixin ): | ||||
|     """ | ||||
|     This class is a particular type of MaskedTextCtrl that accepts | ||||
|     and understands the semantics of IP addresses, reformats input | ||||
|     as you move from field to field, and accepts '.' as a navigation | ||||
|     character, so that typing an IP address can be done naturally. | ||||
|     """ | ||||
|  | ||||
|  | ||||
|  | ||||
|     def __init__( self, parent, id=-1, value = '', | ||||
|                   pos = wx.DefaultPosition, | ||||
|                   size = wx.DefaultSize, | ||||
|                   style = wx.TE_PROCESS_TAB, | ||||
|                   validator = wx.DefaultValidator, | ||||
|                   name = 'IpAddrCtrl', | ||||
|                   setupEventHandling = True,        ## setup event handling by default | ||||
|                   **kwargs): | ||||
|  | ||||
|         if not kwargs.has_key('mask'): | ||||
|            kwargs['mask'] = mask = "###.###.###.###" | ||||
|         if not kwargs.has_key('formatcodes'): | ||||
|             kwargs['formatcodes'] = 'F_Sr<' | ||||
|         if not kwargs.has_key('validRegex'): | ||||
|             kwargs['validRegex'] = "(  \d| \d\d|(1\d\d|2[0-4]\d|25[0-5]))(\.(  \d| \d\d|(1\d\d|2[0-4]\d|25[0-5]))){3}" | ||||
|  | ||||
|  | ||||
|         BaseMaskedTextCtrl.__init__( | ||||
|                 self, parent, id=id, value = value, | ||||
|                 pos=pos, size=size, | ||||
|                 style = style, | ||||
|                 validator = validator, | ||||
|                 name = name, | ||||
|                 setupEventHandling = setupEventHandling, | ||||
|                 **kwargs) | ||||
|  | ||||
|  | ||||
|         # set up individual field parameters as well: | ||||
|         field_params = {} | ||||
|         field_params['validRegex'] = "(   |  \d| \d |\d  | \d\d|\d\d |\d \d|(1\d\d|2[0-4]\d|25[0-5]))" | ||||
|  | ||||
|         # require "valid" string; this prevents entry of any value > 255, but allows | ||||
|         # intermediate constructions; overall control validation requires well-formatted value. | ||||
|         field_params['formatcodes'] = 'V' | ||||
|  | ||||
|         if field_params: | ||||
|             for i in self._field_indices: | ||||
|                 self.SetFieldParameters(i, **field_params) | ||||
|  | ||||
|         # This makes '.' act like tab: | ||||
|         self._AddNavKey('.', handler=self.OnDot) | ||||
|         self._AddNavKey('>', handler=self.OnDot)    # for "shift-." | ||||
|  | ||||
|  | ||||
|     def OnDot(self, event): | ||||
| ##        dbg('IpAddrCtrl::OnDot', indent=1) | ||||
|         pos = self._adjustPos(self._GetInsertionPoint(), event.GetKeyCode()) | ||||
|         oldvalue = self.GetValue() | ||||
|         edit_start, edit_end, slice = self._FindFieldExtent(pos, getslice=True) | ||||
|         if not event.ShiftDown(): | ||||
|             if pos > edit_start and pos < edit_end: | ||||
|                 # clip data in field to the right of pos, if adjusting fields | ||||
|                 # when not at delimeter; (assumption == they hit '.') | ||||
|                 newvalue = oldvalue[:pos] + ' ' * (edit_end - pos) + oldvalue[edit_end:] | ||||
|                 self._SetValue(newvalue) | ||||
|                 self._SetInsertionPoint(pos) | ||||
| ##        dbg(indent=0) | ||||
|         return self._OnChangeField(event) | ||||
|  | ||||
|  | ||||
|  | ||||
|     def GetAddress(self): | ||||
|         value = BaseMaskedTextCtrl.GetValue(self) | ||||
|         return value.replace(' ','')    # remove spaces from the value | ||||
|  | ||||
|  | ||||
|     def _OnCtrl_S(self, event): | ||||
| ##        dbg("IpAddrCtrl::_OnCtrl_S") | ||||
|         if self._demo: | ||||
|             print "value:", self.GetAddress() | ||||
|         return False | ||||
|  | ||||
|     def SetValue(self, value): | ||||
| ##        dbg('IpAddrCtrl::SetValue(%s)' % str(value), indent=1) | ||||
|         if type(value) not in (types.StringType, types.UnicodeType): | ||||
| ##            dbg(indent=0) | ||||
|             raise ValueError('%s must be a string', str(value)) | ||||
|  | ||||
|         bValid = True   # assume True | ||||
|         parts = value.split('.') | ||||
|         if len(parts) != 4: | ||||
|             bValid = False | ||||
|         else: | ||||
|             for i in range(4): | ||||
|                 part = parts[i] | ||||
|                 if not 0 <= len(part) <= 3: | ||||
|                     bValid = False | ||||
|                     break | ||||
|                 elif part.strip():  # non-empty part | ||||
|                     try: | ||||
|                         j = string.atoi(part) | ||||
|                         if not 0 <= j <= 255: | ||||
|                             bValid = False | ||||
|                             break | ||||
|                         else: | ||||
|                             parts[i] = '%3d' % j | ||||
|                     except: | ||||
|                         bValid = False | ||||
|                         break | ||||
|                 else: | ||||
|                     # allow empty sections for SetValue (will result in "invalid" value, | ||||
|                     # but this may be useful for initializing the control: | ||||
|                     parts[i] = '   '    # convert empty field to 3-char length | ||||
|  | ||||
|         if not bValid: | ||||
| ##            dbg(indent=0) | ||||
|             raise ValueError('value (%s) must be a string of form n.n.n.n where n is empty or in range 0-255' % str(value)) | ||||
|         else: | ||||
| ##            dbg('parts:', parts) | ||||
|             value = string.join(parts, '.') | ||||
|             BaseMaskedTextCtrl.SetValue(self, value) | ||||
| ##        dbg(indent=0) | ||||
|  | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,5 +1,5 @@ | ||||
| #---------------------------------------------------------------------------- | ||||
| # Name:         wxPython.lib.maskednumctrl.py | ||||
| # Name:         wxPython.lib.masked.numctrl.py | ||||
| # Author:       Will Sadkin | ||||
| # Created:      09/06/2003 | ||||
| # Copyright:   (c) 2003 by Will Sadkin | ||||
| @@ -9,12 +9,12 @@ | ||||
| # NOTE: | ||||
| #   This was written to provide a numeric edit control for wxPython that | ||||
| #   does things like right-insert (like a calculator), and does grouping, etc. | ||||
| #   (ie. the features of MaskedTextCtrl), but allows Get/Set of numeric | ||||
| #   (ie. the features of masked.TextCtrl), but allows Get/Set of numeric | ||||
| #   values, rather than text. | ||||
| # | ||||
| #   MaskedNumCtrl permits integer, and floating point values to be set | ||||
| #   Masked.NumCtrl permits integer, and floating point values to be set | ||||
| #   retrieved or set via .GetValue() and .SetValue() (type chosen based on | ||||
| #   fraction width, and provides an EVT_MASKEDNUM() event function for trapping | ||||
| #   fraction width, and provides an masked.EVT_NUM() event function for trapping | ||||
| #   changes to the control. | ||||
| # | ||||
| #   It supports negative numbers as well as the naturals, and has the option | ||||
| @@ -24,11 +24,11 @@ | ||||
| #   Similarly, replacing the contents of the control with '-' will result in | ||||
| #   a selected (absolute) value of -1. | ||||
| # | ||||
| #   MaskedNumCtrl also supports range limits, with the option of either | ||||
| #   masked.NumCtrl also supports range limits, with the option of either | ||||
| #   enforcing them or simply coloring the text of the control if the limits | ||||
| #   are exceeded. | ||||
| # | ||||
| #   MaskedNumCtrl is intended to support fixed-point numeric entry, and | ||||
| #   masked.NumCtrl is intended to support fixed-point numeric entry, and | ||||
| #   is derived from BaseMaskedTextCtrl.  As such, it supports a limited range | ||||
| #   of values to comply with a fixed-width entry mask. | ||||
| #---------------------------------------------------------------------------- | ||||
| @@ -39,14 +39,14 @@ | ||||
| # 12/20/2003 - Jeff Grimmett (grimmtooth@softhome.net) | ||||
| # | ||||
| # o wxMaskedEditMixin -> MaskedEditMixin | ||||
| # o wxMaskedTextCtrl -> MaskedTextCtrl | ||||
| # o wxMaskedNumNumberUpdatedEvent -> MaskedNumNumberUpdatedEvent | ||||
| # o wxMaskedNumCtrl -> MaskedNumCtrl | ||||
| # o wxMaskedTextCtrl -> masked.TextCtrl | ||||
| # o wxMaskedNumNumberUpdatedEvent -> masked.NumberUpdatedEvent | ||||
| # o wxMaskedNumCtrl -> masked.NumCtrl | ||||
| # | ||||
| 
 | ||||
| """<html><body> | ||||
| <P> | ||||
| <B>MaskedNumCtrl:</B> | ||||
| <B>masked.NumCtrl:</B> | ||||
| <UL> | ||||
| <LI>allows you to get and set integer or floating point numbers as value,</LI> | ||||
| <LI>provides bounds support and optional value limiting,</LI> | ||||
| @@ -62,14 +62,14 @@ fractional portion. | ||||
| <P> | ||||
| Here's the API: | ||||
| <DL><PRE> | ||||
|     <B>MaskedNumCtrl</B>( | ||||
|     <B>masked.NumCtrl</B>( | ||||
|          parent, id = -1, | ||||
|          <B>value</B> = 0, | ||||
|          pos = wx.DefaultPosition, | ||||
|          size = wx.DefaultSize, | ||||
|          style = 0, | ||||
|          validator = wx.DefaultValidator, | ||||
|          name = "maskednumber", | ||||
|          name = "masked.number", | ||||
|          <B>integerWidth</B> = 10, | ||||
|          <B>fractionWidth</B> = 0, | ||||
|          <B>allowNone</B> = False, | ||||
| @@ -190,7 +190,7 @@ Here's the API: | ||||
| </UL> | ||||
| <BR> | ||||
| <BR> | ||||
| <DT><B>EVT_MASKEDNUM(win, id, func)</B> | ||||
| <DT><B>masked.EVT_NUM(win, id, func)</B> | ||||
| <DD>Respond to a EVT_COMMAND_MASKED_NUMBER_UPDATED event, generated when | ||||
| the value changes. Notice that this event will always be sent when the | ||||
| control's contents changes - whether this is due to user input or | ||||
| @@ -384,18 +384,18 @@ MAXINT = maxint     # (constants should be in upper case) | ||||
| MININT = -maxint-1 | ||||
| 
 | ||||
| from wx.tools.dbg import Logger | ||||
| from wx.lib.maskededit import MaskedEditMixin, BaseMaskedTextCtrl, Field | ||||
| from wx.lib.masked import MaskedEditMixin, Field, BaseMaskedTextCtrl | ||||
| dbg = Logger() | ||||
| dbg(enable=0) | ||||
| ##dbg(enable=0) | ||||
| 
 | ||||
| #---------------------------------------------------------------------------- | ||||
| 
 | ||||
| wxEVT_COMMAND_MASKED_NUMBER_UPDATED = wx.NewEventType() | ||||
| EVT_MASKEDNUM = wx.PyEventBinder(wxEVT_COMMAND_MASKED_NUMBER_UPDATED, 1) | ||||
| EVT_NUM = wx.PyEventBinder(wxEVT_COMMAND_MASKED_NUMBER_UPDATED, 1) | ||||
| 
 | ||||
| #---------------------------------------------------------------------------- | ||||
| 
 | ||||
| class MaskedNumNumberUpdatedEvent(wx.PyCommandEvent): | ||||
| class NumberUpdatedEvent(wx.PyCommandEvent): | ||||
|     def __init__(self, id, value = 0, object=None): | ||||
|         wx.PyCommandEvent.__init__(self, wxEVT_COMMAND_MASKED_NUMBER_UPDATED, id) | ||||
| 
 | ||||
| @@ -409,8 +409,8 @@ class MaskedNumNumberUpdatedEvent(wx.PyCommandEvent): | ||||
| 
 | ||||
| 
 | ||||
| #---------------------------------------------------------------------------- | ||||
| class MaskedNumCtrlAccessorsMixin: | ||||
|     # Define wxMaskedNumCtrl's list of attributes having their own | ||||
| class NumCtrlAccessorsMixin: | ||||
|     # Define masked.NumCtrl's list of attributes having their own | ||||
|     # Get/Set functions, ignoring those that make no sense for | ||||
|     # an numeric control. | ||||
|     exposed_basectrl_params = ( | ||||
| @@ -448,7 +448,7 @@ class MaskedNumCtrlAccessorsMixin: | ||||
| 
 | ||||
| #---------------------------------------------------------------------------- | ||||
| 
 | ||||
| class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
| class NumCtrl(BaseMaskedTextCtrl, NumCtrlAccessorsMixin): | ||||
| 
 | ||||
| 
 | ||||
|     valid_ctrl_params = { | ||||
| @@ -478,31 +478,32 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|                 self, parent, id=-1, value = 0, | ||||
|                 pos = wx.DefaultPosition, size = wx.DefaultSize, | ||||
|                 style = wx.TE_PROCESS_TAB, validator = wx.DefaultValidator, | ||||
|                 name = "maskednum", | ||||
|                 name = "masked.num", | ||||
|                 **kwargs ): | ||||
| 
 | ||||
|         dbg('MaskedNumCtrl::__init__', indent=1) | ||||
| ##        dbg('masked.NumCtrl::__init__', indent=1) | ||||
| 
 | ||||
|         # Set defaults for control: | ||||
|         dbg('setting defaults:') | ||||
|         for key, param_value in MaskedNumCtrl.valid_ctrl_params.items(): | ||||
| ##        dbg('setting defaults:') | ||||
|         for key, param_value in NumCtrl.valid_ctrl_params.items(): | ||||
|             # This is done this way to make setattr behave consistently with | ||||
|             # "private attribute" name mangling | ||||
|             setattr(self, '_' + key, copy.copy(param_value)) | ||||
| 
 | ||||
|         # Assign defaults for all attributes: | ||||
|         init_args = copy.deepcopy(MaskedNumCtrl.valid_ctrl_params) | ||||
|         dbg('kwargs:', kwargs) | ||||
|         init_args = copy.deepcopy(NumCtrl.valid_ctrl_params) | ||||
| ##        dbg('kwargs:', kwargs) | ||||
|         for key, param_value in kwargs.items(): | ||||
|             key = key.replace('Color', 'Colour') | ||||
|             if key not in MaskedNumCtrl.valid_ctrl_params.keys(): | ||||
|             if key not in NumCtrl.valid_ctrl_params.keys(): | ||||
|                 raise AttributeError('invalid keyword argument "%s"' % key) | ||||
|             else: | ||||
|                 init_args[key] = param_value | ||||
|         dbg('init_args:', indent=1) | ||||
| ##        dbg('init_args:', indent=1) | ||||
|         for key, param_value in init_args.items(): | ||||
|             dbg('%s:' % key, param_value) | ||||
|         dbg(indent=0) | ||||
| ##            dbg('%s:' % key, param_value) | ||||
|             pass | ||||
| ##        dbg(indent=0) | ||||
| 
 | ||||
|         # Process initial fields for the control, as part of construction: | ||||
|         if type(init_args['integerWidth']) != types.IntType: | ||||
| @@ -521,7 +522,7 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
| 
 | ||||
|         if self._fractionWidth: | ||||
|             fracmask = '.' + '#{%d}' % self._fractionWidth | ||||
|             dbg('fracmask:', fracmask) | ||||
| ##            dbg('fracmask:', fracmask) | ||||
|             fields[1] = Field(defaultValue='0'*self._fractionWidth) | ||||
|         else: | ||||
|             fracmask = '' | ||||
| @@ -537,7 +538,7 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|         else: | ||||
|             emptyInvalid = True | ||||
|         fields[0] = Field(formatcodes='r<>', emptyInvalid=emptyInvalid) | ||||
|         dbg('intmask:', intmask) | ||||
| ##        dbg('intmask:', intmask) | ||||
| 
 | ||||
|         # don't bother to reprocess these arguments: | ||||
|         del init_args['integerWidth'] | ||||
| @@ -585,14 +586,14 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
| 
 | ||||
|         # Ensure proper coloring: | ||||
|         self.Refresh() | ||||
|         dbg('finished MaskedNumCtrl::__init__', indent=0) | ||||
| ##        dbg('finished NumCtrl::__init__', indent=0) | ||||
| 
 | ||||
| 
 | ||||
|     def SetParameters(self, **kwargs): | ||||
|         """ | ||||
|         This routine is used to initialize and reconfigure the control: | ||||
|         """ | ||||
|         dbg('MaskedNumCtrl::SetParameters', indent=1) | ||||
| ##        dbg('NumCtrl::SetParameters', indent=1) | ||||
|         maskededit_kwargs = {} | ||||
|         reset_fraction_width = False | ||||
| 
 | ||||
| @@ -620,14 +621,14 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|             else: | ||||
|                 emptyInvalid = True | ||||
|                 fracmask = '' | ||||
|             dbg('fracmask:', fracmask) | ||||
| ##            dbg('fracmask:', fracmask) | ||||
| 
 | ||||
|             if kwargs.has_key('integerWidth'): | ||||
|                 if type(kwargs['integerWidth']) != types.IntType: | ||||
|                     dbg(indent=0) | ||||
| ##                    dbg(indent=0) | ||||
|                     raise AttributeError('invalid integerWidth (%s) specified; expected integer' % repr(kwargs['integerWidth'])) | ||||
|                 elif kwargs['integerWidth'] < 0: | ||||
|                     dbg(indent=0) | ||||
| ##                    dbg(indent=0) | ||||
|                     raise AttributeError('invalid integerWidth (%s) specified; must be > 0' % repr(kwargs['integerWidth'])) | ||||
|                 else: | ||||
|                     self._integerWidth = kwargs['integerWidth'] | ||||
| @@ -641,7 +642,7 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|                 self._groupSpace = 0 | ||||
| 
 | ||||
|             intmask = '#{%d}' % (self._integerWidth + self._groupSpace) | ||||
|             dbg('intmask:', intmask) | ||||
| ##            dbg('intmask:', intmask) | ||||
|             fields[0] = Field(formatcodes='r<>', emptyInvalid=emptyInvalid) | ||||
|             maskededit_kwargs['fields'] = fields | ||||
| 
 | ||||
| @@ -655,17 +656,17 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
| 
 | ||||
|         if kwargs.has_key('groupChar'): | ||||
|             old_groupchar = self._groupChar     # save so we can reformat properly | ||||
|             dbg("old_groupchar: '%s'" % old_groupchar) | ||||
| ##            dbg("old_groupchar: '%s'" % old_groupchar) | ||||
|             maskededit_kwargs['groupChar'] = kwargs['groupChar'] | ||||
|         if kwargs.has_key('decimalChar'): | ||||
|             old_decimalchar = self._decimalChar | ||||
|             dbg("old_decimalchar: '%s'" % old_decimalchar) | ||||
| ##            dbg("old_decimalchar: '%s'" % old_decimalchar) | ||||
|             maskededit_kwargs['decimalChar'] = kwargs['decimalChar'] | ||||
| 
 | ||||
|         # for all other parameters, assign keyword args as appropriate: | ||||
|         for key, param_value in kwargs.items(): | ||||
|             key = key.replace('Color', 'Colour') | ||||
|             if key not in MaskedNumCtrl.valid_ctrl_params.keys(): | ||||
|             if key not in NumCtrl.valid_ctrl_params.keys(): | ||||
|                 raise AttributeError('invalid keyword argument "%s"' % key) | ||||
|             elif key not in MaskedEditMixin.valid_ctrl_params.keys(): | ||||
|                 setattr(self, '_' + key, param_value) | ||||
| @@ -673,7 +674,7 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|                 raise AttributeError('invalid keyword argument "%s"' % key) | ||||
|             else: | ||||
|                 maskededit_kwargs[key] = param_value | ||||
|         dbg('kwargs:', kwargs) | ||||
| ##        dbg('kwargs:', kwargs) | ||||
| 
 | ||||
|         # reprocess existing format codes to ensure proper resulting format: | ||||
|         formatcodes = self.GetCtrlParameter('formatcodes') | ||||
| @@ -695,7 +696,7 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
| 
 | ||||
|         if kwargs.has_key('selectOnEntry'): | ||||
|             self._selectOnEntry = kwargs['selectOnEntry'] | ||||
|             dbg("kwargs['selectOnEntry']?", kwargs['selectOnEntry'], "'S' in formatcodes?", 'S' in formatcodes) | ||||
| ##            dbg("kwargs['selectOnEntry']?", kwargs['selectOnEntry'], "'S' in formatcodes?", 'S' in formatcodes) | ||||
|             if kwargs['selectOnEntry'] and 'S' not in formatcodes: | ||||
|                 formatcodes += 'S' | ||||
|                 maskededit_kwargs['formatcodes'] = formatcodes | ||||
| @@ -728,7 +729,7 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|                 maskededit_kwargs['validRequired'] = False | ||||
|             self._limited = kwargs['limited'] | ||||
| 
 | ||||
|         dbg('maskededit_kwargs:', maskededit_kwargs) | ||||
| ##        dbg('maskededit_kwargs:', maskededit_kwargs) | ||||
|         if maskededit_kwargs.keys(): | ||||
|             self.SetCtrlParameters(**maskededit_kwargs) | ||||
| 
 | ||||
| @@ -756,17 +757,18 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|             if( self._max is None | ||||
|                 or min is None | ||||
|                 or (self._max is not None and self._max >= min) ): | ||||
|                 dbg('examining min') | ||||
| ##                dbg('examining min') | ||||
|                 if min is not None: | ||||
|                     try: | ||||
|                         textmin = self._toGUI(min, apply_limits = False) | ||||
|                     except ValueError: | ||||
|                         dbg('min will not fit into control; ignoring', indent=0) | ||||
| ##                        dbg('min will not fit into control; ignoring', indent=0) | ||||
|                         raise | ||||
|                 dbg('accepted min') | ||||
| ##                dbg('accepted min') | ||||
|                 self._min = min | ||||
|             else: | ||||
|                 dbg('ignoring min') | ||||
| ##                dbg('ignoring min') | ||||
|                 pass | ||||
| 
 | ||||
| 
 | ||||
|         if kwargs.has_key('max'): | ||||
| @@ -774,24 +776,25 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|             if( self._min is None | ||||
|                 or max is None | ||||
|                 or (self._min is not None and self._min <= max) ): | ||||
|                 dbg('examining max') | ||||
| ##                dbg('examining max') | ||||
|                 if max is not None: | ||||
|                     try: | ||||
|                         textmax = self._toGUI(max, apply_limits = False) | ||||
|                     except ValueError: | ||||
|                         dbg('max will not fit into control; ignoring', indent=0) | ||||
| ##                        dbg('max will not fit into control; ignoring', indent=0) | ||||
|                         raise | ||||
|                 dbg('accepted max') | ||||
| ##                dbg('accepted max') | ||||
|                 self._max = max | ||||
|             else: | ||||
|                 dbg('ignoring max') | ||||
| ##                dbg('ignoring max') | ||||
|                 pass | ||||
| 
 | ||||
|         if kwargs.has_key('allowNegative'): | ||||
|             self._allowNegative = kwargs['allowNegative'] | ||||
| 
 | ||||
|         # Ensure current value of control obeys any new restrictions imposed: | ||||
|         text = self._GetValue() | ||||
|         dbg('text value: "%s"' % text) | ||||
| ##        dbg('text value: "%s"' % text) | ||||
|         if kwargs.has_key('groupChar') and text.find(old_groupchar) != -1: | ||||
|             text = text.replace(old_groupchar, self._groupChar) | ||||
|         if kwargs.has_key('decimalChar') and text.find(old_decimalchar) != -1: | ||||
| @@ -801,10 +804,10 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
| 
 | ||||
|         value = self.GetValue() | ||||
| 
 | ||||
|         dbg('self._allowNegative?', self._allowNegative) | ||||
| ##        dbg('self._allowNegative?', self._allowNegative) | ||||
|         if not self._allowNegative and self._isNeg: | ||||
|             value = abs(value) | ||||
|             dbg('abs(value):', value) | ||||
| ##            dbg('abs(value):', value) | ||||
|             self._isNeg = False | ||||
| 
 | ||||
|         elif not self._allowNone and BaseMaskedTextCtrl.GetValue(self) == '': | ||||
| @@ -815,19 +818,19 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
| 
 | ||||
|         sel_start, sel_to = self.GetSelection() | ||||
|         if self.IsLimited() and self._min is not None and value < self._min: | ||||
|             dbg('Set to min value:', self._min) | ||||
| ##            dbg('Set to min value:', self._min) | ||||
|             self._SetValue(self._toGUI(self._min)) | ||||
| 
 | ||||
|         elif self.IsLimited() and self._max is not None and value > self._max: | ||||
|             dbg('Setting to max value:', self._max) | ||||
| ##            dbg('Setting to max value:', self._max) | ||||
|             self._SetValue(self._toGUI(self._max)) | ||||
|         else: | ||||
|             # reformat current value as appropriate to possibly new conditions | ||||
|             dbg('Reformatting value:', value) | ||||
| ##            dbg('Reformatting value:', value) | ||||
|             sel_start, sel_to = self.GetSelection() | ||||
|             self._SetValue(self._toGUI(value)) | ||||
|         self.Refresh() # recolor as appropriate | ||||
|         dbg('finished MaskedNumCtrl::SetParameters', indent=0) | ||||
| ##        dbg('finished NumCtrl::SetParameters', indent=0) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| @@ -859,21 +862,21 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|                 return string.atof(fracstring) | ||||
| 
 | ||||
|     def _OnChangeSign(self, event): | ||||
|         dbg('MaskedNumCtrl::_OnChangeSign', indent=1) | ||||
| ##        dbg('NumCtrl::_OnChangeSign', indent=1) | ||||
|         self._typedSign = True | ||||
|         MaskedEditMixin._OnChangeSign(self, event) | ||||
|         dbg(indent=0) | ||||
| ##        dbg(indent=0) | ||||
| 
 | ||||
| 
 | ||||
|     def _disallowValue(self): | ||||
|         dbg('MaskedNumCtrl::_disallowValue') | ||||
| ##        dbg('NumCtrl::_disallowValue') | ||||
|         # limited and -1 is out of bounds | ||||
|         if self._typedSign: | ||||
|             self._isNeg = False | ||||
|         if not wx.Validator_IsSilent(): | ||||
|             wx.Bell() | ||||
|         sel_start, sel_to = self._GetSelection() | ||||
|         dbg('queuing reselection of (%d, %d)' % (sel_start, sel_to)) | ||||
| ##        dbg('queuing reselection of (%d, %d)' % (sel_start, sel_to)) | ||||
|         wx.CallAfter(self.SetInsertionPoint, sel_start)      # preserve current selection/position | ||||
|         wx.CallAfter(self.SetSelection, sel_start, sel_to) | ||||
| 
 | ||||
| @@ -886,19 +889,19 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|         by the user. | ||||
|         """ | ||||
| 
 | ||||
|         dbg('MaskedNumCtrl::_SetValue("%s")' % value, indent=1) | ||||
| ##        dbg('NumCtrl::_SetValue("%s")' % value, indent=1) | ||||
| 
 | ||||
|         if( (self._fractionWidth and value.find(self._decimalChar) == -1) or | ||||
|             (self._fractionWidth == 0 and value.find(self._decimalChar) != -1) ) : | ||||
|             value = self._toGUI(value) | ||||
| 
 | ||||
|         numvalue = self._GetNumValue(value) | ||||
|         dbg('cleansed value: "%s"' % numvalue) | ||||
| ##        dbg('cleansed value: "%s"' % numvalue) | ||||
|         replacement = None | ||||
| 
 | ||||
|         if numvalue == "": | ||||
|             if self._allowNone: | ||||
|                 dbg('calling base BaseMaskedTextCtrl._SetValue(self, "%s")' % value) | ||||
| ##                dbg('calling base BaseMaskedTextCtrl._SetValue(self, "%s")' % value) | ||||
|                 BaseMaskedTextCtrl._SetValue(self, value) | ||||
|                 self.Refresh() | ||||
|                 return | ||||
| @@ -906,54 +909,54 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|                 replacement = self._min | ||||
|             else: | ||||
|                 replacement = 0 | ||||
|             dbg('empty value; setting replacement:', replacement) | ||||
| ##            dbg('empty value; setting replacement:', replacement) | ||||
| 
 | ||||
|         if replacement is None: | ||||
|             # Go get the integer portion about to be set and verify its validity | ||||
|             intstart, intend = self._fields[0]._extent | ||||
|             dbg('intstart, intend:', intstart, intend) | ||||
|             dbg('raw integer:"%s"' % value[intstart:intend]) | ||||
| ##            dbg('intstart, intend:', intstart, intend) | ||||
| ##            dbg('raw integer:"%s"' % value[intstart:intend]) | ||||
|             int = self._GetNumValue(value[intstart:intend]) | ||||
|             numval = self._fromGUI(value) | ||||
| 
 | ||||
|             dbg('integer: "%s"' % int) | ||||
| ##            dbg('integer: "%s"' % int) | ||||
|             try: | ||||
|                 fracval = self.GetFraction(value) | ||||
|             except ValueError, e: | ||||
|                 dbg('Exception:', e, 'must be out of bounds; disallow value') | ||||
| ##                dbg('Exception:', e, 'must be out of bounds; disallow value') | ||||
|                 self._disallowValue() | ||||
|                 dbg(indent=0) | ||||
| ##                dbg(indent=0) | ||||
|                 return | ||||
| 
 | ||||
|             if fracval == 0.0: | ||||
|                 dbg('self._isNeg?', self._isNeg) | ||||
| ##                dbg('self._isNeg?', self._isNeg) | ||||
|                 if int == '-' and self._oldvalue < 0 and not self._typedSign: | ||||
|                     dbg('just a negative sign; old value < 0; setting replacement of 0') | ||||
| ##                    dbg('just a negative sign; old value < 0; setting replacement of 0') | ||||
|                     replacement = 0 | ||||
|                     self._isNeg = False | ||||
|                 elif int[:2] == '-0' and self._fractionWidth == 0: | ||||
|                     if self._oldvalue < 0: | ||||
|                         dbg('-0; setting replacement of 0') | ||||
| ##                        dbg('-0; setting replacement of 0') | ||||
|                         replacement = 0 | ||||
|                         self._isNeg = False | ||||
|                     elif not self._limited or (self._min < -1 and self._max >= -1): | ||||
|                         dbg('-0; setting replacement of -1') | ||||
| ##                        dbg('-0; setting replacement of -1') | ||||
|                         replacement = -1 | ||||
|                         self._isNeg = True | ||||
|                     else: | ||||
|                         # limited and -1 is out of bounds | ||||
|                         self._disallowValue() | ||||
|                         dbg(indent=0) | ||||
| ##                        dbg(indent=0) | ||||
|                         return | ||||
| 
 | ||||
|                 elif int == '-' and (self._oldvalue >= 0 or self._typedSign) and self._fractionWidth == 0: | ||||
|                     if not self._limited or (self._min < -1 and self._max >= -1): | ||||
|                         dbg('just a negative sign; setting replacement of -1') | ||||
| ##                        dbg('just a negative sign; setting replacement of -1') | ||||
|                         replacement = -1 | ||||
|                     else: | ||||
|                         # limited and -1 is out of bounds | ||||
|                         self._disallowValue() | ||||
|                         dbg(indent=0) | ||||
| ##                        dbg(indent=0) | ||||
|                         return | ||||
| 
 | ||||
|                 elif( self._typedSign | ||||
| @@ -963,7 +966,7 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|                     # changed sign resulting in value that's now out-of-bounds; | ||||
|                     # disallow | ||||
|                     self._disallowValue() | ||||
|                     dbg(indent=0) | ||||
| ##                    dbg(indent=0) | ||||
|                     return | ||||
| 
 | ||||
|             if replacement is None: | ||||
| @@ -974,37 +977,37 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|                         # integer requested is not legal.  This can happen if the user | ||||
|                         # is attempting to insert a digit in the middle of the control | ||||
|                         # resulting in something like "   3   45". Disallow such actions: | ||||
|                         dbg('>>>>>>>>>>>>>>>> "%s" does not convert to a long!' % int) | ||||
| ##                        dbg('>>>>>>>>>>>>>>>> "%s" does not convert to a long!' % int) | ||||
|                         if not wx.Validator_IsSilent(): | ||||
|                             wx.Bell() | ||||
|                         sel_start, sel_to = self._GetSelection() | ||||
|                         dbg('queuing reselection of (%d, %d)' % (sel_start, sel_to)) | ||||
| ##                        dbg('queuing reselection of (%d, %d)' % (sel_start, sel_to)) | ||||
|                         wx.CallAfter(self.SetInsertionPoint, sel_start)      # preserve current selection/position | ||||
|                         wx.CallAfter(self.SetSelection, sel_start, sel_to) | ||||
|                         dbg(indent=0) | ||||
| ##                        dbg(indent=0) | ||||
|                         return | ||||
| 
 | ||||
|                     if int[0] == '0' and len(int) > 1: | ||||
|                         dbg('numvalue: "%s"' % numvalue.replace(' ', '')) | ||||
| ##                        dbg('numvalue: "%s"' % numvalue.replace(' ', '')) | ||||
|                         if self._fractionWidth: | ||||
|                             value = self._toGUI(string.atof(numvalue)) | ||||
|                         else: | ||||
|                             value = self._toGUI(string.atol(numvalue)) | ||||
|                         dbg('modified value: "%s"' % value) | ||||
| ##                        dbg('modified value: "%s"' % value) | ||||
| 
 | ||||
|         self._typedSign = False     # reset state var | ||||
| 
 | ||||
|         if replacement is not None: | ||||
|             # Value presented wasn't a legal number, but control should do something | ||||
|             # reasonable instead: | ||||
|             dbg('setting replacement value:', replacement) | ||||
| ##            dbg('setting replacement value:', replacement) | ||||
|             self._SetValue(self._toGUI(replacement)) | ||||
|             sel_start = BaseMaskedTextCtrl.GetValue(self).find(str(abs(replacement)))   # find where it put the 1, so we can select it | ||||
|             sel_to = sel_start + len(str(abs(replacement))) | ||||
|             dbg('queuing selection of (%d, %d)' %(sel_start, sel_to)) | ||||
| ##            dbg('queuing selection of (%d, %d)' %(sel_start, sel_to)) | ||||
|             wx.CallAfter(self.SetInsertionPoint, sel_start) | ||||
|             wx.CallAfter(self.SetSelection, sel_start, sel_to) | ||||
|             dbg(indent=0) | ||||
| ##            dbg(indent=0) | ||||
|             return | ||||
| 
 | ||||
|         # Otherwise, apply appropriate formatting to value: | ||||
| @@ -1016,35 +1019,35 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|         else: | ||||
|             self._isNeg = False | ||||
| 
 | ||||
|         dbg('value:"%s"' % value, 'self._useParens:', self._useParens) | ||||
| ##        dbg('value:"%s"' % value, 'self._useParens:', self._useParens) | ||||
|         if self._fractionWidth: | ||||
|             adjvalue = self._adjustFloat(self._GetNumValue(value).replace('.',self._decimalChar)) | ||||
|         else: | ||||
|             adjvalue = self._adjustInt(self._GetNumValue(value)) | ||||
|         dbg('adjusted value: "%s"' % adjvalue) | ||||
| ##        dbg('adjusted value: "%s"' % adjvalue) | ||||
| 
 | ||||
| 
 | ||||
|         sel_start, sel_to = self._GetSelection()     # record current insertion point | ||||
|         dbg('calling BaseMaskedTextCtrl._SetValue(self, "%s")' % adjvalue) | ||||
| ##        dbg('calling BaseMaskedTextCtrl._SetValue(self, "%s")' % adjvalue) | ||||
|         BaseMaskedTextCtrl._SetValue(self, adjvalue) | ||||
|         # After all actions so far scheduled, check that resulting cursor | ||||
|         # position is appropriate, and move if not: | ||||
|         wx.CallAfter(self._CheckInsertionPoint) | ||||
| 
 | ||||
|         dbg('finished MaskedNumCtrl::_SetValue', indent=0) | ||||
| ##        dbg('finished NumCtrl::_SetValue', indent=0) | ||||
| 
 | ||||
|     def _CheckInsertionPoint(self): | ||||
|         # If current insertion point is before the end of the integer and | ||||
|         # its before the 1st digit, place it just after the sign position: | ||||
|         dbg('MaskedNumCtrl::CheckInsertionPoint', indent=1) | ||||
| ##        dbg('NumCtrl::CheckInsertionPoint', indent=1) | ||||
|         sel_start, sel_to = self._GetSelection() | ||||
|         text = self._GetValue() | ||||
|         if sel_to < self._fields[0]._extent[1] and text[sel_to] in (' ', '-', '('): | ||||
|             text, signpos, right_signpos = self._getSignedValue() | ||||
|             dbg('setting selection(%d, %d)' % (signpos+1, signpos+1)) | ||||
| ##            dbg('setting selection(%d, %d)' % (signpos+1, signpos+1)) | ||||
|             self.SetInsertionPoint(signpos+1) | ||||
|             self.SetSelection(signpos+1, signpos+1) | ||||
|         dbg(indent=0) | ||||
| ##        dbg(indent=0) | ||||
| 
 | ||||
| 
 | ||||
|     def _OnErase( self, event ): | ||||
| @@ -1053,7 +1056,7 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|         grouping characters auto selects the digit before or after the | ||||
|         grouping character, so that the erasure does the right thing. | ||||
|         """ | ||||
|         dbg('MaskedNumCtrl::_OnErase', indent=1) | ||||
| ##        dbg('NumCtrl::_OnErase', indent=1) | ||||
| 
 | ||||
|         #if grouping digits, make sure deletes next to group char always | ||||
|         # delete next digit to appropriate side: | ||||
| @@ -1086,21 +1089,21 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|                     self.SetSelection(sel_start, sel_to+1) | ||||
| 
 | ||||
|         BaseMaskedTextCtrl._OnErase(self, event) | ||||
|         dbg(indent=0) | ||||
| ##        dbg(indent=0) | ||||
| 
 | ||||
| 
 | ||||
|     def OnTextChange( self, event ): | ||||
|         """ | ||||
|         Handles an event indicating that the text control's value | ||||
|         has changed, and issue EVT_MaskedNum event. | ||||
|         has changed, and issue EVT_NUM event. | ||||
|         NOTE: using wxTextCtrl.SetValue() to change the control's | ||||
|         contents from within a EVT_CHAR handler can cause double | ||||
|         text events.  So we check for actual changes to the text | ||||
|         before passing the events on. | ||||
|         """ | ||||
|         dbg('MaskedNumCtrl::OnTextChange', indent=1) | ||||
| ##        dbg('NumCtrl::OnTextChange', indent=1) | ||||
|         if not BaseMaskedTextCtrl._OnTextChange(self, event): | ||||
|             dbg(indent=0) | ||||
| ##            dbg(indent=0) | ||||
|             return | ||||
| 
 | ||||
|         # else... legal value | ||||
| @@ -1109,14 +1112,14 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|         if value != self._oldvalue: | ||||
|             try: | ||||
|                 self.GetEventHandler().ProcessEvent( | ||||
|                     MaskedNumNumberUpdatedEvent( self.GetId(), self.GetValue(), self ) ) | ||||
|                     NumberUpdatedEvent( self.GetId(), self.GetValue(), self ) ) | ||||
|             except ValueError: | ||||
|                 dbg(indent=0) | ||||
| ##                dbg(indent=0) | ||||
|                 return | ||||
|             # let normal processing of the text continue | ||||
|             event.Skip() | ||||
|         self._oldvalue = value # record for next event | ||||
|         dbg(indent=0) | ||||
| ##        dbg(indent=0) | ||||
| 
 | ||||
|     def _GetValue(self): | ||||
|         """ | ||||
| @@ -1172,7 +1175,7 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|         If min > the max value allowed by the width of the control, | ||||
|         the function will return False, and the min will not be set. | ||||
|         """ | ||||
|         dbg('MaskedNumCtrl::SetMin(%s)' % repr(min), indent=1) | ||||
| ##        dbg('NumCtrl::SetMin(%s)' % repr(min), indent=1) | ||||
|         if( self._max is None | ||||
|             or min is None | ||||
|             or (self._max is not None and self._max >= min) ): | ||||
| @@ -1183,7 +1186,7 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|                 bRet = False | ||||
|         else: | ||||
|             bRet = False | ||||
|         dbg(indent=0) | ||||
| ##        dbg(indent=0) | ||||
|         return bRet | ||||
| 
 | ||||
|     def GetMin(self): | ||||
| @@ -1286,14 +1289,14 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|         also be called with a value to see if that value would fall within | ||||
|         the current bounds of the given control. | ||||
|         """ | ||||
|         dbg('IsInBounds(%s)' % repr(value), indent=1) | ||||
| ##        dbg('IsInBounds(%s)' % repr(value), indent=1) | ||||
|         if value is None: | ||||
|             value = self.GetValue() | ||||
|         else: | ||||
|             try: | ||||
|                 value = self._GetNumValue(self._toGUI(value)) | ||||
|             except ValueError, e: | ||||
|                 dbg('error getting NumValue(self._toGUI(value)):', e, indent=0) | ||||
| ##                dbg('error getting NumValue(self._toGUI(value)):', e, indent=0) | ||||
|                 return False | ||||
|             if value.strip() == '': | ||||
|                 value = None | ||||
| @@ -1309,10 +1312,10 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
| 
 | ||||
|         # if bounds set, and value is None, return False | ||||
|         if value == None and (min is not None or max is not None): | ||||
|             dbg('finished IsInBounds', indent=0) | ||||
| ##            dbg('finished IsInBounds', indent=0) | ||||
|             return 0 | ||||
|         else: | ||||
|             dbg('finished IsInBounds', indent=0) | ||||
| ##            dbg('finished IsInBounds', indent=0) | ||||
|             return min <= value <= max | ||||
| 
 | ||||
| 
 | ||||
| @@ -1383,21 +1386,21 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|         type and bounds checking and raises ValueError if argument is | ||||
|         not a valid value. | ||||
|         """ | ||||
|         dbg('MaskedNumCtrl::_toGUI(%s)' % repr(value), indent=1) | ||||
| ##        dbg('NumCtrl::_toGUI(%s)' % repr(value), indent=1) | ||||
|         if value is None and self.IsNoneAllowed(): | ||||
|             dbg(indent=0) | ||||
| ##            dbg(indent=0) | ||||
|             return self._template | ||||
| 
 | ||||
|         elif type(value) in (types.StringType, types.UnicodeType): | ||||
|             value = self._GetNumValue(value) | ||||
|             dbg('cleansed num value: "%s"' % value) | ||||
| ##            dbg('cleansed num value: "%s"' % value) | ||||
|             if value == "": | ||||
|                 if self.IsNoneAllowed(): | ||||
|                     dbg(indent=0) | ||||
| ##                    dbg(indent=0) | ||||
|                     return self._template | ||||
|                 else: | ||||
|                     dbg('exception raised:', e, indent=0) | ||||
|                     raise ValueError ('wxMaskedNumCtrl requires numeric value, passed %s'% repr(value) ) | ||||
| ##                    dbg('exception raised:', e, indent=0) | ||||
|                     raise ValueError ('NumCtrl requires numeric value, passed %s'% repr(value) ) | ||||
|             # else... | ||||
|             try: | ||||
|                 if self._fractionWidth or value.find('.') != -1: | ||||
| @@ -1405,13 +1408,13 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|                 else: | ||||
|                     value = long(value) | ||||
|             except Exception, e: | ||||
|                 dbg('exception raised:', e, indent=0) | ||||
|                 raise ValueError ('MaskedNumCtrl requires numeric value, passed %s'% repr(value) ) | ||||
| ##                dbg('exception raised:', e, indent=0) | ||||
|                 raise ValueError ('NumCtrl requires numeric value, passed %s'% repr(value) ) | ||||
| 
 | ||||
|         elif type(value) not in (types.IntType, types.LongType, types.FloatType): | ||||
|             dbg(indent=0) | ||||
| ##            dbg(indent=0) | ||||
|             raise ValueError ( | ||||
|                 'MaskedNumCtrl requires numeric value, passed %s'% repr(value) ) | ||||
|                 'NumCtrl requires numeric value, passed %s'% repr(value) ) | ||||
| 
 | ||||
|         if not self._allowNegative and value < 0: | ||||
|             raise ValueError ( | ||||
| @@ -1421,29 +1424,29 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|             min = self.GetMin() | ||||
|             max = self.GetMax() | ||||
|             if not min is None and value < min: | ||||
|                 dbg(indent=0) | ||||
| ##                dbg(indent=0) | ||||
|                 raise ValueError ( | ||||
|                     'value %d is below minimum value of control'% value ) | ||||
|             if not max is None and value > max: | ||||
|                 dbg(indent=0) | ||||
| ##                dbg(indent=0) | ||||
|                 raise ValueError ( | ||||
|                     'value %d exceeds value of control'% value ) | ||||
| 
 | ||||
|         adjustwidth = len(self._mask) - (1 * self._useParens * self._signOk) | ||||
|         dbg('len(%s):' % self._mask, len(self._mask)) | ||||
|         dbg('adjustwidth - groupSpace:', adjustwidth - self._groupSpace) | ||||
|         dbg('adjustwidth:', adjustwidth) | ||||
| ##        dbg('len(%s):' % self._mask, len(self._mask)) | ||||
| ##        dbg('adjustwidth - groupSpace:', adjustwidth - self._groupSpace) | ||||
| ##        dbg('adjustwidth:', adjustwidth) | ||||
|         if self._fractionWidth == 0: | ||||
|             s = str(long(value)).rjust(self._integerWidth) | ||||
|         else: | ||||
|             format = '%' + '%d.%df' % (self._integerWidth+self._fractionWidth+1, self._fractionWidth) | ||||
|             s = format % float(value) | ||||
|         dbg('s:"%s"' % s, 'len(s):', len(s)) | ||||
| ##        dbg('s:"%s"' % s, 'len(s):', len(s)) | ||||
|         if len(s) > (adjustwidth - self._groupSpace): | ||||
|             dbg(indent=0) | ||||
| ##            dbg(indent=0) | ||||
|             raise ValueError ('value %s exceeds the integer width of the control (%d)' % (s, self._integerWidth)) | ||||
|         elif s[0] not in ('-', ' ') and self._allowNegative and len(s) == (adjustwidth - self._groupSpace): | ||||
|             dbg(indent=0) | ||||
| ##            dbg(indent=0) | ||||
|             raise ValueError ('value %s exceeds the integer width of the control (%d)' % (s, self._integerWidth)) | ||||
| 
 | ||||
|         s = s.rjust(adjustwidth).replace('.', self._decimalChar) | ||||
| @@ -1452,7 +1455,7 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|                 s = s.replace('-', '(') + ')' | ||||
|             else: | ||||
|                 s += ' ' | ||||
|         dbg('returned: "%s"' % s, indent=0) | ||||
| ##        dbg('returned: "%s"' % s, indent=0) | ||||
|         return s | ||||
| 
 | ||||
| 
 | ||||
| @@ -1460,8 +1463,8 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|         """ | ||||
|         Conversion function used in getting the value of the control. | ||||
|         """ | ||||
|         dbg(suspend=0) | ||||
|         dbg('MaskedNumCtrl::_fromGUI(%s)' % value, indent=1) | ||||
| ##        dbg(suspend=0) | ||||
| ##        dbg('NumCtrl::_fromGUI(%s)' % value, indent=1) | ||||
|         # One or more of the underlying text control implementations | ||||
|         # issue an intermediate EVT_TEXT when replacing the control's | ||||
|         # value, where the intermediate value is an empty string. | ||||
| @@ -1470,42 +1473,42 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|         # | ||||
|         if value.strip() == '': | ||||
|             if not self.IsNoneAllowed(): | ||||
|                 dbg('empty value; not allowed,returning 0', indent = 0) | ||||
| ##                dbg('empty value; not allowed,returning 0', indent = 0) | ||||
|                 if self._fractionWidth: | ||||
|                     return 0.0 | ||||
|                 else: | ||||
|                     return 0 | ||||
|             else: | ||||
|                 dbg('empty value; returning None', indent = 0) | ||||
| ##                dbg('empty value; returning None', indent = 0) | ||||
|                 return None | ||||
|         else: | ||||
|             value = self._GetNumValue(value) | ||||
|             dbg('Num value: "%s"' % value) | ||||
| ##            dbg('Num value: "%s"' % value) | ||||
|             if self._fractionWidth: | ||||
|                 try: | ||||
|                     dbg(indent=0) | ||||
| ##                    dbg(indent=0) | ||||
|                     return float( value ) | ||||
|                 except ValueError: | ||||
|                     dbg("couldn't convert to float; returning None") | ||||
| ##                    dbg("couldn't convert to float; returning None") | ||||
|                     return None | ||||
|                 else: | ||||
|                     raise | ||||
|             else: | ||||
|                 try: | ||||
|                     dbg(indent=0) | ||||
| ##                    dbg(indent=0) | ||||
|                     return int( value ) | ||||
|                 except ValueError: | ||||
|                     try: | ||||
|                        dbg(indent=0) | ||||
| ##                       dbg(indent=0) | ||||
|                        return long( value ) | ||||
|                     except ValueError: | ||||
|                        dbg("couldn't convert to long; returning None") | ||||
| ##                       dbg("couldn't convert to long; returning None") | ||||
|                        return None | ||||
| 
 | ||||
|                     else: | ||||
|                        raise | ||||
|                 else: | ||||
|                     dbg('exception occurred; returning None') | ||||
| ##                    dbg('exception occurred; returning None') | ||||
|                     return None | ||||
| 
 | ||||
| 
 | ||||
| @@ -1514,7 +1517,7 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | ||||
|         Preprocessor for base control paste; if value needs to be right-justified | ||||
|         to fit in control, do so prior to paste: | ||||
|         """ | ||||
|         dbg('MaskedNumCtrl::_Paste (value = "%s")' % value) | ||||
| ##        dbg('NumCtrl::_Paste (value = "%s")' % value) | ||||
|         if value is None: | ||||
|             paste_text = self._getClipboardContents() | ||||
|         else: | ||||
| @@ -1545,7 +1548,7 @@ if __name__ == '__main__': | ||||
|             style = wx.DEFAULT_DIALOG_STYLE ): | ||||
|             wx.Dialog.__init__(self, parent, id, title, pos, size, style) | ||||
| 
 | ||||
|             self.int_ctrl = MaskedNumCtrl(self, wx.NewId(), size=(55,20)) | ||||
|             self.int_ctrl = NumCtrl(self, wx.NewId(), size=(55,20)) | ||||
|             self.OK = wx.Button( self, wx.ID_OK, "OK") | ||||
|             self.Cancel = wx.Button( self, wx.ID_CANCEL, "Cancel") | ||||
| 
 | ||||
| @@ -1560,7 +1563,7 @@ if __name__ == '__main__': | ||||
|             self.SetSizer( vs ) | ||||
|             vs.Fit( self ) | ||||
|             vs.SetSizeHints( self ) | ||||
|             self.Bind(EVT_MASKEDNUM, self.OnChange, self.int_ctrl) | ||||
|             self.Bind(EVT_NUM, self.OnChange, self.int_ctrl) | ||||
| 
 | ||||
|         def OnChange(self, event): | ||||
|             print 'value now', event.GetValue() | ||||
| @@ -1578,7 +1581,7 @@ if __name__ == '__main__': | ||||
|             return True | ||||
| 
 | ||||
|         def OnClick(self, event): | ||||
|             dlg = myDialog(self.panel, -1, "test MaskedNumCtrl") | ||||
|             dlg = myDialog(self.panel, -1, "test NumCtrl") | ||||
|             dlg.int_ctrl.SetValue(501) | ||||
|             dlg.int_ctrl.SetInsertionPoint(1) | ||||
|             dlg.int_ctrl.SetSelection(1,2) | ||||
							
								
								
									
										325
									
								
								wxPython/wx/lib/masked/textctrl.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										325
									
								
								wxPython/wx/lib/masked/textctrl.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,325 @@ | ||||
| #---------------------------------------------------------------------------- | ||||
| # Name:         masked.textctrl.py | ||||
| # Authors:      Jeff Childers, Will Sadkin | ||||
| # Email:        jchilders_98@yahoo.com, wsadkin@nameconnector.com | ||||
| # Created:      02/11/2003 | ||||
| # Copyright:    (c) 2003 by Jeff Childers, Will Sadkin, 2003 | ||||
| # Portions:     (c) 2002 by Will Sadkin, 2002-2003 | ||||
| # RCS-ID:       $Id$ | ||||
| # License:      wxWidgets license | ||||
| #---------------------------------------------------------------------------- | ||||
| # | ||||
| # This file contains the most typically used generic masked control, | ||||
| # masked.TextCtrl.  It also defines the BaseMaskedTextCtrl, which can | ||||
| # be used to derive other "semantics-specific" classes, like masked.NumCtrl, | ||||
| # masked.TimeCtrl, and masked.IpAddrCtrl. | ||||
| # | ||||
| #---------------------------------------------------------------------------- | ||||
| import  wx | ||||
| from wx.lib.masked import * | ||||
|  | ||||
| # jmg 12/9/03 - when we cut ties with Py 2.2 and earlier, this would | ||||
| # be a good place to implement the 2.3 logger class | ||||
| from wx.tools.dbg import Logger | ||||
| dbg = Logger() | ||||
| ##dbg(enable=0) | ||||
|  | ||||
| # ## TRICKY BIT: to avoid a ton of boiler-plate, and to | ||||
| # ## automate the getter/setter generation for each valid | ||||
| # ## control parameter so we never forget to add the | ||||
| # ## functions when adding parameters, this loop | ||||
| # ## programmatically adds them to the class: | ||||
| # ## (This makes it easier for Designers like Boa to | ||||
| # ## deal with masked controls.) | ||||
| # | ||||
| # ## To further complicate matters, this is done with an | ||||
| # ## extra level of inheritance, so that "general" classes like | ||||
| # ## MaskedTextCtrl can have all possible attributes, | ||||
| # ## while derived classes, like TimeCtrl and MaskedNumCtrl | ||||
| # ## can prevent exposure of those optional attributes of their base | ||||
| # ## class that do not make sense for their derivation.  Therefore, | ||||
| # ## we define | ||||
| # ##    BaseMaskedTextCtrl(TextCtrl, MaskedEditMixin) | ||||
| # ## and | ||||
| # ##    MaskedTextCtrl(BaseMaskedTextCtrl, MaskedEditAccessorsMixin). | ||||
| # ## | ||||
| # ## This allows us to then derive: | ||||
| # ##    MaskedNumCtrl( BaseMaskedTextCtrl ) | ||||
| # ## | ||||
| # ## and not have to expose all the same accessor functions for the | ||||
| # ## derived control when they don't all make sense for it. | ||||
| # ## | ||||
|  | ||||
| class BaseMaskedTextCtrl( wx.TextCtrl, MaskedEditMixin ): | ||||
|     """ | ||||
|     This is the primary derivation from MaskedEditMixin.  It provides | ||||
|     a general masked text control that can be configured with different | ||||
|     masks.  It's actually a "base masked textCtrl", so that the | ||||
|     MaskedTextCtrl class can be derived from it, and add those | ||||
|     accessor functions to it that are appropriate to the general class, | ||||
|     whilst other classes can derive from BaseMaskedTextCtrl, and | ||||
|     only define those accessor functions that are appropriate for | ||||
|     those derivations. | ||||
|     """ | ||||
|  | ||||
|     def __init__( self, parent, id=-1, value = '', | ||||
|                   pos = wx.DefaultPosition, | ||||
|                   size = wx.DefaultSize, | ||||
|                   style = wx.TE_PROCESS_TAB, | ||||
|                   validator=wx.DefaultValidator,     ## placeholder provided for data-transfer logic | ||||
|                   name = 'maskedTextCtrl', | ||||
|                   setupEventHandling = True,        ## setup event handling by default | ||||
|                   **kwargs): | ||||
|  | ||||
|         wx.TextCtrl.__init__(self, parent, id, value='', | ||||
|                             pos=pos, size = size, | ||||
|                             style=style, validator=validator, | ||||
|                             name=name) | ||||
|  | ||||
|         self.controlInitialized = True | ||||
|         MaskedEditMixin.__init__( self, name, **kwargs ) | ||||
|  | ||||
|         self._SetInitialValue(value) | ||||
|  | ||||
|         if setupEventHandling: | ||||
|             ## Setup event handlers | ||||
|             self.Bind(wx.EVT_SET_FOCUS, self._OnFocus )         ## defeat automatic full selection | ||||
|             self.Bind(wx.EVT_KILL_FOCUS, self._OnKillFocus )    ## run internal validator | ||||
|             self.Bind(wx.EVT_LEFT_DCLICK, self._OnDoubleClick)  ## select field under cursor on dclick | ||||
|             self.Bind(wx.EVT_RIGHT_UP, self._OnContextMenu )    ## bring up an appropriate context menu | ||||
|             self.Bind(wx.EVT_KEY_DOWN, self._OnKeyDown )        ## capture control events not normally seen, eg ctrl-tab. | ||||
|             self.Bind(wx.EVT_CHAR, self._OnChar )               ## handle each keypress | ||||
|             self.Bind(wx.EVT_TEXT, self._OnTextChange )         ## color control appropriately & keep | ||||
|                                                                 ## track of previous value for undo | ||||
|  | ||||
|  | ||||
|     def __repr__(self): | ||||
|         return "<BaseMaskedTextCtrl: %s>" % self.GetValue() | ||||
|  | ||||
|  | ||||
|     def _GetSelection(self): | ||||
|         """ | ||||
|         Allow mixin to get the text selection of this control. | ||||
|         REQUIRED by any class derived from MaskedEditMixin. | ||||
|         """ | ||||
|         return self.GetSelection() | ||||
|  | ||||
|     def _SetSelection(self, sel_start, sel_to): | ||||
|         """ | ||||
|         Allow mixin to set the text selection of this control. | ||||
|         REQUIRED by any class derived from MaskedEditMixin. | ||||
|         """ | ||||
| ####        dbg("MaskedTextCtrl::_SetSelection(%(sel_start)d, %(sel_to)d)" % locals()) | ||||
|         return self.SetSelection( sel_start, sel_to ) | ||||
|  | ||||
|     def SetSelection(self, sel_start, sel_to): | ||||
|         """ | ||||
|         This is just for debugging... | ||||
|         """ | ||||
| ##        dbg("MaskedTextCtrl::SetSelection(%(sel_start)d, %(sel_to)d)" % locals()) | ||||
|         wx.TextCtrl.SetSelection(self, sel_start, sel_to) | ||||
|  | ||||
|  | ||||
|     def _GetInsertionPoint(self): | ||||
|         return self.GetInsertionPoint() | ||||
|  | ||||
|     def _SetInsertionPoint(self, pos): | ||||
| ####        dbg("MaskedTextCtrl::_SetInsertionPoint(%(pos)d)" % locals()) | ||||
|         self.SetInsertionPoint(pos) | ||||
|  | ||||
|     def SetInsertionPoint(self, pos): | ||||
|         """ | ||||
|         This is just for debugging... | ||||
|         """ | ||||
| ##        dbg("MaskedTextCtrl::SetInsertionPoint(%(pos)d)" % locals()) | ||||
|         wx.TextCtrl.SetInsertionPoint(self, pos) | ||||
|  | ||||
|  | ||||
|     def _GetValue(self): | ||||
|         """ | ||||
|         Allow mixin to get the raw value of the control with this function. | ||||
|         REQUIRED by any class derived from MaskedEditMixin. | ||||
|         """ | ||||
|         return self.GetValue() | ||||
|  | ||||
|     def _SetValue(self, value): | ||||
|         """ | ||||
|         Allow mixin to set the raw value of the control with this function. | ||||
|         REQUIRED by any class derived from MaskedEditMixin. | ||||
|         """ | ||||
| ##        dbg('MaskedTextCtrl::_SetValue("%(value)s")' % locals(), indent=1) | ||||
|         # Record current selection and insertion point, for undo | ||||
|         self._prevSelection = self._GetSelection() | ||||
|         self._prevInsertionPoint = self._GetInsertionPoint() | ||||
|         wx.TextCtrl.SetValue(self, value) | ||||
| ##        dbg(indent=0) | ||||
|  | ||||
|     def SetValue(self, value): | ||||
|         """ | ||||
|         This function redefines the externally accessible .SetValue to be | ||||
|         a smart "paste" of the text in question, so as not to corrupt the | ||||
|         masked control.  NOTE: this must be done in the class derived | ||||
|         from the base wx control. | ||||
|         """ | ||||
| ##        dbg('MaskedTextCtrl::SetValue = "%s"' % value, indent=1) | ||||
|  | ||||
|         if not self._mask: | ||||
|             wx.TextCtrl.SetValue(self, value)    # revert to base control behavior | ||||
|             return | ||||
|  | ||||
|         # empty previous contents, replacing entire value: | ||||
|         self._SetInsertionPoint(0) | ||||
|         self._SetSelection(0, self._masklength) | ||||
|         if self._signOk and self._useParens: | ||||
|             signpos = value.find('-') | ||||
|             if signpos != -1: | ||||
|                 value = value[:signpos] + '(' + value[signpos+1:].strip() + ')' | ||||
|             elif value.find(')') == -1 and len(value) < self._masklength: | ||||
|                 value += ' '    # add place holder for reserved space for right paren | ||||
|  | ||||
|         if( len(value) < self._masklength                # value shorter than control | ||||
|             and (self._isFloat or self._isInt)            # and it's a numeric control | ||||
|             and self._ctrl_constraints._alignRight ):   # and it's a right-aligned control | ||||
|  | ||||
| ##            dbg('len(value)', len(value), ' < self._masklength', self._masklength) | ||||
|             # try to intelligently "pad out" the value to the right size: | ||||
|             value = self._template[0:self._masklength - len(value)] + value | ||||
|             if self._isFloat and value.find('.') == -1: | ||||
|                 value = value[1:] | ||||
| ##            dbg('padded value = "%s"' % value) | ||||
|  | ||||
|         # make SetValue behave the same as if you had typed the value in: | ||||
|         try: | ||||
|             value = self._Paste(value, raise_on_invalid=True, just_return_value=True) | ||||
|             if self._isFloat: | ||||
|                 self._isNeg = False     # (clear current assumptions) | ||||
|                 value = self._adjustFloat(value) | ||||
|             elif self._isInt: | ||||
|                 self._isNeg = False     # (clear current assumptions) | ||||
|                 value = self._adjustInt(value) | ||||
|             elif self._isDate and not self.IsValid(value) and self._4digityear: | ||||
|                 value = self._adjustDate(value, fixcentury=True) | ||||
|         except ValueError: | ||||
|             # If date, year might be 2 digits vs. 4; try adjusting it: | ||||
|             if self._isDate and self._4digityear: | ||||
|                 dateparts = value.split(' ') | ||||
|                 dateparts[0] = self._adjustDate(dateparts[0], fixcentury=True) | ||||
|                 value = string.join(dateparts, ' ') | ||||
| ##                dbg('adjusted value: "%s"' % value) | ||||
|                 value = self._Paste(value, raise_on_invalid=True, just_return_value=True) | ||||
|             else: | ||||
| ##                dbg('exception thrown', indent=0) | ||||
|                 raise | ||||
|  | ||||
|         self._SetValue(value)   # note: to preserve similar capability, .SetValue() | ||||
|                                 # does not change IsModified() | ||||
| ####        dbg('queuing insertion after .SetValue', self._masklength) | ||||
|         wx.CallAfter(self._SetInsertionPoint, self._masklength) | ||||
|         wx.CallAfter(self._SetSelection, self._masklength, self._masklength) | ||||
| ##        dbg(indent=0) | ||||
|  | ||||
|  | ||||
|     def Clear(self): | ||||
|         """ Blanks the current control value by replacing it with the default value.""" | ||||
| ##        dbg("MaskedTextCtrl::Clear - value reset to default value (template)") | ||||
|         if self._mask: | ||||
|             self.ClearValue() | ||||
|         else: | ||||
|             wx.TextCtrl.Clear(self)    # else revert to base control behavior | ||||
|  | ||||
|  | ||||
|     def _Refresh(self): | ||||
|         """ | ||||
|         Allow mixin to refresh the base control with this function. | ||||
|         REQUIRED by any class derived from MaskedEditMixin. | ||||
|         """ | ||||
| ##        dbg('MaskedTextCtrl::_Refresh', indent=1) | ||||
|         wx.TextCtrl.Refresh(self) | ||||
| ##        dbg(indent=0) | ||||
|  | ||||
|  | ||||
|     def Refresh(self): | ||||
|         """ | ||||
|         This function redefines the externally accessible .Refresh() to | ||||
|         validate the contents of the masked control as it refreshes. | ||||
|         NOTE: this must be done in the class derived from the base wx control. | ||||
|         """ | ||||
| ##        dbg('MaskedTextCtrl::Refresh', indent=1) | ||||
|         self._CheckValid() | ||||
|         self._Refresh() | ||||
| ##        dbg(indent=0) | ||||
|  | ||||
|  | ||||
|     def _IsEditable(self): | ||||
|         """ | ||||
|         Allow mixin to determine if the base control is editable with this function. | ||||
|         REQUIRED by any class derived from MaskedEditMixin. | ||||
|         """ | ||||
|         return wx.TextCtrl.IsEditable(self) | ||||
|  | ||||
|  | ||||
|     def Cut(self): | ||||
|         """ | ||||
|         This function redefines the externally accessible .Cut to be | ||||
|         a smart "erase" of the text in question, so as not to corrupt the | ||||
|         masked control.  NOTE: this must be done in the class derived | ||||
|         from the base wx control. | ||||
|         """ | ||||
|         if self._mask: | ||||
|             self._Cut()             # call the mixin's Cut method | ||||
|         else: | ||||
|             wx.TextCtrl.Cut(self)    # else revert to base control behavior | ||||
|  | ||||
|  | ||||
|     def Paste(self): | ||||
|         """ | ||||
|         This function redefines the externally accessible .Paste to be | ||||
|         a smart "paste" of the text in question, so as not to corrupt the | ||||
|         masked control.  NOTE: this must be done in the class derived | ||||
|         from the base wx control. | ||||
|         """ | ||||
|         if self._mask: | ||||
|             self._Paste()                   # call the mixin's Paste method | ||||
|         else: | ||||
|             wx.TextCtrl.Paste(self, value)   # else revert to base control behavior | ||||
|  | ||||
|  | ||||
|     def Undo(self): | ||||
|         """ | ||||
|         This function defines the undo operation for the control. (The default | ||||
|         undo is 1-deep.) | ||||
|         """ | ||||
|         if self._mask: | ||||
|             self._Undo() | ||||
|         else: | ||||
|             wx.TextCtrl.Undo(self)   # else revert to base control behavior | ||||
|  | ||||
|  | ||||
|     def IsModified(self): | ||||
|         """ | ||||
|         This function overrides the raw wxTextCtrl method, because the | ||||
|         masked edit mixin uses SetValue to change the value, which doesn't | ||||
|         modify the state of this attribute.  So, we keep track on each | ||||
|         keystroke to see if the value changes, and if so, it's been | ||||
|         modified. | ||||
|         """ | ||||
|         return wx.TextCtrl.IsModified(self) or self.modified | ||||
|  | ||||
|  | ||||
|     def _CalcSize(self, size=None): | ||||
|         """ | ||||
|         Calculate automatic size if allowed; use base mixin function. | ||||
|         """ | ||||
|         return self._calcSize(size) | ||||
|  | ||||
|  | ||||
| class TextCtrl( BaseMaskedTextCtrl, MaskedEditAccessorsMixin ): | ||||
|     """ | ||||
|     This extra level of inheritance allows us to add the generic set of | ||||
|     masked edit parameters only to this class while allowing other | ||||
|     classes to derive from the "base" masked text control, and provide | ||||
|     a smaller set of valid accessor functions. | ||||
|     """ | ||||
|     pass | ||||
|  | ||||
|  | ||||
| @@ -39,8 +39,8 @@ | ||||
| # | ||||
| # 12/20/2003 - Jeff Grimmett (grimmtooth@softhome.net) | ||||
| # | ||||
| # o wxMaskedTextCtrl -> MaskedTextCtrl | ||||
| # o wxTimeCtrl -> TimeCtrl | ||||
| # o wxMaskedTextCtrl -> masked.TextCtrl | ||||
| # o wxTimeCtrl -> masked.TimeCtrl | ||||
| # | ||||
| 
 | ||||
| """<html><body> | ||||
| @@ -272,10 +272,10 @@ import  types | ||||
| import  wx | ||||
| 
 | ||||
| from wx.tools.dbg import Logger | ||||
| from wx.lib.maskededit import BaseMaskedTextCtrl, Field | ||||
| from wx.lib.masked import Field, BaseMaskedTextCtrl | ||||
| 
 | ||||
| dbg = Logger() | ||||
| dbg(enable=0) | ||||
| ##dbg(enable=0) | ||||
| 
 | ||||
| try: | ||||
|     from mx import DateTime | ||||
| @@ -333,7 +333,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|         'max': None, | ||||
|         'limited': False,           # by default, no limiting even if bounds set | ||||
|         'useFixedWidthFont': True,  # by default, use a fixed-width font | ||||
|         'oob_color': "Yellow"       # by default, the default MaskedTextCtrl "invalid" color | ||||
|         'oob_color': "Yellow"       # by default, the default masked.TextCtrl "invalid" color | ||||
|         } | ||||
| 
 | ||||
|     def __init__ ( | ||||
| @@ -347,7 +347,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|                 **kwargs ): | ||||
| 
 | ||||
|         # set defaults for control: | ||||
|         dbg('setting defaults:') | ||||
| ##        dbg('setting defaults:') | ||||
|         for key, param_value in TimeCtrl.valid_ctrl_params.items(): | ||||
|             # This is done this way to make setattr behave consistently with | ||||
|             # "private attribute" name mangling | ||||
| @@ -456,7 +456,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
| 
 | ||||
| 
 | ||||
|     def SetParameters(self, **kwargs): | ||||
|         dbg('TimeCtrl::SetParameters(%s)' % repr(kwargs), indent=1) | ||||
| ##        dbg('TimeCtrl::SetParameters(%s)' % repr(kwargs), indent=1) | ||||
|         maskededit_kwargs = {} | ||||
|         reset_format = False | ||||
| 
 | ||||
| @@ -553,10 +553,10 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|                 self.SetValue(value) | ||||
|             except: | ||||
|                 self.SetValue('12:00:00 AM') | ||||
|             dbg(indent=0) | ||||
| ##            dbg(indent=0) | ||||
|             return {}   # no arguments to return | ||||
|         else: | ||||
|             dbg(indent=0) | ||||
| ##            dbg(indent=0) | ||||
|             return maskededit_kwargs | ||||
| 
 | ||||
| 
 | ||||
| @@ -565,7 +565,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|         This function binds an externally created spin button to the control, so that | ||||
|         up/down events from the button automatically change the control. | ||||
|         """ | ||||
|         dbg('TimeCtrl::BindSpinButton') | ||||
| ##        dbg('TimeCtrl::BindSpinButton') | ||||
|         self.__spinButton = sb | ||||
|         if self.__spinButton: | ||||
|             # bind event handlers to spin ctrl | ||||
| @@ -584,16 +584,16 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|         and convert wxDateTime, mxDateTime, or 12/24 format time string | ||||
|         into the appropriate format string for the control. | ||||
|         """ | ||||
|         dbg('TimeCtrl::SetValue(%s)' % repr(value), indent=1) | ||||
| ##        dbg('TimeCtrl::SetValue(%s)' % repr(value), indent=1) | ||||
|         try: | ||||
|             strtime = self._toGUI(self.__validateValue(value)) | ||||
|         except: | ||||
|             dbg('validation failed', indent=0) | ||||
| ##            dbg('validation failed', indent=0) | ||||
|             raise | ||||
| 
 | ||||
|         dbg('strtime:', strtime) | ||||
| ##        dbg('strtime:', strtime) | ||||
|         self._SetValue(strtime) | ||||
|         dbg(indent=0) | ||||
| ##        dbg(indent=0) | ||||
| 
 | ||||
|     def GetValue(self, | ||||
|                  as_wxDateTime = False, | ||||
| @@ -641,12 +641,12 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|         raised. | ||||
|         """ | ||||
|         global accept_mx | ||||
|         dbg(suspend=1) | ||||
|         dbg('TimeCtrl::GetWxDateTime(%s)' % repr(value), indent=1) | ||||
| ##        dbg(suspend=1) | ||||
| ##        dbg('TimeCtrl::GetWxDateTime(%s)' % repr(value), indent=1) | ||||
|         if value is None: | ||||
|             dbg('getting control value') | ||||
| ##            dbg('getting control value') | ||||
|             value = self.GetValue() | ||||
|             dbg('value = "%s"' % value) | ||||
| ##            dbg('value = "%s"' % value) | ||||
| 
 | ||||
|         if type(value) == types.UnicodeType: | ||||
|             value = str(value)  # convert to regular string | ||||
| @@ -656,14 +656,14 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
| 
 | ||||
|             # Construct constant wxDateTime, then try to parse the string: | ||||
|             wxdt = wx.DateTimeFromDMY(1, 0, 1970) | ||||
|             dbg('attempting conversion') | ||||
| ##            dbg('attempting conversion') | ||||
|             value = value.strip()    # (parser doesn't like leading spaces) | ||||
|             checkTime    = wxdt.ParseTime(value) | ||||
|             valid = checkTime == len(value)     # entire string parsed? | ||||
|             dbg('checkTime == len(value)?', valid) | ||||
| ##            dbg('checkTime == len(value)?', valid) | ||||
| 
 | ||||
|             if not valid: | ||||
|                 dbg(indent=0, suspend=0) | ||||
| ##                dbg(indent=0, suspend=0) | ||||
|                 raise ValueError('cannot convert string "%s" to valid time' % value) | ||||
| 
 | ||||
|         else: | ||||
| @@ -685,7 +685,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|                     error = 'GetWxDateTime requires wxDateTime, mxDateTime or parsable time string, passed %s'% repr(value) | ||||
|                 else: | ||||
|                     error = 'GetWxDateTime requires wxDateTime or parsable time string, passed %s'% repr(value) | ||||
|                 dbg(indent=0, suspend=0) | ||||
| ##                dbg(indent=0, suspend=0) | ||||
|                 raise ValueError(error) | ||||
| 
 | ||||
|             wxdt = wx.DateTimeFromDMY(1, 0, 1970) | ||||
| @@ -693,7 +693,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|             wxdt.SetMinute(minute) | ||||
|             wxdt.SetSecond(second) | ||||
| 
 | ||||
|         dbg('wxdt:', wxdt, indent=0, suspend=0) | ||||
| ##        dbg('wxdt:', wxdt, indent=0, suspend=0) | ||||
|         return wxdt | ||||
| 
 | ||||
| 
 | ||||
| @@ -730,13 +730,13 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|         adjusted to the new minimum value; if not limited, the value in the | ||||
|         control will be colored as invalid. | ||||
|         """ | ||||
|         dbg('TimeCtrl::SetMin(%s)'% repr(min), indent=1) | ||||
| ##        dbg('TimeCtrl::SetMin(%s)'% repr(min), indent=1) | ||||
|         if min is not None: | ||||
|             try: | ||||
|                 min = self.GetWxDateTime(min) | ||||
|                 self.__min = self._toGUI(min) | ||||
|             except: | ||||
|                 dbg('exception occurred', indent=0) | ||||
| ##                dbg('exception occurred', indent=0) | ||||
|                 return False | ||||
|         else: | ||||
|             self.__min = min | ||||
| @@ -746,7 +746,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|         else: | ||||
|             self._CheckValid() | ||||
|         ret = True | ||||
|         dbg('ret:', ret, indent=0) | ||||
| ##        dbg('ret:', ret, indent=0) | ||||
|         return ret | ||||
| 
 | ||||
| 
 | ||||
| @@ -757,22 +757,23 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|         the current minimum bound on the control, as a wxDateTime | ||||
|         by default, or as a string if as_string argument is True. | ||||
|         """ | ||||
|         dbg(suspend=1) | ||||
|         dbg('TimeCtrl::GetMin, as_string?', as_string, indent=1) | ||||
| ##        dbg(suspend=1) | ||||
| ##        dbg('TimeCtrl::GetMin, as_string?', as_string, indent=1) | ||||
|         if self.__min is None: | ||||
|             dbg('(min == None)') | ||||
| ##            dbg('(min == None)') | ||||
|             ret = self.__min | ||||
|         elif as_string: | ||||
|             ret = self.__min | ||||
|             dbg('ret:', ret) | ||||
| ##            dbg('ret:', ret) | ||||
|         else: | ||||
|             try: | ||||
|                 ret = self.GetWxDateTime(self.__min) | ||||
|             except: | ||||
|                 dbg(suspend=0) | ||||
|                 dbg('exception occurred', indent=0) | ||||
|             dbg('ret:', repr(ret)) | ||||
|         dbg(indent=0, suspend=0) | ||||
| ##                dbg(suspend=0) | ||||
| ##                dbg('exception occurred', indent=0) | ||||
|                 raise | ||||
| ##            dbg('ret:', repr(ret)) | ||||
| ##        dbg(indent=0, suspend=0) | ||||
|         return ret | ||||
| 
 | ||||
| 
 | ||||
| @@ -789,23 +790,23 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|         adjusted to this maximum value; if not limited, the value in the | ||||
|         control will be colored as invalid. | ||||
|         """ | ||||
|         dbg('TimeCtrl::SetMax(%s)' % repr(max), indent=1) | ||||
| ##        dbg('TimeCtrl::SetMax(%s)' % repr(max), indent=1) | ||||
|         if max is not None: | ||||
|             try: | ||||
|                 max = self.GetWxDateTime(max) | ||||
|                 self.__max = self._toGUI(max) | ||||
|             except: | ||||
|                 dbg('exception occurred', indent=0) | ||||
| ##                dbg('exception occurred', indent=0) | ||||
|                 return False | ||||
|         else: | ||||
|             self.__max = max | ||||
|         dbg('max:', repr(self.__max)) | ||||
| ##        dbg('max:', repr(self.__max)) | ||||
|         if self.IsLimited() and not self.IsInBounds(): | ||||
|             self.SetLimited(self.__limited) # force limited value: | ||||
|         else: | ||||
|             self._CheckValid() | ||||
|         ret = True | ||||
|         dbg('ret:', ret, indent=0) | ||||
| ##        dbg('ret:', ret, indent=0) | ||||
|         return ret | ||||
| 
 | ||||
| 
 | ||||
| @@ -816,23 +817,23 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|         the current minimum bound on the control, as a wxDateTime | ||||
|         by default, or as a string if as_string argument is True. | ||||
|         """ | ||||
|         dbg(suspend=1) | ||||
|         dbg('TimeCtrl::GetMin, as_string?', as_string, indent=1) | ||||
| ##        dbg(suspend=1) | ||||
| ##        dbg('TimeCtrl::GetMin, as_string?', as_string, indent=1) | ||||
|         if self.__max is None: | ||||
|             dbg('(max == None)') | ||||
| ##            dbg('(max == None)') | ||||
|             ret = self.__max | ||||
|         elif as_string: | ||||
|             ret = self.__max | ||||
|             dbg('ret:', ret) | ||||
| ##            dbg('ret:', ret) | ||||
|         else: | ||||
|             try: | ||||
|                 ret = self.GetWxDateTime(self.__max) | ||||
|             except: | ||||
|                 dbg(suspend=0) | ||||
|                 dbg('exception occurred', indent=0) | ||||
| ##                dbg(suspend=0) | ||||
| ##                dbg('exception occurred', indent=0) | ||||
|                 raise | ||||
|             dbg('ret:', repr(ret)) | ||||
|         dbg(indent=0, suspend=0) | ||||
| ##            dbg('ret:', repr(ret)) | ||||
| ##        dbg(indent=0, suspend=0) | ||||
|         return ret | ||||
| 
 | ||||
| 
 | ||||
| @@ -868,22 +869,22 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|         limiting, but coloring of out-of-bounds values will still take | ||||
|         place if bounds have been set for the control. | ||||
|         """ | ||||
|         dbg('TimeCtrl::SetLimited(%d)' % limited, indent=1) | ||||
| ##        dbg('TimeCtrl::SetLimited(%d)' % limited, indent=1) | ||||
|         self.__limited = limited | ||||
| 
 | ||||
|         if not limited: | ||||
|             self.SetMaskParameters(validRequired = False) | ||||
|             self._CheckValid() | ||||
|             dbg(indent=0) | ||||
| ##            dbg(indent=0) | ||||
|             return | ||||
| 
 | ||||
|         dbg('requiring valid value') | ||||
| ##        dbg('requiring valid value') | ||||
|         self.SetMaskParameters(validRequired = True) | ||||
| 
 | ||||
|         min = self.GetMin() | ||||
|         max = self.GetMax() | ||||
|         if min is None or max is None: | ||||
|             dbg('both bounds not set; no further action taken') | ||||
| ##            dbg('both bounds not set; no further action taken') | ||||
|             return  # can't limit without 2 bounds | ||||
| 
 | ||||
|         elif not self.IsInBounds(): | ||||
| @@ -891,11 +892,11 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|             try: | ||||
|                 value = self.GetWxDateTime() | ||||
|             except: | ||||
|                 dbg('exception occurred', indent=0) | ||||
| ##                dbg('exception occurred', indent=0) | ||||
|                 raise | ||||
| 
 | ||||
|             if min <= max:   # valid range doesn't span midnight | ||||
|                 dbg('min <= max') | ||||
| ##                dbg('min <= max') | ||||
|                 # which makes the "nearest bound" computation trickier... | ||||
| 
 | ||||
|                 # determine how long the "invalid" pie wedge is, and cut | ||||
| @@ -918,24 +919,24 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|                     cmp_value = value | ||||
| 
 | ||||
|                 if (cmp_value - max) > half_interval: | ||||
|                     dbg('forcing value to min (%s)' % min.FormatTime()) | ||||
| ##                    dbg('forcing value to min (%s)' % min.FormatTime()) | ||||
|                     self.SetValue(min) | ||||
|                 else: | ||||
|                     dbg('forcing value to max (%s)' % max.FormatTime()) | ||||
| ##                    dbg('forcing value to max (%s)' % max.FormatTime()) | ||||
|                     self.SetValue(max) | ||||
|             else: | ||||
|                 dbg('max < min') | ||||
| ##                dbg('max < min') | ||||
|                 # therefore  max < value < min guaranteed to be true, | ||||
|                 # so "nearest bound" calculation is much easier: | ||||
|                 if (value - max) >= (min - value): | ||||
|                     # current value closer to min; pick that edge of pie wedge | ||||
|                     dbg('forcing value to min (%s)' % min.FormatTime()) | ||||
| ##                    dbg('forcing value to min (%s)' % min.FormatTime()) | ||||
|                     self.SetValue(min) | ||||
|                 else: | ||||
|                     dbg('forcing value to max (%s)' % max.FormatTime()) | ||||
| ##                    dbg('forcing value to max (%s)' % max.FormatTime()) | ||||
|                     self.SetValue(max) | ||||
| 
 | ||||
|         dbg(indent=0) | ||||
| ##        dbg(indent=0) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| @@ -961,21 +962,22 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|             try: | ||||
|                 value = self.GetWxDateTime(value)   # try to regularize passed value | ||||
|             except ValueError: | ||||
|                 dbg('ValueError getting wxDateTime for %s' % repr(value), indent=0) | ||||
| ##                dbg('ValueError getting wxDateTime for %s' % repr(value), indent=0) | ||||
|                 raise | ||||
| 
 | ||||
|         dbg('TimeCtrl::IsInBounds(%s)' % repr(value), indent=1) | ||||
| ##        dbg('TimeCtrl::IsInBounds(%s)' % repr(value), indent=1) | ||||
|         if self.__min is None or self.__max is None: | ||||
|             dbg(indent=0) | ||||
| ##            dbg(indent=0) | ||||
|             return True | ||||
| 
 | ||||
|         elif value is None: | ||||
|             try: | ||||
|                 value = self.GetWxDateTime() | ||||
|             except: | ||||
|                 dbg('exception occurred', indent=0) | ||||
| ##                dbg('exception occurred', indent=0) | ||||
|                 raise | ||||
| 
 | ||||
|         dbg('value:', value.FormatTime()) | ||||
| ##        dbg('value:', value.FormatTime()) | ||||
| 
 | ||||
|         # Get wxDateTime representations of bounds: | ||||
|         min = self.GetMin() | ||||
| @@ -990,7 +992,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|             # either "min" <= value (<= midnight of *next day*) | ||||
|             # or midnight <= value <= "max" | ||||
|             ret = min <= value or (midnight <= value <= max) | ||||
|         dbg('in bounds?', ret, indent=0) | ||||
| ##        dbg('in bounds?', ret, indent=0) | ||||
|         return ret | ||||
| 
 | ||||
| 
 | ||||
| @@ -1021,7 +1023,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
| 
 | ||||
| 
 | ||||
|     def __OnTextChange(self, event=None): | ||||
|         dbg('TimeCtrl::OnTextChange', indent=1) | ||||
| ##        dbg('TimeCtrl::OnTextChange', indent=1) | ||||
| 
 | ||||
|         # Allow Maskedtext base control to color as appropriate, | ||||
|         # and Skip the EVT_TEXT event (if appropriate.) | ||||
| @@ -1035,11 +1037,11 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|         if not BaseMaskedTextCtrl._OnTextChange(self, event): | ||||
|             return | ||||
| 
 | ||||
|         dbg('firing TimeUpdatedEvent...') | ||||
| ##        dbg('firing TimeUpdatedEvent...') | ||||
|         evt = TimeUpdatedEvent(self.GetId(), self.GetValue()) | ||||
|         evt.SetEventObject(self) | ||||
|         self.GetEventHandler().ProcessEvent(evt) | ||||
|         dbg(indent=0) | ||||
| ##        dbg(indent=0) | ||||
| 
 | ||||
| 
 | ||||
|     def SetInsertionPoint(self, pos): | ||||
| @@ -1048,14 +1050,14 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|         This is necessary to handle the optional spin button, because the insertion | ||||
|         point is lost when the focus shifts to the spin button. | ||||
|         """ | ||||
|         dbg('TimeCtrl::SetInsertionPoint', pos, indent=1) | ||||
| ##        dbg('TimeCtrl::SetInsertionPoint', pos, indent=1) | ||||
|         BaseMaskedTextCtrl.SetInsertionPoint(self, pos)                 # (causes EVT_TEXT event to fire) | ||||
|         self.__posCurrent = self.GetInsertionPoint() | ||||
|         dbg(indent=0) | ||||
| ##        dbg(indent=0) | ||||
| 
 | ||||
| 
 | ||||
|     def SetSelection(self, sel_start, sel_to): | ||||
|         dbg('TimeCtrl::SetSelection', sel_start, sel_to, indent=1) | ||||
| ##        dbg('TimeCtrl::SetSelection', sel_start, sel_to, indent=1) | ||||
| 
 | ||||
|         # Adjust selection range to legal extent if not already | ||||
|         if sel_start < 0: | ||||
| @@ -1069,7 +1071,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
| 
 | ||||
|         self.__bSelection = sel_start != sel_to | ||||
|         BaseMaskedTextCtrl.SetSelection(self, sel_start, sel_to) | ||||
|         dbg(indent=0) | ||||
| ##        dbg(indent=0) | ||||
| 
 | ||||
| 
 | ||||
|     def __OnSpin(self, key): | ||||
| @@ -1085,7 +1087,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|         start, end = self._FindField(self.__posCurrent)._extent | ||||
|         self.SetInsertionPoint(start) | ||||
|         self.SetSelection(start, end) | ||||
|         dbg('current position:', self.__posCurrent) | ||||
| ##        dbg('current position:', self.__posCurrent) | ||||
| 
 | ||||
| 
 | ||||
|     def __OnSpinUp(self, event): | ||||
| @@ -1093,10 +1095,10 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|         Event handler for any bound spin button on EVT_SPIN_UP; | ||||
|         causes control to behave as if up arrow was pressed. | ||||
|         """ | ||||
|         dbg('TimeCtrl::OnSpinUp', indent=1) | ||||
| ##        dbg('TimeCtrl::OnSpinUp', indent=1) | ||||
|         self.__OnSpin(wx.WXK_UP) | ||||
|         keep_processing = False | ||||
|         dbg(indent=0) | ||||
| ##        dbg(indent=0) | ||||
|         return keep_processing | ||||
| 
 | ||||
| 
 | ||||
| @@ -1105,10 +1107,10 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|         Event handler for any bound spin button on EVT_SPIN_DOWN; | ||||
|         causes control to behave as if down arrow was pressed. | ||||
|         """ | ||||
|         dbg('TimeCtrl::OnSpinDown', indent=1) | ||||
| ##        dbg('TimeCtrl::OnSpinDown', indent=1) | ||||
|         self.__OnSpin(wx.WXK_DOWN) | ||||
|         keep_processing = False | ||||
|         dbg(indent=0) | ||||
| ##        dbg(indent=0) | ||||
|         return keep_processing | ||||
| 
 | ||||
| 
 | ||||
| @@ -1119,14 +1121,14 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|         It then calls the base control's _OnChar routine with the modified | ||||
|         event instance. | ||||
|         """ | ||||
|         dbg('TimeCtrl::OnChar', indent=1) | ||||
| ##        dbg('TimeCtrl::OnChar', indent=1) | ||||
|         keycode = event.GetKeyCode() | ||||
|         dbg('keycode:', keycode) | ||||
| ##        dbg('keycode:', keycode) | ||||
|         if keycode == ord(':'): | ||||
|             dbg('colon seen! removing shift attribute') | ||||
| ##            dbg('colon seen! removing shift attribute') | ||||
|             event.m_shiftDown = False | ||||
|         BaseMaskedTextCtrl._OnChar(self, event )              ## handle each keypress | ||||
|         dbg(indent=0) | ||||
| ##        dbg(indent=0) | ||||
| 
 | ||||
| 
 | ||||
|     def __OnSetToNow(self, event): | ||||
| @@ -1144,7 +1146,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|         Event handler for motion events; this handler | ||||
|         changes limits the selection to the new cell boundaries. | ||||
|         """ | ||||
|         dbg('TimeCtrl::LimitSelection', indent=1) | ||||
| ##        dbg('TimeCtrl::LimitSelection', indent=1) | ||||
|         pos = self.GetInsertionPoint() | ||||
|         self.__posCurrent = pos | ||||
|         sel_start, sel_to = self.GetSelection() | ||||
| @@ -1155,18 +1157,18 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|             if sel_to < pos:   sel_to = start | ||||
|             elif sel_to > pos: sel_to = end | ||||
| 
 | ||||
|         dbg('new pos =', self.__posCurrent, 'select to ', sel_to) | ||||
| ##        dbg('new pos =', self.__posCurrent, 'select to ', sel_to) | ||||
|         self.SetInsertionPoint(self.__posCurrent) | ||||
|         self.SetSelection(self.__posCurrent, sel_to) | ||||
|         if event: event.Skip() | ||||
|         dbg(indent=0) | ||||
| ##        dbg(indent=0) | ||||
| 
 | ||||
| 
 | ||||
|     def __IncrementValue(self, key, pos): | ||||
|         dbg('TimeCtrl::IncrementValue', key, pos, indent=1) | ||||
| ##        dbg('TimeCtrl::IncrementValue', key, pos, indent=1) | ||||
|         text = self.GetValue() | ||||
|         field = self._FindField(pos) | ||||
|         dbg('field: ', field._index) | ||||
| ##        dbg('field: ', field._index) | ||||
|         start, end = field._extent | ||||
|         slice = text[start:end] | ||||
|         if key == wx.WXK_UP: increment = 1 | ||||
| @@ -1182,14 +1184,14 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|             # am/pm setting.  So, we use wxDateTime to generate a new value for us: | ||||
|             # (Use a fixed date not subject to DST variations:) | ||||
|             converter = wx.DateTimeFromDMY(1, 0, 1970) | ||||
|             dbg('text: "%s"' % text) | ||||
| ##            dbg('text: "%s"' % text) | ||||
|             converter.ParseTime(text.strip()) | ||||
|             currenthour = converter.GetHour() | ||||
|             dbg('current hour:', currenthour) | ||||
| ##            dbg('current hour:', currenthour) | ||||
|             newhour = (currenthour + increment) % 24 | ||||
|             dbg('newhour:', newhour) | ||||
| ##            dbg('newhour:', newhour) | ||||
|             converter.SetHour(newhour) | ||||
|             dbg('converter.GetHour():', converter.GetHour()) | ||||
| ##            dbg('converter.GetHour():', converter.GetHour()) | ||||
|             newvalue = converter     # take advantage of auto-conversion for am/pm in .SetValue() | ||||
| 
 | ||||
|         else:   # minute or second field; handled the same way: | ||||
| @@ -1202,7 +1204,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|         except ValueError:  # must not be in bounds: | ||||
|             if not wx.Validator_IsSilent(): | ||||
|                 wx.Bell() | ||||
|         dbg(indent=0) | ||||
| ##        dbg(indent=0) | ||||
| 
 | ||||
| 
 | ||||
|     def _toGUI( self, wxdt ): | ||||
| @@ -1227,23 +1229,23 @@ class TimeCtrl(BaseMaskedTextCtrl): | ||||
|         not a valid value for the control as currently specified. | ||||
|         It is used by both the SetValue() and the IsValid() methods. | ||||
|         """ | ||||
|         dbg('TimeCtrl::__validateValue(%s)' % repr(value), indent=1) | ||||
| ##        dbg('TimeCtrl::__validateValue(%s)' % repr(value), indent=1) | ||||
|         if not value: | ||||
|             dbg(indent=0) | ||||
| ##            dbg(indent=0) | ||||
|             raise ValueError('%s not a valid time value' % repr(value)) | ||||
| 
 | ||||
|         valid = True    # assume true | ||||
|         try: | ||||
|             value = self.GetWxDateTime(value)   # regularize form; can generate ValueError if problem doing so | ||||
|         except: | ||||
|             dbg('exception occurred', indent=0) | ||||
| ##            dbg('exception occurred', indent=0) | ||||
|             raise | ||||
| 
 | ||||
|         if self.IsLimited() and not self.IsInBounds(value): | ||||
|             dbg(indent=0) | ||||
| ##            dbg(indent=0) | ||||
|             raise ValueError ( | ||||
|                 'value %s is not within the bounds of the control' % str(value) ) | ||||
|         dbg(indent=0) | ||||
| ##        dbg(indent=0) | ||||
|         return value | ||||
| 
 | ||||
| #---------------------------------------------------------------------------- | ||||
| @@ -1278,12 +1280,12 @@ if __name__ == '__main__': | ||||
|             self.Bind(EVT_TIMEUPDATE, self.OnTimeChange, self.tc) | ||||
| 
 | ||||
|         def OnTimeChange(self, event): | ||||
|             dbg('OnTimeChange: value = ', event.GetValue()) | ||||
| ##            dbg('OnTimeChange: value = ', event.GetValue()) | ||||
|             wxdt = self.tc.GetWxDateTime() | ||||
|             dbg('wxdt =', wxdt.GetHour(), wxdt.GetMinute(), wxdt.GetSecond()) | ||||
| ##            dbg('wxdt =', wxdt.GetHour(), wxdt.GetMinute(), wxdt.GetSecond()) | ||||
|             if self.test_mx: | ||||
|                 mxdt = self.tc.GetMxDateTime() | ||||
|                 dbg('mxdt =', mxdt.hour, mxdt.minute, mxdt.second) | ||||
| ##                dbg('mxdt =', mxdt.hour, mxdt.minute, mxdt.second) | ||||
| 
 | ||||
| 
 | ||||
|     class MyApp(wx.App): | ||||
| @@ -2,9 +2,21 @@ | ||||
| ## backwards compatibility.  Some names will also have a 'wx' added on if | ||||
| ## that is how they used to be named in the old wxPython package. | ||||
|  | ||||
| import wx.lib.maskedctrl | ||||
| import wx.lib.masked.ctrl | ||||
|  | ||||
| __doc__ =  wx.lib.maskedctrl.__doc__ | ||||
| __doc__ =  wx.lib.masked.ctrl.__doc__ | ||||
|  | ||||
| controlTypes = wx.lib.maskedctrl.controlTypes | ||||
| wxMaskedCtrl = wx.lib.maskedctrl.MaskedCtrl | ||||
| MASKEDTEXT  = wx.lib.masked.ctrl.TEXT | ||||
| MASKEDCOMBO = wx.lib.masked.ctrl.COMBO | ||||
| IPADDR      = wx.lib.masked.ctrl.IPADDR | ||||
| TIME        = wx.lib.masked.ctrl.TIME | ||||
| NUMBER      = wx.lib.masked.ctrl.NUMBER | ||||
|  | ||||
| class controlTypes: | ||||
|     MASKEDTEXT  = wx.lib.masked.ctrl.TEXT | ||||
|     MASKEDCOMBO = wx.lib.masked.ctrl.COMBO | ||||
|     IPADDR      = wx.lib.masked.ctrl.IPADDR | ||||
|     TIME        = wx.lib.masked.ctrl.TIME | ||||
|     NUMBER      = wx.lib.masked.ctrl.NUMBER | ||||
|  | ||||
| wxMaskedCtrl = wx.lib.masked.Ctrl | ||||
|   | ||||
| @@ -1,16 +1,15 @@ | ||||
| ## This file imports items from the wx package into the wxPython package for | ||||
| ## backwards compatibility.  Some names will also have a 'wx' added on if | ||||
| ## that is how they used to be named in the old wxPython package. | ||||
| import wx.lib.masked | ||||
| import wx.lib.masked.maskededit | ||||
|  | ||||
| import wx.lib.maskededit | ||||
| __doc__ =  wx.lib.masked.maskededit.__doc__ | ||||
|  | ||||
| __doc__ =  wx.lib.maskededit.__doc__ | ||||
| from wx.lib.masked.maskededit import * | ||||
|  | ||||
| Field = wx.lib.maskededit.Field | ||||
| test = wx.lib.maskededit.test | ||||
| test2 = wx.lib.maskededit.test2 | ||||
| wxIpAddrCtrl = wx.lib.maskededit.IpAddrCtrl | ||||
| wxMaskedComboBox = wx.lib.maskededit.MaskedComboBox | ||||
| wxMaskedComboBoxSelectEvent = wx.lib.maskededit.MaskedComboBoxSelectEvent | ||||
| wxMaskedEditMixin = wx.lib.maskededit.MaskedEditMixin | ||||
| wxMaskedTextCtrl = wx.lib.maskededit.MaskedTextCtrl | ||||
| wxMaskedEditMixin = wx.lib.masked.MaskedEditMixin | ||||
| wxMaskedTextCtrl = wx.lib.masked.TextCtrl | ||||
| wxMaskedComboBox = wx.lib.masked.ComboBox | ||||
| wxMaskedComboBoxSelectEvent = wx.lib.masked.MaskedComboBoxSelectEvent | ||||
| wxIpAddrCtrl = wx.lib.masked.IpAddrCtrl | ||||
|   | ||||
| @@ -2,10 +2,10 @@ | ||||
| ## backwards compatibility.  Some names will also have a 'wx' added on if | ||||
| ## that is how they used to be named in the old wxPython package. | ||||
|  | ||||
| import wx.lib.maskednumctrl | ||||
| import wx.lib.masked.numctrl | ||||
|  | ||||
| __doc__ =  wx.lib.maskednumctrl.__doc__ | ||||
| __doc__ =  wx.lib.masked.numctrl.__doc__ | ||||
|  | ||||
| EVT_MASKEDNUM = wx.lib.maskednumctrl.EVT_MASKEDNUM | ||||
| wxMaskedNumCtrl = wx.lib.maskednumctrl.MaskedNumCtrl | ||||
| wxMaskedNumNumberUpdatedEvent = wx.lib.maskednumctrl.MaskedNumNumberUpdatedEvent | ||||
| EVT_MASKEDNUM = wx.lib.masked.numctrl.EVT_NUM | ||||
| wxMaskedNumCtrl = wx.lib.masked.numctrl.NumCtrl | ||||
| wxMaskedNumNumberUpdatedEvent = wx.lib.masked.numctrl.NumberUpdatedEvent | ||||
|   | ||||
| @@ -2,10 +2,10 @@ | ||||
| ## backwards compatibility.  Some names will also have a 'wx' added on if | ||||
| ## that is how they used to be named in the old wxPython package. | ||||
|  | ||||
| import wx.lib.timectrl | ||||
| import wx.lib.masked.timectrl | ||||
|  | ||||
| __doc__ =  wx.lib.timectrl.__doc__ | ||||
| __doc__ =  wx.lib.masked.timectrl.__doc__ | ||||
|  | ||||
| EVT_TIMEUPDATE = wx.lib.timectrl.EVT_TIMEUPDATE | ||||
| TimeUpdatedEvent = wx.lib.timectrl.TimeUpdatedEvent | ||||
| wxTimeCtrl = wx.lib.timectrl.TimeCtrl | ||||
| EVT_TIMEUPDATE = wx.lib.masked.timectrl.EVT_TIMEUPDATE | ||||
| TimeUpdatedEvent = wx.lib.masked.timectrl.TimeUpdatedEvent | ||||
| wxTimeCtrl = wx.lib.masked.timectrl.TimeCtrl | ||||
|   | ||||
		Reference in New Issue
	
	Block a user