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  traceback | ||||||
|  |  | ||||||
| import  wx | import  wx | ||||||
| import  wx.lib.maskededit       as  med | import  wx.lib.masked             as  masked | ||||||
| import  wx.lib.maskedctrl       as  mctl | import  wx.lib.scrolledpanel      as  scroll | ||||||
| import  wx.lib.scrolledpanel    as  scroll |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class demoMixin: | class demoMixin: | ||||||
| @@ -18,7 +17,7 @@ class demoMixin: | |||||||
|         mask        = wx.StaticText( self, -1, "Mask Value" ) |         mask        = wx.StaticText( self, -1, "Mask Value" ) | ||||||
|         formatcode  = wx.StaticText( self, -1, "Format" ) |         formatcode  = wx.StaticText( self, -1, "Format" ) | ||||||
|         regex       = wx.StaticText( self, -1, "Regexp Validator(opt.)" ) |         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)) |         description.SetFont( wx.Font(9, wx.SWISS, wx.NORMAL, wx.BOLD)) | ||||||
|         mask.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]) ) |             sizer.Add( wx.StaticText( self, -1, control[4]) ) | ||||||
|  |  | ||||||
|             if control in controls: |             if control in controls: | ||||||
|                 newControl  = med.MaskedTextCtrl( self, -1, "", |                 newControl  = masked.TextCtrl( self, -1, "", | ||||||
|                                                 mask         = control[1], |                                                 mask         = control[1], | ||||||
|                                                 excludeChars = control[2], |                                                 excludeChars = control[2], | ||||||
|                                                 formatcodes  = control[3], |                                                 formatcodes  = control[3], | ||||||
| @@ -79,7 +78,7 @@ class demoPage1(scroll.ScrolledPanel, demoMixin): | |||||||
|         self.editList  = [] |         self.editList  = [] | ||||||
|  |  | ||||||
|         label = wx.StaticText( self, -1, """\ |         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 | with this control.  Note that all controls have been auto-sized by including 'F' in | ||||||
| the format codes. | the format codes. | ||||||
|  |  | ||||||
| @@ -152,8 +151,8 @@ class demoPage2(scroll.ScrolledPanel, demoMixin): | |||||||
|  |  | ||||||
|         label = wx.StaticText( self, -1, """\ |         label = wx.StaticText( self, -1, """\ | ||||||
| All these controls have been created by passing a single parameter, the autoformat code, | All these controls have been created by passing a single parameter, the autoformat code, | ||||||
| and use the factory class MaskedCtrl with its default controlType. | and use the factory class masked.Ctrl with its default controlType. | ||||||
| The maskededit module contains an internal dictionary of types and formats (autoformats). | The masked package contains an internal dictionary of types and formats (autoformats). | ||||||
| Many of these already do complicated validation; To see some examples, try | 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. | 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") |         description = wx.StaticText( self, -1, "Description") | ||||||
|         autofmt     = wx.StaticText( self, -1, "AutoFormat Code") |         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 ) ) |         description.SetFont( wx.Font( 9, wx.SWISS, wx.NORMAL, wx.BOLD ) ) | ||||||
|         autofmt.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( autofmt,     0, wx.ALIGN_LEFT ) | ||||||
|         grid.Add( ctrl,        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, desc), 0, wx.ALIGN_LEFT ) | ||||||
|             grid.Add( wx.StaticText( self, -1, autoformat), 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, |                                     autoformat       = autoformat, | ||||||
|                                     demo             = True, |                                     demo             = True, | ||||||
|                                     name             = autoformat), |                                     name             = autoformat), | ||||||
| @@ -197,7 +196,7 @@ class demoPage3(scroll.ScrolledPanel, demoMixin): | |||||||
|         self.editList  = [] |         self.editList  = [] | ||||||
|  |  | ||||||
|         label = wx.StaticText( self, -1, """\ |         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 | control has a list of valid values, and the unsigned integer | ||||||
| has a legal range specified. | has a legal range specified. | ||||||
| """) | """) | ||||||
| @@ -215,7 +214,7 @@ has a legal range specified. | |||||||
|  |  | ||||||
|         controls = [ |         controls = [ | ||||||
|         #description        mask                    excl format     regexp                              range,list,initial |         #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 (signed)",         "#{6}",          "", 'F-_',       "",                                 '','', ' 0    '), | ||||||
|        ("Integer (unsigned)\n(1-399)","######",      "", 'F_',        "",                                 (1,399),'', '1     '), |        ("Integer (unsigned)\n(1-399)","######",      "", 'F_',        "",                                 (1,399),'', '1     '), | ||||||
|        ("Float (signed)",           "#{6}.#{9}",     "", 'F-_R',      "",                                 '','', '000000.000000000'), |        ("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" ) |         description  = wx.StaticText( self, -1, "Description" ) | ||||||
|         autofmt      = wx.StaticText( self, -1, "AutoFormat Code" ) |         autofmt      = wx.StaticText( self, -1, "AutoFormat Code" ) | ||||||
|         fields       = wx.StaticText( self, -1, "Field Objects" ) |         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 ) ) |         description.SetFont( wx.Font( 9, wx.SWISS, wx.NORMAL, wx.BOLD ) ) | ||||||
|         autofmt.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 ) |         grid.Add( ctrl,        0, wx.ALIGN_LEFT ) | ||||||
|  |  | ||||||
|         autoformat = "USPHONEFULLEXT" |         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 = """\ |         fieldsLabel = """\ | ||||||
| {0: Field(choices=[ | {0: Field(choices=[ | ||||||
|             "617","781", |             "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, "Restricted Area Code"), 0, wx.ALIGN_LEFT ) | ||||||
|         grid.Add( wx.StaticText( self, -1, autoformat), 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( wx.StaticText( self, -1, fieldsLabel), 0, wx.ALIGN_LEFT ) | ||||||
|         grid.Add( med.MaskedTextCtrl( self, -1, "", |         grid.Add( masked.TextCtrl( self, -1, "", | ||||||
|                                     autoformat       = autoformat, |                                     autoformat       = autoformat, | ||||||
|                                     fields           = fieldsDict, |                                     fields           = fieldsDict, | ||||||
|                                     demo             = True, |                                     demo             = True, | ||||||
| @@ -287,12 +286,12 @@ Page Up and Shift-Up arrow will similarly cycle backwards through the list. | |||||||
|                   0, wx.ALIGN_LEFT ) |                   0, wx.ALIGN_LEFT ) | ||||||
|  |  | ||||||
|         autoformat = "EXPDATEMMYY" |         autoformat = "EXPDATEMMYY" | ||||||
|         fieldsDict = {1: med.Field(choices=["03", "04", "05"], choiceRequired=True)} |         fieldsDict = {1: masked.Field(choices=["03", "04", "05"], choiceRequired=True)} | ||||||
|         fieldsLabel = """\ |         fieldsLabel = """\ | ||||||
| {1: Field(choices=[ | {1: Field(choices=[ | ||||||
|             "03", "04", "05"], |             "03", "04", "05"], | ||||||
|           choiceRequired=True)}""" |           choiceRequired=True)}""" | ||||||
|         exp =  med.MaskedTextCtrl( self, -1, "", |         exp =  masked.TextCtrl( self, -1, "", | ||||||
|                                  autoformat       = autoformat, |                                  autoformat       = autoformat, | ||||||
|                                  fields           = fieldsDict, |                                  fields           = fieldsDict, | ||||||
|                                  demo             = True, |                                  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( wx.StaticText( self, -1, fieldsLabel), 0, wx.ALIGN_LEFT ) | ||||||
|         grid.Add( exp, 0, wx.ALIGN_LEFT ) |         grid.Add( exp, 0, wx.ALIGN_LEFT ) | ||||||
|  |  | ||||||
|         fieldsDict = {0: med.Field(choices=["02134","02155"], choiceRequired=True), |         fieldsDict = {0: masked.Field(choices=["02134","02155"], choiceRequired=True), | ||||||
|                       1: med.Field(choices=["1234", "5678"],  choiceRequired=False)} |                       1: masked.Field(choices=["1234", "5678"],  choiceRequired=False)} | ||||||
|         fieldsLabel = """\ |         fieldsLabel = """\ | ||||||
| {0: Field(choices=["02134","02155"], | {0: Field(choices=["02134","02155"], | ||||||
|           choiceRequired=True), |           choiceRequired=True), | ||||||
|  1: Field(choices=["1234", "5678"], |  1: Field(choices=["1234", "5678"], | ||||||
|           choiceRequired=False)}""" |           choiceRequired=False)}""" | ||||||
|         autoformat = "USZIPPLUS4" |         autoformat = "USZIPPLUS4" | ||||||
|         zip =  med.MaskedTextCtrl( self, -1, "", |         zip =  masked.TextCtrl( self, -1, "", | ||||||
|                                  autoformat       = autoformat, |                                  autoformat       = autoformat, | ||||||
|                                  fields           = fieldsDict, |                                  fields           = fieldsDict, | ||||||
|                                  demo             = True, |                                  demo             = True, | ||||||
| @@ -336,7 +335,7 @@ class demoPage5(scroll.ScrolledPanel, demoMixin): | |||||||
|  |  | ||||||
|  |  | ||||||
|         labelMaskedCombos = wx.StaticText( self, -1, """\ |         labelMaskedCombos = wx.StaticText( self, -1, """\ | ||||||
| These are some examples of MaskedComboBox:""") | These are some examples of masked.ComboBox:""") | ||||||
|         labelMaskedCombos.SetForegroundColour( "Blue" ) |         labelMaskedCombos.SetForegroundColour( "Blue" ) | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -344,8 +343,8 @@ These are some examples of MaskedComboBox:""") | |||||||
| A state selector; only | A state selector; only | ||||||
| "legal" values can be | "legal" values can be | ||||||
| entered:""") | entered:""") | ||||||
|         statecode = med.MaskedComboBox( self, -1, med.states[0], |         statecode = masked.ComboBox( self, -1, masked.states[0], | ||||||
|                                   choices = med.states, |                                   choices = masked.states, | ||||||
|                                   autoformat="USSTATE") |                                   autoformat="USSTATE") | ||||||
|  |  | ||||||
|         label_statename = wx.StaticText( self, -1, """\ |         label_statename = wx.StaticText( self, -1, """\ | ||||||
| @@ -353,9 +352,9 @@ A state name selector, | |||||||
| with auto-select:""") | with auto-select:""") | ||||||
|  |  | ||||||
|         # Create this one using factory function: |         # Create this one using factory function: | ||||||
|         statename = mctl.MaskedCtrl( self, -1, med.state_names[0], |         statename = masked.Ctrl( self, -1, masked.state_names[0], | ||||||
|                                   controlType = mctl.controlTypes.MASKEDCOMBO, |                                   controlType = masked.controlTypes.COMBO, | ||||||
|                                   choices = med.state_names, |                                   choices = masked.state_names, | ||||||
|                                   autoformat="USSTATENAME", |                                   autoformat="USSTATENAME", | ||||||
|                                   autoSelect=True) |                                   autoSelect=True) | ||||||
|         statename.SetCtrlParameters(formatcodes = 'F!V_') |         statename.SetCtrlParameters(formatcodes = 'F!V_') | ||||||
| @@ -363,8 +362,8 @@ with auto-select:""") | |||||||
|  |  | ||||||
|         numerators = [ str(i) for i in range(1, 4) ] |         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] ] |         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), |         fieldsDict = {0: masked.Field(choices=numerators, choiceRequired=False), | ||||||
|                       1: med.Field(choices=denominators, choiceRequired=True)} |                       1: masked.Field(choices=denominators, choiceRequired=True)} | ||||||
|         choices = [] |         choices = [] | ||||||
|         for n in numerators: |         for n in numerators: | ||||||
|             for d in denominators: |             for d in denominators: | ||||||
| @@ -377,8 +376,8 @@ A masked ComboBox for fraction selection. | |||||||
| Choices for each side of the fraction can | Choices for each side of the fraction can | ||||||
| be selected with PageUp/Down:""") | be selected with PageUp/Down:""") | ||||||
|  |  | ||||||
|         fraction = mctl.MaskedCtrl( self, -1, "", |         fraction = masked.Ctrl( self, -1, "", | ||||||
|                                  controlType = mctl.MASKEDCOMBO, |                                  controlType = masked.controlTypes.COMBO, | ||||||
|                                  choices = choices, |                                  choices = choices, | ||||||
|                                  choiceRequired = True, |                                  choiceRequired = True, | ||||||
|                                  mask = "#/##", |                                  mask = "#/##", | ||||||
| @@ -392,7 +391,7 @@ A masked ComboBox to validate | |||||||
| text from a list of numeric codes:""") | text from a list of numeric codes:""") | ||||||
|  |  | ||||||
|         choices = ["91", "136", "305", "4579"] |         choices = ["91", "136", "305", "4579"] | ||||||
|         code = med.MaskedComboBox( self, -1, choices[0], |         code = masked.ComboBox( self, -1, choices[0], | ||||||
|                                  choices = choices, |                                  choices = choices, | ||||||
|                                  choiceRequired = True, |                                  choiceRequired = True, | ||||||
|                                  formatcodes = "F_r", |                                  formatcodes = "F_r", | ||||||
| @@ -402,8 +401,8 @@ text from a list of numeric codes:""") | |||||||
| Programmatically set | Programmatically set | ||||||
| choice sets:""") | choice sets:""") | ||||||
|         self.list_selector = wx.ComboBox(self, -1, '', choices = ['list1', 'list2', 'list3']) |         self.list_selector = wx.ComboBox(self, -1, '', choices = ['list1', 'list2', 'list3']) | ||||||
|         self.dynamicbox = mctl.MaskedCtrl( self, -1, '    ', |         self.dynamicbox = masked.Ctrl( self, -1, '    ', | ||||||
|                                       controlType = mctl.controlTypes.MASKEDCOMBO, |                                       controlType = masked.controlTypes.COMBO, | ||||||
|                                       mask =    'XXXX', |                                       mask =    'XXXX', | ||||||
|                                       formatcodes = 'F_', |                                       formatcodes = 'F_', | ||||||
|                                       # these are to give dropdown some initial height, |                                       # these are to give dropdown some initial height, | ||||||
| @@ -415,23 +414,23 @@ choice sets:""") | |||||||
|  |  | ||||||
|  |  | ||||||
|         labelIpAddrs = wx.StaticText( self, -1, """\ |         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" ) |         labelIpAddrs.SetForegroundColour( "Blue" ) | ||||||
|  |  | ||||||
|  |  | ||||||
|         label_ipaddr1 = wx.StaticText( self, -1, "An empty control:") |         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:") |         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, """\ |         label_ipaddr3 = wx.StaticText( self, -1, """\ | ||||||
| A control with restricted legal values: | A control with restricted legal values: | ||||||
| 10. (1|2) . (129..255) . (0..255)""") | 10. (1|2) . (129..255) . (0..255)""") | ||||||
|         ipaddr3 = mctl.MaskedCtrl( self, -1, |         ipaddr3 = masked.Ctrl( self, -1, | ||||||
|                                 controlType = mctl.controlTypes.IPADDR, |                                 controlType = masked.controlTypes.IPADDR, | ||||||
|                                 mask=" 10.  #.###.###") |                                 mask=" 10.  #.###.###") | ||||||
|         ipaddr3.SetFieldParameters(0, validRegex="1|2",validRequired=False )   # requires entry to match or not allowed |         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, """\ |         labelNumerics = wx.StaticText( self, -1, """\ | ||||||
| Here are some useful configurations of a MaskedTextCtrl for integer and floating point input that still treat | 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 MaskedNumCtrl class!)""") | the control as a text control.  (For a true numeric control, check out the masked.NumCtrl class!)""") | ||||||
|         labelNumerics.SetForegroundColour( "Blue" ) |         labelNumerics.SetForegroundColour( "Blue" ) | ||||||
|  |  | ||||||
|         label_intctrl1 = wx.StaticText( self, -1, """\ |         label_intctrl1 = wx.StaticText( self, -1, """\ | ||||||
| An integer entry control with | An integer entry control with | ||||||
| shifting insert enabled:""") | 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, """\ |         label_intctrl2 = wx.StaticText( self, -1, """\ | ||||||
|      Right-insert integer entry:""") |      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, """\ |         label_floatctrl = wx.StaticText( self, -1, """\ | ||||||
| A floating point entry control | A floating point entry control | ||||||
| with right-insert for ordinal:""") | 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(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 |         self.floatctrl.SetFieldParameters(1, defaultValue='00')                     # don't allow blank fraction | ||||||
|  |  | ||||||
| @@ -588,7 +587,7 @@ with right-insert for ordinal:""") | |||||||
|             formatcodes += 'r' |             formatcodes += 'r' | ||||||
|             mask = '###' |             mask = '###' | ||||||
|         else: |         else: | ||||||
|             choices = med.states |             choices = masked.states | ||||||
|             mask = 'AA' |             mask = 'AA' | ||||||
|             formatcodes += '!' |             formatcodes += '!' | ||||||
|         self.dynamicbox.SetCtrlParameters( mask = mask, |         self.dynamicbox.SetCtrlParameters( mask = mask, | ||||||
| @@ -628,15 +627,15 @@ def runTest(frame, nb, log): | |||||||
|  |  | ||||||
| def RunStandalone(): | def RunStandalone(): | ||||||
|     app = wx.PySimpleApp() |     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) |     win = TestMaskedTextCtrls(frame, -1, sys.stdout) | ||||||
|     frame.Show(True) |     frame.Show(True) | ||||||
|     app.MainLoop() |     app.MainLoop() | ||||||
| #---------------------------------------------------------------------------- | #---------------------------------------------------------------------------- | ||||||
|  | import wx.lib.masked.maskededit as maskededit | ||||||
| overview = """<html> | overview = """<html> | ||||||
| <PRE><FONT SIZE=-1> | <PRE><FONT SIZE=-1> | ||||||
| """ + med.__doc__ + """ | """ + maskededit.__doc__ + """ | ||||||
| </FONT></PRE> | </FONT></PRE> | ||||||
| """ | """ | ||||||
|  |  | ||||||
|   | |||||||
| @@ -4,8 +4,8 @@ import  sys | |||||||
| import  traceback | import  traceback | ||||||
|  |  | ||||||
| import  wx | import  wx | ||||||
| import  wx.lib.maskededit       as me | from    wx.lib import masked | ||||||
| import  wx.lib.maskednumctrl    as mnum |  | ||||||
| #---------------------------------------------------------------------- | #---------------------------------------------------------------------- | ||||||
|  |  | ||||||
| class TestPanel( wx.Panel ): | class TestPanel( wx.Panel ): | ||||||
| @@ -16,40 +16,40 @@ class TestPanel( wx.Panel ): | |||||||
|         panel = wx.Panel( self, -1 ) |         panel = wx.Panel( self, -1 ) | ||||||
|  |  | ||||||
|         header = wx.StaticText(panel, -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. | The controls at the top reconfigure the resulting control at the bottom. | ||||||
| """) | """) | ||||||
|         header.SetForegroundColour( "Blue" ) |         header.SetForegroundColour( "Blue" ) | ||||||
|  |  | ||||||
|         intlabel = wx.StaticText( panel, -1, "Integer width:" ) |         intlabel = wx.StaticText( panel, -1, "Integer width:" ) | ||||||
|         self.integerwidth = mnum.MaskedNumCtrl( |         self.integerwidth = masked.NumCtrl( | ||||||
|                                 panel, value=10, integerWidth=2, allowNegative=False |                                 panel, value=10, integerWidth=2, allowNegative=False | ||||||
|                                 ) |                                 ) | ||||||
|  |  | ||||||
|         fraclabel = wx.StaticText( panel, -1, "Fraction width:" ) |         fraclabel = wx.StaticText( panel, -1, "Fraction width:" ) | ||||||
|         self.fractionwidth = mnum.MaskedNumCtrl( |         self.fractionwidth = masked.NumCtrl( | ||||||
|                                 panel, value=0, integerWidth=2, allowNegative=False |                                 panel, value=0, integerWidth=2, allowNegative=False | ||||||
|                                 ) |                                 ) | ||||||
|  |  | ||||||
|         groupcharlabel = wx.StaticText( panel,-1, "Grouping char:" ) |         groupcharlabel = wx.StaticText( panel,-1, "Grouping char:" ) | ||||||
|         self.groupchar = me.MaskedTextCtrl(  |         self.groupchar = masked.TextCtrl( | ||||||
|                                 panel, -1, value=',', mask='&', excludeChars = '-()', |                                 panel, -1, value=',', mask='&', excludeChars = '-()', | ||||||
|                                 formatcodes='F', emptyInvalid=True, validRequired=True |                                 formatcodes='F', emptyInvalid=True, validRequired=True | ||||||
|                                 ) |                                 ) | ||||||
|  |  | ||||||
|         decimalcharlabel = wx.StaticText( panel,-1, "Decimal char:" ) |         decimalcharlabel = wx.StaticText( panel,-1, "Decimal char:" ) | ||||||
|         self.decimalchar = me.MaskedTextCtrl(  |         self.decimalchar = masked.TextCtrl( | ||||||
|                                 panel, -1, value='.', mask='&', excludeChars = '-()', |                                 panel, -1, value='.', mask='&', excludeChars = '-()', | ||||||
|                                 formatcodes='F', emptyInvalid=True, validRequired=True |                                 formatcodes='F', emptyInvalid=True, validRequired=True | ||||||
|                                 ) |                                 ) | ||||||
|  |  | ||||||
|         self.set_min = wx.CheckBox( panel, -1, "Set minimum value:" ) |         self.set_min = wx.CheckBox( panel, -1, "Set minimum value:" ) | ||||||
|         # Create this MaskedNumCtrl using factory, to show how: |         # Create this masked.NumCtrl using factory, to show how: | ||||||
|         self.min = mnum.MaskedNumCtrl( panel, integerWidth=5, fractionWidth=2 ) |         self.min = masked.Ctrl( panel, integerWidth=5, fractionWidth=2, controlType=masked.controlTypes.NUMBER ) | ||||||
|         self.min.Enable( False ) |         self.min.Enable( False ) | ||||||
|  |  | ||||||
|         self.set_max = wx.CheckBox( panel, -1, "Set maximum value:" ) |         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 ) |         self.max.Enable( False ) | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -68,7 +68,7 @@ The controls at the top reconfigure the resulting control at the bottom. | |||||||
|         font.SetWeight(wx.BOLD) |         font.SetWeight(wx.BOLD) | ||||||
|         label.SetFont(font) |         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, """\ |         label_numselect = wx.StaticText( panel, -1, """\ | ||||||
| Programmatically set the above | Programmatically set the above | ||||||
| @@ -141,15 +141,15 @@ value entry ctrl:""") | |||||||
|         panel.Move( (50,10) ) |         panel.Move( (50,10) ) | ||||||
|         self.panel = panel |         self.panel = panel | ||||||
|  |  | ||||||
|         self.Bind(mnum.EVT_MASKEDNUM, self.OnSetIntWidth, self.integerwidth ) |         self.Bind(masked.EVT_NUM, self.OnSetIntWidth, self.integerwidth ) | ||||||
|         self.Bind(mnum.EVT_MASKEDNUM, self.OnSetFractionWidth, self.fractionwidth ) |         self.Bind(masked.EVT_NUM, self.OnSetFractionWidth, self.fractionwidth ) | ||||||
|         self.Bind(wx.EVT_TEXT, self.OnSetGroupChar, self.groupchar ) |         self.Bind(wx.EVT_TEXT, self.OnSetGroupChar, self.groupchar ) | ||||||
|         self.Bind(wx.EVT_TEXT, self.OnSetDecimalChar, self.decimalchar ) |         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.OnSetMin, self.set_min ) | ||||||
|         self.Bind(wx.EVT_CHECKBOX, self.OnSetMax, self.set_max ) |         self.Bind(wx.EVT_CHECKBOX, self.OnSetMax, self.set_max ) | ||||||
|         self.Bind(mnum.EVT_MASKEDNUM, self.SetTargetMinMax, self.min ) |         self.Bind(masked.EVT_NUM, self.SetTargetMinMax, self.min ) | ||||||
|         self.Bind(mnum.EVT_MASKEDNUM, self.SetTargetMinMax, self.max ) |         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.SetTargetMinMax, self.limit_target ) | ||||||
|         self.Bind(wx.EVT_CHECKBOX, self.OnSetAllowNone, self.allow_none ) |         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.OnSetUseParens, self.use_parens ) | ||||||
|         self.Bind(wx.EVT_CHECKBOX, self.OnSetSelectOnEntry, self.select_on_entry ) |         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 ) |         self.Bind(wx.EVT_COMBOBOX, self.OnNumberSelect, self.numselect ) | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -323,6 +323,7 @@ def runTest( frame, nb, log ): | |||||||
|     return win |     return win | ||||||
|  |  | ||||||
| #---------------------------------------------------------------------- | #---------------------------------------------------------------------- | ||||||
|  | import wx.lib.masked.numctrl as mnum | ||||||
| overview = mnum.__doc__ | overview = mnum.__doc__ | ||||||
|  |  | ||||||
| if __name__ == '__main__': | if __name__ == '__main__': | ||||||
|   | |||||||
| @@ -4,9 +4,9 @@ | |||||||
| # o presense of spin control causing probs (see spin ctrl demo for details) | # o presense of spin control causing probs (see spin ctrl demo for details) | ||||||
| # | # | ||||||
|  |  | ||||||
| import  wx | import wx | ||||||
| import  wx.lib.timectrl         as  timectl | import wx.lib.scrolledpanel    as scrolled | ||||||
| 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:") |         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 ) |         spin1 = wx.SpinButton( self, -1, wx.DefaultPosition, (-1,20), 0 ) | ||||||
|         self.time12.BindSpinButton( spin1 ) |         self.time12.BindSpinButton( spin1 ) | ||||||
|  |  | ||||||
|         text2 = wx.StaticText( self, -1, "24-hour format:") |         text2 = wx.StaticText( self, -1, "24-hour format:") | ||||||
|         spin2 = wx.SpinButton( self, -1, wx.DefaultPosition, (-1,20), 0 ) |         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, |                         self, -1, name="24 hour control", fmt24hr=True, | ||||||
|                         spinButton = spin2 |                         spinButton = spin2 | ||||||
|                         ) |                         ) | ||||||
|  |  | ||||||
|         text3 = wx.StaticText( self, -1, "No seconds\nor spin button:") |         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", |                                 self, -1, name="spinless control", | ||||||
|                                 display_seconds = False |                                 display_seconds = False | ||||||
|                                 ) |                                 ) | ||||||
| @@ -86,17 +86,17 @@ class TestPanel( scrolled.ScrolledPanel ): | |||||||
|         self.set_bounds = wx.CheckBox( self, -1, "Set time bounds:" ) |         self.set_bounds = wx.CheckBox( self, -1, "Set time bounds:" ) | ||||||
|  |  | ||||||
|         minlabel = wx.StaticText( self, -1, "minimum time:" ) |         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 ) |         self.min.Enable( False ) | ||||||
|  |  | ||||||
|         maxlabel = wx.StaticText( self, -1, "maximum time:" ) |         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.max.Enable( False ) | ||||||
|  |  | ||||||
|         self.limit_check = wx.CheckBox( self, -1, "Limit control" ) |         self.limit_check = wx.CheckBox( self, -1, "Limit control" ) | ||||||
|  |  | ||||||
|         label = wx.StaticText( self, -1, "Resulting time 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 = wx.FlexGridSizer( 0, 2, 0, 0 ) | ||||||
|         grid2.Add( (20, 0), 0, wx.ALIGN_LEFT|wx.ALL, 5 ) |         grid2.Add( (20, 0), 0, wx.ALIGN_LEFT|wx.ALL, 5 ) | ||||||
| @@ -142,14 +142,14 @@ class TestPanel( scrolled.ScrolledPanel ): | |||||||
|         self.SetupScrolling() |         self.SetupScrolling() | ||||||
|  |  | ||||||
|         self.Bind(wx.EVT_BUTTON, self.OnButtonClick, buttonChange ) |         self.Bind(wx.EVT_BUTTON, self.OnButtonClick, buttonChange ) | ||||||
|         self.Bind(timectl.EVT_TIMEUPDATE, self.OnTimeChange, self.time12 ) |         self.Bind(masked.EVT_TIMEUPDATE, self.OnTimeChange, self.time12 ) | ||||||
|         self.Bind(timectl.EVT_TIMEUPDATE, self.OnTimeChange, self.time24 ) |         self.Bind(masked.EVT_TIMEUPDATE, self.OnTimeChange, self.time24 ) | ||||||
|         self.Bind(timectl.EVT_TIMEUPDATE, self.OnTimeChange, self.spinless_ctrl ) |         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.OnBoundsCheck, self.set_bounds ) | ||||||
|         self.Bind(wx.EVT_CHECKBOX, self.SetTargetMinMax, self.limit_check ) |         self.Bind(wx.EVT_CHECKBOX, self.SetTargetMinMax, self.limit_check ) | ||||||
|         self.Bind(timectl.EVT_TIMEUPDATE, self.SetTargetMinMax, self.min ) |         self.Bind(masked.EVT_TIMEUPDATE, self.SetTargetMinMax, self.min ) | ||||||
|         self.Bind(timectl.EVT_TIMEUPDATE, self.SetTargetMinMax, self.max ) |         self.Bind(masked.EVT_TIMEUPDATE, self.SetTargetMinMax, self.max ) | ||||||
|         self.Bind(timectl.EVT_TIMEUPDATE, self.OnTimeChange, self.target_ctrl ) |         self.Bind(masked.EVT_TIMEUPDATE, self.OnTimeChange, self.target_ctrl ) | ||||||
|  |  | ||||||
|  |  | ||||||
|     def OnTimeChange( self, event ): |     def OnTimeChange( self, event ): | ||||||
| @@ -204,7 +204,7 @@ class TestPanel( scrolled.ScrolledPanel ): | |||||||
|             min, max = None, None |             min, max = None, None | ||||||
|  |  | ||||||
|         cur_min, cur_max = self.target_ctrl.GetBounds() |         cur_min, cur_max = self.target_ctrl.GetBounds() | ||||||
|  |         print cur_min, min | ||||||
|         if min and (min != cur_min): self.target_ctrl.SetMin( min ) |         if min and (min != cur_min): self.target_ctrl.SetMin( min ) | ||||||
|         if max and (max != cur_max): self.target_ctrl.SetMax( max ) |         if max and (max != cur_max): self.target_ctrl.SetMax( max ) | ||||||
|  |  | ||||||
| @@ -225,11 +225,11 @@ def runTest( frame, nb, log ): | |||||||
|     return win |     return win | ||||||
|  |  | ||||||
| #---------------------------------------------------------------------- | #---------------------------------------------------------------------- | ||||||
|  | import wx.lib.masked.timectrl as timectl | ||||||
| overview = timectl.__doc__ | overview = timectl.__doc__ | ||||||
|  |  | ||||||
| if __name__ == '__main__': | if __name__ == '__main__': | ||||||
|     import sys,os |     import sys,os | ||||||
|     import run |     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) | 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. | 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 | GetSystemColour, GetSystemFont and GetSystemMetric have also gone into | ||||||
| the bit-bucket.  Use GetColour, GetFont and GetMetric instead. | 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 | 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 | 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 | 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 | convert itself to one.  A similar conversion fragment is in place for | ||||||
| parameters that expect floating point values. | 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 | # Author:       Will Sadkin | ||||||
| # Created:      09/24/2003 | # Created:      09/24/2003 | ||||||
| # Copyright:   (c) 2003 by Will Sadkin | # Copyright:   (c) 2003 by Will Sadkin | ||||||
| @@ -17,24 +17,24 @@ | |||||||
| 
 | 
 | ||||||
| """<html><body> | """<html><body> | ||||||
| <P> | <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: | masked edit controls: | ||||||
| <P> | <P> | ||||||
| <UL> | <UL> | ||||||
|     <LI><b>MaskedTextCtrl</b> - standard masked edit text box</LI> |     <LI><b>masked.TextCtrl</b>   - standard masked edit text box</LI> | ||||||
|     <LI><b>MaskedComboBox</b> - adds combobox capabilities</LI> |     <LI><b>masked.ComboBox</b>   - adds combobox capabilities</LI> | ||||||
|     <LI><b>IpAddrCtrl</b> - adds logical input semantics for IP address entry</LI> |     <LI><b>masked.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>masked.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.NumCtrl</b>    - special subclass handling numeric values</LI> | ||||||
| </UL> | </UL> | ||||||
| <P> | <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 | parameter in the variable arguments of the control, to determine | ||||||
| what kind of instance to return. | what kind of instance to return. | ||||||
| controlType can be one of: | controlType can be one of: | ||||||
| <PRE><FONT SIZE=-1> | <PRE><FONT SIZE=-1> | ||||||
|     controlTypes.MASKEDTEXT |     controlTypes.TEXT | ||||||
|     controlTypes.MASKEDCOMBO |     controlTypes.COMBO | ||||||
|     controlTypes.IPADDR |     controlTypes.IPADDR | ||||||
|     controlTypes.TIME |     controlTypes.TIME | ||||||
|     controlTypes.NUMBER |     controlTypes.NUMBER | ||||||
| @@ -42,56 +42,56 @@ controlType can be one of: | |||||||
| These constants are also available individually, ie, you can | These constants are also available individually, ie, you can | ||||||
| use either of the following: | use either of the following: | ||||||
| <PRE><FONT SIZE=-1> | <PRE><FONT SIZE=-1> | ||||||
|     from wxPython.wx.lib.maskedctrl import MaskedCtrl, MASKEDCOMBO, MASKEDTEXT, NUMBER |     from wxPython.wx.lib.masked import Ctrl, COMBO, TEXT, NUMBER, TIME | ||||||
|     from wxPython.wx.lib.maskedctrl import MaskedCtrl, controlTypes |     from wxPython.wx.lib.masked import Ctrl, controlTypes | ||||||
| </FONT></PRE> | </FONT></PRE> | ||||||
| If not specified as a keyword argument, the default controlType is | If not specified as a keyword argument, the default controlType is | ||||||
| controlTypes.MASKEDTEXT. | controlTypes.TEXT. | ||||||
| <P> | <P> | ||||||
| Each of the above classes has its own unique arguments, but MaskedCtrl | Each of the above classes has its own unique arguments, but MaskedCtrl | ||||||
| provides a single "unified" interface for masked controls.  MaskedTextCtrl, | provides a single "unified" interface for masked controls.  Masked.TextCtrl, | ||||||
| MaskedComboBox and IpAddrCtrl are all documented below; the others have | masked.ComboBox and masked.IpAddrCtrl are all documented below; the others have | ||||||
| their own demo pages and interface descriptions. | their own demo pages and interface descriptions. | ||||||
| </body></html> | </body></html> | ||||||
| """ | """ | ||||||
| 
 | 
 | ||||||
| from wx.lib.maskededit      import MaskedTextCtrl, MaskedComboBox, IpAddrCtrl | from wx.lib.masked   import TextCtrl, ComboBox, IpAddrCtrl | ||||||
| from wx.lib.maskednumctrl   import MaskedNumCtrl | from wx.lib.masked   import NumCtrl | ||||||
| from wx.lib.timectrl        import TimeCtrl | from wx.lib.masked   import TimeCtrl | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # "type" enumeration for class instance factory function | # "type" enumeration for class instance factory function | ||||||
| MASKEDTEXT  = 0 | TEXT        = 0 | ||||||
| MASKEDCOMBO = 1 | COMBO       = 1 | ||||||
| IPADDR      = 2 | IPADDR      = 2 | ||||||
| TIME        = 3 | TIME        = 3 | ||||||
| NUMBER      = 4 | NUMBER      = 4 | ||||||
| 
 | 
 | ||||||
| # for ease of import | # for ease of import | ||||||
| class controlTypes: | class controlTypes: | ||||||
|     MASKEDTEXT  = MASKEDTEXT |     TEXT        = TEXT | ||||||
|     MASKEDCOMBO = MASKEDCOMBO |     COMBO       = COMBO | ||||||
|     IPADDR      = IPADDR |     IPADDR      = IPADDR | ||||||
|     TIME        = TIME |     TIME        = TIME | ||||||
|     NUMBER      = NUMBER |     NUMBER      = NUMBER | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def MaskedCtrl( *args, **kwargs): | def Ctrl( *args, **kwargs): | ||||||
|     """ |     """ | ||||||
|     Actually a factory function providing a unifying |     Actually a factory function providing a unifying | ||||||
|     interface for generating masked controls. |     interface for generating masked controls. | ||||||
|     """ |     """ | ||||||
|     if not kwargs.has_key('controlType'): |     if not kwargs.has_key('controlType'): | ||||||
|         controlType = MASKEDTEXT |         controlType = TEXT | ||||||
|     else: |     else: | ||||||
|         controlType = kwargs['controlType'] |         controlType = kwargs['controlType'] | ||||||
|         del kwargs['controlType'] |         del kwargs['controlType'] | ||||||
| 
 | 
 | ||||||
|     if controlType == MASKEDTEXT: |     if controlType == TEXT: | ||||||
|         return MaskedTextCtrl(*args, **kwargs) |         return TextCtrl(*args, **kwargs) | ||||||
| 
 | 
 | ||||||
|     elif controlType == MASKEDCOMBO: |     elif controlType == COMBO: | ||||||
|         return MaskedComboBox(*args, **kwargs) |         return ComboBox(*args, **kwargs) | ||||||
| 
 | 
 | ||||||
|     elif controlType == IPADDR: |     elif controlType == IPADDR: | ||||||
|         return IpAddrCtrl(*args, **kwargs) |         return IpAddrCtrl(*args, **kwargs) | ||||||
| @@ -100,7 +100,7 @@ def MaskedCtrl( *args, **kwargs): | |||||||
|         return TimeCtrl(*args, **kwargs) |         return TimeCtrl(*args, **kwargs) | ||||||
| 
 | 
 | ||||||
|     elif controlType == NUMBER: |     elif controlType == NUMBER: | ||||||
|         return MaskedNumCtrl(*args, **kwargs) |         return NumCtrl(*args, **kwargs) | ||||||
| 
 | 
 | ||||||
|     else: |     else: | ||||||
|         raise AttributeError( |         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 | # Author:       Will Sadkin | ||||||
| # Created:      09/06/2003 | # Created:      09/06/2003 | ||||||
| # Copyright:   (c) 2003 by Will Sadkin | # Copyright:   (c) 2003 by Will Sadkin | ||||||
| @@ -9,12 +9,12 @@ | |||||||
| # NOTE: | # NOTE: | ||||||
| #   This was written to provide a numeric edit control for wxPython that | #   This was written to provide a numeric edit control for wxPython that | ||||||
| #   does things like right-insert (like a calculator), and does grouping, etc. | #   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. | #   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 | #   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. | #   changes to the control. | ||||||
| # | # | ||||||
| #   It supports negative numbers as well as the naturals, and has the option | #   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 | #   Similarly, replacing the contents of the control with '-' will result in | ||||||
| #   a selected (absolute) value of -1. | #   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 | #   enforcing them or simply coloring the text of the control if the limits | ||||||
| #   are exceeded. | #   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 | #   is derived from BaseMaskedTextCtrl.  As such, it supports a limited range | ||||||
| #   of values to comply with a fixed-width entry mask. | #   of values to comply with a fixed-width entry mask. | ||||||
| #---------------------------------------------------------------------------- | #---------------------------------------------------------------------------- | ||||||
| @@ -39,14 +39,14 @@ | |||||||
| # 12/20/2003 - Jeff Grimmett (grimmtooth@softhome.net) | # 12/20/2003 - Jeff Grimmett (grimmtooth@softhome.net) | ||||||
| # | # | ||||||
| # o wxMaskedEditMixin -> MaskedEditMixin | # o wxMaskedEditMixin -> MaskedEditMixin | ||||||
| # o wxMaskedTextCtrl -> MaskedTextCtrl | # o wxMaskedTextCtrl -> masked.TextCtrl | ||||||
| # o wxMaskedNumNumberUpdatedEvent -> MaskedNumNumberUpdatedEvent | # o wxMaskedNumNumberUpdatedEvent -> masked.NumberUpdatedEvent | ||||||
| # o wxMaskedNumCtrl -> MaskedNumCtrl | # o wxMaskedNumCtrl -> masked.NumCtrl | ||||||
| # | # | ||||||
| 
 | 
 | ||||||
| """<html><body> | """<html><body> | ||||||
| <P> | <P> | ||||||
| <B>MaskedNumCtrl:</B> | <B>masked.NumCtrl:</B> | ||||||
| <UL> | <UL> | ||||||
| <LI>allows you to get and set integer or floating point numbers as value,</LI> | <LI>allows you to get and set integer or floating point numbers as value,</LI> | ||||||
| <LI>provides bounds support and optional value limiting,</LI> | <LI>provides bounds support and optional value limiting,</LI> | ||||||
| @@ -62,14 +62,14 @@ fractional portion. | |||||||
| <P> | <P> | ||||||
| Here's the API: | Here's the API: | ||||||
| <DL><PRE> | <DL><PRE> | ||||||
|     <B>MaskedNumCtrl</B>( |     <B>masked.NumCtrl</B>( | ||||||
|          parent, id = -1, |          parent, id = -1, | ||||||
|          <B>value</B> = 0, |          <B>value</B> = 0, | ||||||
|          pos = wx.DefaultPosition, |          pos = wx.DefaultPosition, | ||||||
|          size = wx.DefaultSize, |          size = wx.DefaultSize, | ||||||
|          style = 0, |          style = 0, | ||||||
|          validator = wx.DefaultValidator, |          validator = wx.DefaultValidator, | ||||||
|          name = "maskednumber", |          name = "masked.number", | ||||||
|          <B>integerWidth</B> = 10, |          <B>integerWidth</B> = 10, | ||||||
|          <B>fractionWidth</B> = 0, |          <B>fractionWidth</B> = 0, | ||||||
|          <B>allowNone</B> = False, |          <B>allowNone</B> = False, | ||||||
| @@ -190,7 +190,7 @@ Here's the API: | |||||||
| </UL> | </UL> | ||||||
| <BR> | <BR> | ||||||
| <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 | <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 | 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 | 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 | MININT = -maxint-1 | ||||||
| 
 | 
 | ||||||
| from wx.tools.dbg import Logger | 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 = Logger() | ||||||
| dbg(enable=0) | ##dbg(enable=0) | ||||||
| 
 | 
 | ||||||
| #---------------------------------------------------------------------------- | #---------------------------------------------------------------------------- | ||||||
| 
 | 
 | ||||||
| wxEVT_COMMAND_MASKED_NUMBER_UPDATED = wx.NewEventType() | 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): |     def __init__(self, id, value = 0, object=None): | ||||||
|         wx.PyCommandEvent.__init__(self, wxEVT_COMMAND_MASKED_NUMBER_UPDATED, id) |         wx.PyCommandEvent.__init__(self, wxEVT_COMMAND_MASKED_NUMBER_UPDATED, id) | ||||||
| 
 | 
 | ||||||
| @@ -409,8 +409,8 @@ class MaskedNumNumberUpdatedEvent(wx.PyCommandEvent): | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #---------------------------------------------------------------------------- | #---------------------------------------------------------------------------- | ||||||
| class MaskedNumCtrlAccessorsMixin: | class NumCtrlAccessorsMixin: | ||||||
|     # Define wxMaskedNumCtrl's list of attributes having their own |     # Define masked.NumCtrl's list of attributes having their own | ||||||
|     # Get/Set functions, ignoring those that make no sense for |     # Get/Set functions, ignoring those that make no sense for | ||||||
|     # an numeric control. |     # an numeric control. | ||||||
|     exposed_basectrl_params = ( |     exposed_basectrl_params = ( | ||||||
| @@ -448,7 +448,7 @@ class MaskedNumCtrlAccessorsMixin: | |||||||
| 
 | 
 | ||||||
| #---------------------------------------------------------------------------- | #---------------------------------------------------------------------------- | ||||||
| 
 | 
 | ||||||
| class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | class NumCtrl(BaseMaskedTextCtrl, NumCtrlAccessorsMixin): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     valid_ctrl_params = { |     valid_ctrl_params = { | ||||||
| @@ -478,31 +478,32 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|                 self, parent, id=-1, value = 0, |                 self, parent, id=-1, value = 0, | ||||||
|                 pos = wx.DefaultPosition, size = wx.DefaultSize, |                 pos = wx.DefaultPosition, size = wx.DefaultSize, | ||||||
|                 style = wx.TE_PROCESS_TAB, validator = wx.DefaultValidator, |                 style = wx.TE_PROCESS_TAB, validator = wx.DefaultValidator, | ||||||
|                 name = "maskednum", |                 name = "masked.num", | ||||||
|                 **kwargs ): |                 **kwargs ): | ||||||
| 
 | 
 | ||||||
|         dbg('MaskedNumCtrl::__init__', indent=1) | ##        dbg('masked.NumCtrl::__init__', indent=1) | ||||||
| 
 | 
 | ||||||
|         # Set defaults for control: |         # Set defaults for control: | ||||||
|         dbg('setting defaults:') | ##        dbg('setting defaults:') | ||||||
|         for key, param_value in MaskedNumCtrl.valid_ctrl_params.items(): |         for key, param_value in NumCtrl.valid_ctrl_params.items(): | ||||||
|             # This is done this way to make setattr behave consistently with |             # This is done this way to make setattr behave consistently with | ||||||
|             # "private attribute" name mangling |             # "private attribute" name mangling | ||||||
|             setattr(self, '_' + key, copy.copy(param_value)) |             setattr(self, '_' + key, copy.copy(param_value)) | ||||||
| 
 | 
 | ||||||
|         # Assign defaults for all attributes: |         # Assign defaults for all attributes: | ||||||
|         init_args = copy.deepcopy(MaskedNumCtrl.valid_ctrl_params) |         init_args = copy.deepcopy(NumCtrl.valid_ctrl_params) | ||||||
|         dbg('kwargs:', kwargs) | ##        dbg('kwargs:', kwargs) | ||||||
|         for key, param_value in kwargs.items(): |         for key, param_value in kwargs.items(): | ||||||
|             key = key.replace('Color', 'Colour') |             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) |                 raise AttributeError('invalid keyword argument "%s"' % key) | ||||||
|             else: |             else: | ||||||
|                 init_args[key] = param_value |                 init_args[key] = param_value | ||||||
|         dbg('init_args:', indent=1) | ##        dbg('init_args:', indent=1) | ||||||
|         for key, param_value in init_args.items(): |         for key, param_value in init_args.items(): | ||||||
|             dbg('%s:' % key, param_value) | ##            dbg('%s:' % key, param_value) | ||||||
|         dbg(indent=0) |             pass | ||||||
|  | ##        dbg(indent=0) | ||||||
| 
 | 
 | ||||||
|         # Process initial fields for the control, as part of construction: |         # Process initial fields for the control, as part of construction: | ||||||
|         if type(init_args['integerWidth']) != types.IntType: |         if type(init_args['integerWidth']) != types.IntType: | ||||||
| @@ -521,7 +522,7 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
| 
 | 
 | ||||||
|         if self._fractionWidth: |         if self._fractionWidth: | ||||||
|             fracmask = '.' + '#{%d}' % self._fractionWidth |             fracmask = '.' + '#{%d}' % self._fractionWidth | ||||||
|             dbg('fracmask:', fracmask) | ##            dbg('fracmask:', fracmask) | ||||||
|             fields[1] = Field(defaultValue='0'*self._fractionWidth) |             fields[1] = Field(defaultValue='0'*self._fractionWidth) | ||||||
|         else: |         else: | ||||||
|             fracmask = '' |             fracmask = '' | ||||||
| @@ -537,7 +538,7 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|         else: |         else: | ||||||
|             emptyInvalid = True |             emptyInvalid = True | ||||||
|         fields[0] = Field(formatcodes='r<>', emptyInvalid=emptyInvalid) |         fields[0] = Field(formatcodes='r<>', emptyInvalid=emptyInvalid) | ||||||
|         dbg('intmask:', intmask) | ##        dbg('intmask:', intmask) | ||||||
| 
 | 
 | ||||||
|         # don't bother to reprocess these arguments: |         # don't bother to reprocess these arguments: | ||||||
|         del init_args['integerWidth'] |         del init_args['integerWidth'] | ||||||
| @@ -585,14 +586,14 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
| 
 | 
 | ||||||
|         # Ensure proper coloring: |         # Ensure proper coloring: | ||||||
|         self.Refresh() |         self.Refresh() | ||||||
|         dbg('finished MaskedNumCtrl::__init__', indent=0) | ##        dbg('finished NumCtrl::__init__', indent=0) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def SetParameters(self, **kwargs): |     def SetParameters(self, **kwargs): | ||||||
|         """ |         """ | ||||||
|         This routine is used to initialize and reconfigure the control: |         This routine is used to initialize and reconfigure the control: | ||||||
|         """ |         """ | ||||||
|         dbg('MaskedNumCtrl::SetParameters', indent=1) | ##        dbg('NumCtrl::SetParameters', indent=1) | ||||||
|         maskededit_kwargs = {} |         maskededit_kwargs = {} | ||||||
|         reset_fraction_width = False |         reset_fraction_width = False | ||||||
| 
 | 
 | ||||||
| @@ -620,14 +621,14 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|             else: |             else: | ||||||
|                 emptyInvalid = True |                 emptyInvalid = True | ||||||
|                 fracmask = '' |                 fracmask = '' | ||||||
|             dbg('fracmask:', fracmask) | ##            dbg('fracmask:', fracmask) | ||||||
| 
 | 
 | ||||||
|             if kwargs.has_key('integerWidth'): |             if kwargs.has_key('integerWidth'): | ||||||
|                 if type(kwargs['integerWidth']) != types.IntType: |                 if type(kwargs['integerWidth']) != types.IntType: | ||||||
|                     dbg(indent=0) | ##                    dbg(indent=0) | ||||||
|                     raise AttributeError('invalid integerWidth (%s) specified; expected integer' % repr(kwargs['integerWidth'])) |                     raise AttributeError('invalid integerWidth (%s) specified; expected integer' % repr(kwargs['integerWidth'])) | ||||||
|                 elif kwargs['integerWidth'] < 0: |                 elif kwargs['integerWidth'] < 0: | ||||||
|                     dbg(indent=0) | ##                    dbg(indent=0) | ||||||
|                     raise AttributeError('invalid integerWidth (%s) specified; must be > 0' % repr(kwargs['integerWidth'])) |                     raise AttributeError('invalid integerWidth (%s) specified; must be > 0' % repr(kwargs['integerWidth'])) | ||||||
|                 else: |                 else: | ||||||
|                     self._integerWidth = kwargs['integerWidth'] |                     self._integerWidth = kwargs['integerWidth'] | ||||||
| @@ -641,7 +642,7 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|                 self._groupSpace = 0 |                 self._groupSpace = 0 | ||||||
| 
 | 
 | ||||||
|             intmask = '#{%d}' % (self._integerWidth + self._groupSpace) |             intmask = '#{%d}' % (self._integerWidth + self._groupSpace) | ||||||
|             dbg('intmask:', intmask) | ##            dbg('intmask:', intmask) | ||||||
|             fields[0] = Field(formatcodes='r<>', emptyInvalid=emptyInvalid) |             fields[0] = Field(formatcodes='r<>', emptyInvalid=emptyInvalid) | ||||||
|             maskededit_kwargs['fields'] = fields |             maskededit_kwargs['fields'] = fields | ||||||
| 
 | 
 | ||||||
| @@ -655,17 +656,17 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
| 
 | 
 | ||||||
|         if kwargs.has_key('groupChar'): |         if kwargs.has_key('groupChar'): | ||||||
|             old_groupchar = self._groupChar     # save so we can reformat properly |             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'] |             maskededit_kwargs['groupChar'] = kwargs['groupChar'] | ||||||
|         if kwargs.has_key('decimalChar'): |         if kwargs.has_key('decimalChar'): | ||||||
|             old_decimalchar = self._decimalChar |             old_decimalchar = self._decimalChar | ||||||
|             dbg("old_decimalchar: '%s'" % old_decimalchar) | ##            dbg("old_decimalchar: '%s'" % old_decimalchar) | ||||||
|             maskededit_kwargs['decimalChar'] = kwargs['decimalChar'] |             maskededit_kwargs['decimalChar'] = kwargs['decimalChar'] | ||||||
| 
 | 
 | ||||||
|         # for all other parameters, assign keyword args as appropriate: |         # for all other parameters, assign keyword args as appropriate: | ||||||
|         for key, param_value in kwargs.items(): |         for key, param_value in kwargs.items(): | ||||||
|             key = key.replace('Color', 'Colour') |             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) |                 raise AttributeError('invalid keyword argument "%s"' % key) | ||||||
|             elif key not in MaskedEditMixin.valid_ctrl_params.keys(): |             elif key not in MaskedEditMixin.valid_ctrl_params.keys(): | ||||||
|                 setattr(self, '_' + key, param_value) |                 setattr(self, '_' + key, param_value) | ||||||
| @@ -673,7 +674,7 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|                 raise AttributeError('invalid keyword argument "%s"' % key) |                 raise AttributeError('invalid keyword argument "%s"' % key) | ||||||
|             else: |             else: | ||||||
|                 maskededit_kwargs[key] = param_value |                 maskededit_kwargs[key] = param_value | ||||||
|         dbg('kwargs:', kwargs) | ##        dbg('kwargs:', kwargs) | ||||||
| 
 | 
 | ||||||
|         # reprocess existing format codes to ensure proper resulting format: |         # reprocess existing format codes to ensure proper resulting format: | ||||||
|         formatcodes = self.GetCtrlParameter('formatcodes') |         formatcodes = self.GetCtrlParameter('formatcodes') | ||||||
| @@ -695,7 +696,7 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
| 
 | 
 | ||||||
|         if kwargs.has_key('selectOnEntry'): |         if kwargs.has_key('selectOnEntry'): | ||||||
|             self._selectOnEntry = kwargs['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: |             if kwargs['selectOnEntry'] and 'S' not in formatcodes: | ||||||
|                 formatcodes += 'S' |                 formatcodes += 'S' | ||||||
|                 maskededit_kwargs['formatcodes'] = formatcodes |                 maskededit_kwargs['formatcodes'] = formatcodes | ||||||
| @@ -728,7 +729,7 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|                 maskededit_kwargs['validRequired'] = False |                 maskededit_kwargs['validRequired'] = False | ||||||
|             self._limited = kwargs['limited'] |             self._limited = kwargs['limited'] | ||||||
| 
 | 
 | ||||||
|         dbg('maskededit_kwargs:', maskededit_kwargs) | ##        dbg('maskededit_kwargs:', maskededit_kwargs) | ||||||
|         if maskededit_kwargs.keys(): |         if maskededit_kwargs.keys(): | ||||||
|             self.SetCtrlParameters(**maskededit_kwargs) |             self.SetCtrlParameters(**maskededit_kwargs) | ||||||
| 
 | 
 | ||||||
| @@ -756,17 +757,18 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|             if( self._max is None |             if( self._max is None | ||||||
|                 or min is None |                 or min is None | ||||||
|                 or (self._max is not None and self._max >= min) ): |                 or (self._max is not None and self._max >= min) ): | ||||||
|                 dbg('examining min') | ##                dbg('examining min') | ||||||
|                 if min is not None: |                 if min is not None: | ||||||
|                     try: |                     try: | ||||||
|                         textmin = self._toGUI(min, apply_limits = False) |                         textmin = self._toGUI(min, apply_limits = False) | ||||||
|                     except ValueError: |                     except ValueError: | ||||||
|                         dbg('min will not fit into control; ignoring', indent=0) | ##                        dbg('min will not fit into control; ignoring', indent=0) | ||||||
|                         raise |                         raise | ||||||
|                 dbg('accepted min') | ##                dbg('accepted min') | ||||||
|                 self._min = min |                 self._min = min | ||||||
|             else: |             else: | ||||||
|                 dbg('ignoring min') | ##                dbg('ignoring min') | ||||||
|  |                 pass | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         if kwargs.has_key('max'): |         if kwargs.has_key('max'): | ||||||
| @@ -774,24 +776,25 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|             if( self._min is None |             if( self._min is None | ||||||
|                 or max is None |                 or max is None | ||||||
|                 or (self._min is not None and self._min <= max) ): |                 or (self._min is not None and self._min <= max) ): | ||||||
|                 dbg('examining max') | ##                dbg('examining max') | ||||||
|                 if max is not None: |                 if max is not None: | ||||||
|                     try: |                     try: | ||||||
|                         textmax = self._toGUI(max, apply_limits = False) |                         textmax = self._toGUI(max, apply_limits = False) | ||||||
|                     except ValueError: |                     except ValueError: | ||||||
|                         dbg('max will not fit into control; ignoring', indent=0) | ##                        dbg('max will not fit into control; ignoring', indent=0) | ||||||
|                         raise |                         raise | ||||||
|                 dbg('accepted max') | ##                dbg('accepted max') | ||||||
|                 self._max = max |                 self._max = max | ||||||
|             else: |             else: | ||||||
|                 dbg('ignoring max') | ##                dbg('ignoring max') | ||||||
|  |                 pass | ||||||
| 
 | 
 | ||||||
|         if kwargs.has_key('allowNegative'): |         if kwargs.has_key('allowNegative'): | ||||||
|             self._allowNegative = kwargs['allowNegative'] |             self._allowNegative = kwargs['allowNegative'] | ||||||
| 
 | 
 | ||||||
|         # Ensure current value of control obeys any new restrictions imposed: |         # Ensure current value of control obeys any new restrictions imposed: | ||||||
|         text = self._GetValue() |         text = self._GetValue() | ||||||
|         dbg('text value: "%s"' % text) | ##        dbg('text value: "%s"' % text) | ||||||
|         if kwargs.has_key('groupChar') and text.find(old_groupchar) != -1: |         if kwargs.has_key('groupChar') and text.find(old_groupchar) != -1: | ||||||
|             text = text.replace(old_groupchar, self._groupChar) |             text = text.replace(old_groupchar, self._groupChar) | ||||||
|         if kwargs.has_key('decimalChar') and text.find(old_decimalchar) != -1: |         if kwargs.has_key('decimalChar') and text.find(old_decimalchar) != -1: | ||||||
| @@ -801,10 +804,10 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
| 
 | 
 | ||||||
|         value = self.GetValue() |         value = self.GetValue() | ||||||
| 
 | 
 | ||||||
|         dbg('self._allowNegative?', self._allowNegative) | ##        dbg('self._allowNegative?', self._allowNegative) | ||||||
|         if not self._allowNegative and self._isNeg: |         if not self._allowNegative and self._isNeg: | ||||||
|             value = abs(value) |             value = abs(value) | ||||||
|             dbg('abs(value):', value) | ##            dbg('abs(value):', value) | ||||||
|             self._isNeg = False |             self._isNeg = False | ||||||
| 
 | 
 | ||||||
|         elif not self._allowNone and BaseMaskedTextCtrl.GetValue(self) == '': |         elif not self._allowNone and BaseMaskedTextCtrl.GetValue(self) == '': | ||||||
| @@ -815,19 +818,19 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
| 
 | 
 | ||||||
|         sel_start, sel_to = self.GetSelection() |         sel_start, sel_to = self.GetSelection() | ||||||
|         if self.IsLimited() and self._min is not None and value < self._min: |         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)) |             self._SetValue(self._toGUI(self._min)) | ||||||
| 
 | 
 | ||||||
|         elif self.IsLimited() and self._max is not None and value > self._max: |         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)) |             self._SetValue(self._toGUI(self._max)) | ||||||
|         else: |         else: | ||||||
|             # reformat current value as appropriate to possibly new conditions |             # reformat current value as appropriate to possibly new conditions | ||||||
|             dbg('Reformatting value:', value) | ##            dbg('Reformatting value:', value) | ||||||
|             sel_start, sel_to = self.GetSelection() |             sel_start, sel_to = self.GetSelection() | ||||||
|             self._SetValue(self._toGUI(value)) |             self._SetValue(self._toGUI(value)) | ||||||
|         self.Refresh() # recolor as appropriate |         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) |                 return string.atof(fracstring) | ||||||
| 
 | 
 | ||||||
|     def _OnChangeSign(self, event): |     def _OnChangeSign(self, event): | ||||||
|         dbg('MaskedNumCtrl::_OnChangeSign', indent=1) | ##        dbg('NumCtrl::_OnChangeSign', indent=1) | ||||||
|         self._typedSign = True |         self._typedSign = True | ||||||
|         MaskedEditMixin._OnChangeSign(self, event) |         MaskedEditMixin._OnChangeSign(self, event) | ||||||
|         dbg(indent=0) | ##        dbg(indent=0) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def _disallowValue(self): |     def _disallowValue(self): | ||||||
|         dbg('MaskedNumCtrl::_disallowValue') | ##        dbg('NumCtrl::_disallowValue') | ||||||
|         # limited and -1 is out of bounds |         # limited and -1 is out of bounds | ||||||
|         if self._typedSign: |         if self._typedSign: | ||||||
|             self._isNeg = False |             self._isNeg = False | ||||||
|         if not wx.Validator_IsSilent(): |         if not wx.Validator_IsSilent(): | ||||||
|             wx.Bell() |             wx.Bell() | ||||||
|         sel_start, sel_to = self._GetSelection() |         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.SetInsertionPoint, sel_start)      # preserve current selection/position | ||||||
|         wx.CallAfter(self.SetSelection, sel_start, sel_to) |         wx.CallAfter(self.SetSelection, sel_start, sel_to) | ||||||
| 
 | 
 | ||||||
| @@ -886,19 +889,19 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|         by the user. |         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 |         if( (self._fractionWidth and value.find(self._decimalChar) == -1) or | ||||||
|             (self._fractionWidth == 0 and value.find(self._decimalChar) != -1) ) : |             (self._fractionWidth == 0 and value.find(self._decimalChar) != -1) ) : | ||||||
|             value = self._toGUI(value) |             value = self._toGUI(value) | ||||||
| 
 | 
 | ||||||
|         numvalue = self._GetNumValue(value) |         numvalue = self._GetNumValue(value) | ||||||
|         dbg('cleansed value: "%s"' % numvalue) | ##        dbg('cleansed value: "%s"' % numvalue) | ||||||
|         replacement = None |         replacement = None | ||||||
| 
 | 
 | ||||||
|         if numvalue == "": |         if numvalue == "": | ||||||
|             if self._allowNone: |             if self._allowNone: | ||||||
|                 dbg('calling base BaseMaskedTextCtrl._SetValue(self, "%s")' % value) | ##                dbg('calling base BaseMaskedTextCtrl._SetValue(self, "%s")' % value) | ||||||
|                 BaseMaskedTextCtrl._SetValue(self, value) |                 BaseMaskedTextCtrl._SetValue(self, value) | ||||||
|                 self.Refresh() |                 self.Refresh() | ||||||
|                 return |                 return | ||||||
| @@ -906,54 +909,54 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|                 replacement = self._min |                 replacement = self._min | ||||||
|             else: |             else: | ||||||
|                 replacement = 0 |                 replacement = 0 | ||||||
|             dbg('empty value; setting replacement:', replacement) | ##            dbg('empty value; setting replacement:', replacement) | ||||||
| 
 | 
 | ||||||
|         if replacement is None: |         if replacement is None: | ||||||
|             # Go get the integer portion about to be set and verify its validity |             # Go get the integer portion about to be set and verify its validity | ||||||
|             intstart, intend = self._fields[0]._extent |             intstart, intend = self._fields[0]._extent | ||||||
|             dbg('intstart, intend:', intstart, intend) | ##            dbg('intstart, intend:', intstart, intend) | ||||||
|             dbg('raw integer:"%s"' % value[intstart:intend]) | ##            dbg('raw integer:"%s"' % value[intstart:intend]) | ||||||
|             int = self._GetNumValue(value[intstart:intend]) |             int = self._GetNumValue(value[intstart:intend]) | ||||||
|             numval = self._fromGUI(value) |             numval = self._fromGUI(value) | ||||||
| 
 | 
 | ||||||
|             dbg('integer: "%s"' % int) | ##            dbg('integer: "%s"' % int) | ||||||
|             try: |             try: | ||||||
|                 fracval = self.GetFraction(value) |                 fracval = self.GetFraction(value) | ||||||
|             except ValueError, e: |             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() |                 self._disallowValue() | ||||||
|                 dbg(indent=0) | ##                dbg(indent=0) | ||||||
|                 return |                 return | ||||||
| 
 | 
 | ||||||
|             if fracval == 0.0: |             if fracval == 0.0: | ||||||
|                 dbg('self._isNeg?', self._isNeg) | ##                dbg('self._isNeg?', self._isNeg) | ||||||
|                 if int == '-' and self._oldvalue < 0 and not self._typedSign: |                 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 |                     replacement = 0 | ||||||
|                     self._isNeg = False |                     self._isNeg = False | ||||||
|                 elif int[:2] == '-0' and self._fractionWidth == 0: |                 elif int[:2] == '-0' and self._fractionWidth == 0: | ||||||
|                     if self._oldvalue < 0: |                     if self._oldvalue < 0: | ||||||
|                         dbg('-0; setting replacement of 0') | ##                        dbg('-0; setting replacement of 0') | ||||||
|                         replacement = 0 |                         replacement = 0 | ||||||
|                         self._isNeg = False |                         self._isNeg = False | ||||||
|                     elif not self._limited or (self._min < -1 and self._max >= -1): |                     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 |                         replacement = -1 | ||||||
|                         self._isNeg = True |                         self._isNeg = True | ||||||
|                     else: |                     else: | ||||||
|                         # limited and -1 is out of bounds |                         # limited and -1 is out of bounds | ||||||
|                         self._disallowValue() |                         self._disallowValue() | ||||||
|                         dbg(indent=0) | ##                        dbg(indent=0) | ||||||
|                         return |                         return | ||||||
| 
 | 
 | ||||||
|                 elif int == '-' and (self._oldvalue >= 0 or self._typedSign) and self._fractionWidth == 0: |                 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): |                     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 |                         replacement = -1 | ||||||
|                     else: |                     else: | ||||||
|                         # limited and -1 is out of bounds |                         # limited and -1 is out of bounds | ||||||
|                         self._disallowValue() |                         self._disallowValue() | ||||||
|                         dbg(indent=0) | ##                        dbg(indent=0) | ||||||
|                         return |                         return | ||||||
| 
 | 
 | ||||||
|                 elif( self._typedSign |                 elif( self._typedSign | ||||||
| @@ -963,7 +966,7 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|                     # changed sign resulting in value that's now out-of-bounds; |                     # changed sign resulting in value that's now out-of-bounds; | ||||||
|                     # disallow |                     # disallow | ||||||
|                     self._disallowValue() |                     self._disallowValue() | ||||||
|                     dbg(indent=0) | ##                    dbg(indent=0) | ||||||
|                     return |                     return | ||||||
| 
 | 
 | ||||||
|             if replacement is None: |             if replacement is None: | ||||||
| @@ -974,37 +977,37 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|                         # integer requested is not legal.  This can happen if the user |                         # integer requested is not legal.  This can happen if the user | ||||||
|                         # is attempting to insert a digit in the middle of the control |                         # is attempting to insert a digit in the middle of the control | ||||||
|                         # resulting in something like "   3   45". Disallow such actions: |                         # 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(): |                         if not wx.Validator_IsSilent(): | ||||||
|                             wx.Bell() |                             wx.Bell() | ||||||
|                         sel_start, sel_to = self._GetSelection() |                         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.SetInsertionPoint, sel_start)      # preserve current selection/position | ||||||
|                         wx.CallAfter(self.SetSelection, sel_start, sel_to) |                         wx.CallAfter(self.SetSelection, sel_start, sel_to) | ||||||
|                         dbg(indent=0) | ##                        dbg(indent=0) | ||||||
|                         return |                         return | ||||||
| 
 | 
 | ||||||
|                     if int[0] == '0' and len(int) > 1: |                     if int[0] == '0' and len(int) > 1: | ||||||
|                         dbg('numvalue: "%s"' % numvalue.replace(' ', '')) | ##                        dbg('numvalue: "%s"' % numvalue.replace(' ', '')) | ||||||
|                         if self._fractionWidth: |                         if self._fractionWidth: | ||||||
|                             value = self._toGUI(string.atof(numvalue)) |                             value = self._toGUI(string.atof(numvalue)) | ||||||
|                         else: |                         else: | ||||||
|                             value = self._toGUI(string.atol(numvalue)) |                             value = self._toGUI(string.atol(numvalue)) | ||||||
|                         dbg('modified value: "%s"' % value) | ##                        dbg('modified value: "%s"' % value) | ||||||
| 
 | 
 | ||||||
|         self._typedSign = False     # reset state var |         self._typedSign = False     # reset state var | ||||||
| 
 | 
 | ||||||
|         if replacement is not None: |         if replacement is not None: | ||||||
|             # Value presented wasn't a legal number, but control should do something |             # Value presented wasn't a legal number, but control should do something | ||||||
|             # reasonable instead: |             # reasonable instead: | ||||||
|             dbg('setting replacement value:', replacement) | ##            dbg('setting replacement value:', replacement) | ||||||
|             self._SetValue(self._toGUI(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_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))) |             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.SetInsertionPoint, sel_start) | ||||||
|             wx.CallAfter(self.SetSelection, sel_start, sel_to) |             wx.CallAfter(self.SetSelection, sel_start, sel_to) | ||||||
|             dbg(indent=0) | ##            dbg(indent=0) | ||||||
|             return |             return | ||||||
| 
 | 
 | ||||||
|         # Otherwise, apply appropriate formatting to value: |         # Otherwise, apply appropriate formatting to value: | ||||||
| @@ -1016,35 +1019,35 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|         else: |         else: | ||||||
|             self._isNeg = False |             self._isNeg = False | ||||||
| 
 | 
 | ||||||
|         dbg('value:"%s"' % value, 'self._useParens:', self._useParens) | ##        dbg('value:"%s"' % value, 'self._useParens:', self._useParens) | ||||||
|         if self._fractionWidth: |         if self._fractionWidth: | ||||||
|             adjvalue = self._adjustFloat(self._GetNumValue(value).replace('.',self._decimalChar)) |             adjvalue = self._adjustFloat(self._GetNumValue(value).replace('.',self._decimalChar)) | ||||||
|         else: |         else: | ||||||
|             adjvalue = self._adjustInt(self._GetNumValue(value)) |             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 |         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) |         BaseMaskedTextCtrl._SetValue(self, adjvalue) | ||||||
|         # After all actions so far scheduled, check that resulting cursor |         # After all actions so far scheduled, check that resulting cursor | ||||||
|         # position is appropriate, and move if not: |         # position is appropriate, and move if not: | ||||||
|         wx.CallAfter(self._CheckInsertionPoint) |         wx.CallAfter(self._CheckInsertionPoint) | ||||||
| 
 | 
 | ||||||
|         dbg('finished MaskedNumCtrl::_SetValue', indent=0) | ##        dbg('finished NumCtrl::_SetValue', indent=0) | ||||||
| 
 | 
 | ||||||
|     def _CheckInsertionPoint(self): |     def _CheckInsertionPoint(self): | ||||||
|         # If current insertion point is before the end of the integer and |         # If current insertion point is before the end of the integer and | ||||||
|         # its before the 1st digit, place it just after the sign position: |         # 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() |         sel_start, sel_to = self._GetSelection() | ||||||
|         text = self._GetValue() |         text = self._GetValue() | ||||||
|         if sel_to < self._fields[0]._extent[1] and text[sel_to] in (' ', '-', '('): |         if sel_to < self._fields[0]._extent[1] and text[sel_to] in (' ', '-', '('): | ||||||
|             text, signpos, right_signpos = self._getSignedValue() |             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.SetInsertionPoint(signpos+1) | ||||||
|             self.SetSelection(signpos+1, signpos+1) |             self.SetSelection(signpos+1, signpos+1) | ||||||
|         dbg(indent=0) | ##        dbg(indent=0) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def _OnErase( self, event ): |     def _OnErase( self, event ): | ||||||
| @@ -1053,7 +1056,7 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|         grouping characters auto selects the digit before or after the |         grouping characters auto selects the digit before or after the | ||||||
|         grouping character, so that the erasure does the right thing. |         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 |         #if grouping digits, make sure deletes next to group char always | ||||||
|         # delete next digit to appropriate side: |         # delete next digit to appropriate side: | ||||||
| @@ -1086,21 +1089,21 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|                     self.SetSelection(sel_start, sel_to+1) |                     self.SetSelection(sel_start, sel_to+1) | ||||||
| 
 | 
 | ||||||
|         BaseMaskedTextCtrl._OnErase(self, event) |         BaseMaskedTextCtrl._OnErase(self, event) | ||||||
|         dbg(indent=0) | ##        dbg(indent=0) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def OnTextChange( self, event ): |     def OnTextChange( self, event ): | ||||||
|         """ |         """ | ||||||
|         Handles an event indicating that the text control's value |         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 |         NOTE: using wxTextCtrl.SetValue() to change the control's | ||||||
|         contents from within a EVT_CHAR handler can cause double |         contents from within a EVT_CHAR handler can cause double | ||||||
|         text events.  So we check for actual changes to the text |         text events.  So we check for actual changes to the text | ||||||
|         before passing the events on. |         before passing the events on. | ||||||
|         """ |         """ | ||||||
|         dbg('MaskedNumCtrl::OnTextChange', indent=1) | ##        dbg('NumCtrl::OnTextChange', indent=1) | ||||||
|         if not BaseMaskedTextCtrl._OnTextChange(self, event): |         if not BaseMaskedTextCtrl._OnTextChange(self, event): | ||||||
|             dbg(indent=0) | ##            dbg(indent=0) | ||||||
|             return |             return | ||||||
| 
 | 
 | ||||||
|         # else... legal value |         # else... legal value | ||||||
| @@ -1109,14 +1112,14 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|         if value != self._oldvalue: |         if value != self._oldvalue: | ||||||
|             try: |             try: | ||||||
|                 self.GetEventHandler().ProcessEvent( |                 self.GetEventHandler().ProcessEvent( | ||||||
|                     MaskedNumNumberUpdatedEvent( self.GetId(), self.GetValue(), self ) ) |                     NumberUpdatedEvent( self.GetId(), self.GetValue(), self ) ) | ||||||
|             except ValueError: |             except ValueError: | ||||||
|                 dbg(indent=0) | ##                dbg(indent=0) | ||||||
|                 return |                 return | ||||||
|             # let normal processing of the text continue |             # let normal processing of the text continue | ||||||
|             event.Skip() |             event.Skip() | ||||||
|         self._oldvalue = value # record for next event |         self._oldvalue = value # record for next event | ||||||
|         dbg(indent=0) | ##        dbg(indent=0) | ||||||
| 
 | 
 | ||||||
|     def _GetValue(self): |     def _GetValue(self): | ||||||
|         """ |         """ | ||||||
| @@ -1172,7 +1175,7 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|         If min > the max value allowed by the width of the control, |         If min > the max value allowed by the width of the control, | ||||||
|         the function will return False, and the min will not be set. |         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 |         if( self._max is None | ||||||
|             or min is None |             or min is None | ||||||
|             or (self._max is not None and self._max >= min) ): |             or (self._max is not None and self._max >= min) ): | ||||||
| @@ -1183,7 +1186,7 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|                 bRet = False |                 bRet = False | ||||||
|         else: |         else: | ||||||
|             bRet = False |             bRet = False | ||||||
|         dbg(indent=0) | ##        dbg(indent=0) | ||||||
|         return bRet |         return bRet | ||||||
| 
 | 
 | ||||||
|     def GetMin(self): |     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 |         also be called with a value to see if that value would fall within | ||||||
|         the current bounds of the given control. |         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: |         if value is None: | ||||||
|             value = self.GetValue() |             value = self.GetValue() | ||||||
|         else: |         else: | ||||||
|             try: |             try: | ||||||
|                 value = self._GetNumValue(self._toGUI(value)) |                 value = self._GetNumValue(self._toGUI(value)) | ||||||
|             except ValueError, e: |             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 |                 return False | ||||||
|             if value.strip() == '': |             if value.strip() == '': | ||||||
|                 value = None |                 value = None | ||||||
| @@ -1309,10 +1312,10 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
| 
 | 
 | ||||||
|         # if bounds set, and value is None, return False |         # if bounds set, and value is None, return False | ||||||
|         if value == None and (min is not None or max is not None): |         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 |             return 0 | ||||||
|         else: |         else: | ||||||
|             dbg('finished IsInBounds', indent=0) | ##            dbg('finished IsInBounds', indent=0) | ||||||
|             return min <= value <= max |             return min <= value <= max | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @@ -1383,21 +1386,21 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|         type and bounds checking and raises ValueError if argument is |         type and bounds checking and raises ValueError if argument is | ||||||
|         not a valid value. |         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(): |         if value is None and self.IsNoneAllowed(): | ||||||
|             dbg(indent=0) | ##            dbg(indent=0) | ||||||
|             return self._template |             return self._template | ||||||
| 
 | 
 | ||||||
|         elif type(value) in (types.StringType, types.UnicodeType): |         elif type(value) in (types.StringType, types.UnicodeType): | ||||||
|             value = self._GetNumValue(value) |             value = self._GetNumValue(value) | ||||||
|             dbg('cleansed num value: "%s"' % value) | ##            dbg('cleansed num value: "%s"' % value) | ||||||
|             if value == "": |             if value == "": | ||||||
|                 if self.IsNoneAllowed(): |                 if self.IsNoneAllowed(): | ||||||
|                     dbg(indent=0) | ##                    dbg(indent=0) | ||||||
|                     return self._template |                     return self._template | ||||||
|                 else: |                 else: | ||||||
|                     dbg('exception raised:', e, indent=0) | ##                    dbg('exception raised:', e, indent=0) | ||||||
|                     raise ValueError ('wxMaskedNumCtrl requires numeric value, passed %s'% repr(value) ) |                     raise ValueError ('NumCtrl requires numeric value, passed %s'% repr(value) ) | ||||||
|             # else... |             # else... | ||||||
|             try: |             try: | ||||||
|                 if self._fractionWidth or value.find('.') != -1: |                 if self._fractionWidth or value.find('.') != -1: | ||||||
| @@ -1405,13 +1408,13 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|                 else: |                 else: | ||||||
|                     value = long(value) |                     value = long(value) | ||||||
|             except Exception, e: |             except Exception, e: | ||||||
|                 dbg('exception raised:', e, indent=0) | ##                dbg('exception raised:', e, indent=0) | ||||||
|                 raise ValueError ('MaskedNumCtrl requires numeric value, passed %s'% repr(value) ) |                 raise ValueError ('NumCtrl requires numeric value, passed %s'% repr(value) ) | ||||||
| 
 | 
 | ||||||
|         elif type(value) not in (types.IntType, types.LongType, types.FloatType): |         elif type(value) not in (types.IntType, types.LongType, types.FloatType): | ||||||
|             dbg(indent=0) | ##            dbg(indent=0) | ||||||
|             raise ValueError ( |             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: |         if not self._allowNegative and value < 0: | ||||||
|             raise ValueError ( |             raise ValueError ( | ||||||
| @@ -1421,29 +1424,29 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|             min = self.GetMin() |             min = self.GetMin() | ||||||
|             max = self.GetMax() |             max = self.GetMax() | ||||||
|             if not min is None and value < min: |             if not min is None and value < min: | ||||||
|                 dbg(indent=0) | ##                dbg(indent=0) | ||||||
|                 raise ValueError ( |                 raise ValueError ( | ||||||
|                     'value %d is below minimum value of control'% value ) |                     'value %d is below minimum value of control'% value ) | ||||||
|             if not max is None and value > max: |             if not max is None and value > max: | ||||||
|                 dbg(indent=0) | ##                dbg(indent=0) | ||||||
|                 raise ValueError ( |                 raise ValueError ( | ||||||
|                     'value %d exceeds value of control'% value ) |                     'value %d exceeds value of control'% value ) | ||||||
| 
 | 
 | ||||||
|         adjustwidth = len(self._mask) - (1 * self._useParens * self._signOk) |         adjustwidth = len(self._mask) - (1 * self._useParens * self._signOk) | ||||||
|         dbg('len(%s):' % self._mask, len(self._mask)) | ##        dbg('len(%s):' % self._mask, len(self._mask)) | ||||||
|         dbg('adjustwidth - groupSpace:', adjustwidth - self._groupSpace) | ##        dbg('adjustwidth - groupSpace:', adjustwidth - self._groupSpace) | ||||||
|         dbg('adjustwidth:', adjustwidth) | ##        dbg('adjustwidth:', adjustwidth) | ||||||
|         if self._fractionWidth == 0: |         if self._fractionWidth == 0: | ||||||
|             s = str(long(value)).rjust(self._integerWidth) |             s = str(long(value)).rjust(self._integerWidth) | ||||||
|         else: |         else: | ||||||
|             format = '%' + '%d.%df' % (self._integerWidth+self._fractionWidth+1, self._fractionWidth) |             format = '%' + '%d.%df' % (self._integerWidth+self._fractionWidth+1, self._fractionWidth) | ||||||
|             s = format % float(value) |             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): |         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)) |             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): |         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)) |             raise ValueError ('value %s exceeds the integer width of the control (%d)' % (s, self._integerWidth)) | ||||||
| 
 | 
 | ||||||
|         s = s.rjust(adjustwidth).replace('.', self._decimalChar) |         s = s.rjust(adjustwidth).replace('.', self._decimalChar) | ||||||
| @@ -1452,7 +1455,7 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|                 s = s.replace('-', '(') + ')' |                 s = s.replace('-', '(') + ')' | ||||||
|             else: |             else: | ||||||
|                 s += ' ' |                 s += ' ' | ||||||
|         dbg('returned: "%s"' % s, indent=0) | ##        dbg('returned: "%s"' % s, indent=0) | ||||||
|         return s |         return s | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @@ -1460,8 +1463,8 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|         """ |         """ | ||||||
|         Conversion function used in getting the value of the control. |         Conversion function used in getting the value of the control. | ||||||
|         """ |         """ | ||||||
|         dbg(suspend=0) | ##        dbg(suspend=0) | ||||||
|         dbg('MaskedNumCtrl::_fromGUI(%s)' % value, indent=1) | ##        dbg('NumCtrl::_fromGUI(%s)' % value, indent=1) | ||||||
|         # One or more of the underlying text control implementations |         # One or more of the underlying text control implementations | ||||||
|         # issue an intermediate EVT_TEXT when replacing the control's |         # issue an intermediate EVT_TEXT when replacing the control's | ||||||
|         # value, where the intermediate value is an empty string. |         # value, where the intermediate value is an empty string. | ||||||
| @@ -1470,42 +1473,42 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|         # |         # | ||||||
|         if value.strip() == '': |         if value.strip() == '': | ||||||
|             if not self.IsNoneAllowed(): |             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: |                 if self._fractionWidth: | ||||||
|                     return 0.0 |                     return 0.0 | ||||||
|                 else: |                 else: | ||||||
|                     return 0 |                     return 0 | ||||||
|             else: |             else: | ||||||
|                 dbg('empty value; returning None', indent = 0) | ##                dbg('empty value; returning None', indent = 0) | ||||||
|                 return None |                 return None | ||||||
|         else: |         else: | ||||||
|             value = self._GetNumValue(value) |             value = self._GetNumValue(value) | ||||||
|             dbg('Num value: "%s"' % value) | ##            dbg('Num value: "%s"' % value) | ||||||
|             if self._fractionWidth: |             if self._fractionWidth: | ||||||
|                 try: |                 try: | ||||||
|                     dbg(indent=0) | ##                    dbg(indent=0) | ||||||
|                     return float( value ) |                     return float( value ) | ||||||
|                 except ValueError: |                 except ValueError: | ||||||
|                     dbg("couldn't convert to float; returning None") | ##                    dbg("couldn't convert to float; returning None") | ||||||
|                     return None |                     return None | ||||||
|                 else: |                 else: | ||||||
|                     raise |                     raise | ||||||
|             else: |             else: | ||||||
|                 try: |                 try: | ||||||
|                     dbg(indent=0) | ##                    dbg(indent=0) | ||||||
|                     return int( value ) |                     return int( value ) | ||||||
|                 except ValueError: |                 except ValueError: | ||||||
|                     try: |                     try: | ||||||
|                        dbg(indent=0) | ##                       dbg(indent=0) | ||||||
|                        return long( value ) |                        return long( value ) | ||||||
|                     except ValueError: |                     except ValueError: | ||||||
|                        dbg("couldn't convert to long; returning None") | ##                       dbg("couldn't convert to long; returning None") | ||||||
|                        return None |                        return None | ||||||
| 
 | 
 | ||||||
|                     else: |                     else: | ||||||
|                        raise |                        raise | ||||||
|                 else: |                 else: | ||||||
|                     dbg('exception occurred; returning None') | ##                    dbg('exception occurred; returning None') | ||||||
|                     return None |                     return None | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @@ -1514,7 +1517,7 @@ class MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin): | |||||||
|         Preprocessor for base control paste; if value needs to be right-justified |         Preprocessor for base control paste; if value needs to be right-justified | ||||||
|         to fit in control, do so prior to paste: |         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: |         if value is None: | ||||||
|             paste_text = self._getClipboardContents() |             paste_text = self._getClipboardContents() | ||||||
|         else: |         else: | ||||||
| @@ -1545,7 +1548,7 @@ if __name__ == '__main__': | |||||||
|             style = wx.DEFAULT_DIALOG_STYLE ): |             style = wx.DEFAULT_DIALOG_STYLE ): | ||||||
|             wx.Dialog.__init__(self, parent, id, title, pos, size, 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.OK = wx.Button( self, wx.ID_OK, "OK") | ||||||
|             self.Cancel = wx.Button( self, wx.ID_CANCEL, "Cancel") |             self.Cancel = wx.Button( self, wx.ID_CANCEL, "Cancel") | ||||||
| 
 | 
 | ||||||
| @@ -1560,7 +1563,7 @@ if __name__ == '__main__': | |||||||
|             self.SetSizer( vs ) |             self.SetSizer( vs ) | ||||||
|             vs.Fit( self ) |             vs.Fit( self ) | ||||||
|             vs.SetSizeHints( 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): |         def OnChange(self, event): | ||||||
|             print 'value now', event.GetValue() |             print 'value now', event.GetValue() | ||||||
| @@ -1578,7 +1581,7 @@ if __name__ == '__main__': | |||||||
|             return True |             return True | ||||||
| 
 | 
 | ||||||
|         def OnClick(self, event): |         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.SetValue(501) | ||||||
|             dlg.int_ctrl.SetInsertionPoint(1) |             dlg.int_ctrl.SetInsertionPoint(1) | ||||||
|             dlg.int_ctrl.SetSelection(1,2) |             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) | # 12/20/2003 - Jeff Grimmett (grimmtooth@softhome.net) | ||||||
| # | # | ||||||
| # o wxMaskedTextCtrl -> MaskedTextCtrl | # o wxMaskedTextCtrl -> masked.TextCtrl | ||||||
| # o wxTimeCtrl -> TimeCtrl | # o wxTimeCtrl -> masked.TimeCtrl | ||||||
| # | # | ||||||
| 
 | 
 | ||||||
| """<html><body> | """<html><body> | ||||||
| @@ -272,10 +272,10 @@ import  types | |||||||
| import  wx | import  wx | ||||||
| 
 | 
 | ||||||
| from wx.tools.dbg import Logger | from wx.tools.dbg import Logger | ||||||
| from wx.lib.maskededit import BaseMaskedTextCtrl, Field | from wx.lib.masked import Field, BaseMaskedTextCtrl | ||||||
| 
 | 
 | ||||||
| dbg = Logger() | dbg = Logger() | ||||||
| dbg(enable=0) | ##dbg(enable=0) | ||||||
| 
 | 
 | ||||||
| try: | try: | ||||||
|     from mx import DateTime |     from mx import DateTime | ||||||
| @@ -333,7 +333,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|         'max': None, |         'max': None, | ||||||
|         'limited': False,           # by default, no limiting even if bounds set |         'limited': False,           # by default, no limiting even if bounds set | ||||||
|         'useFixedWidthFont': True,  # by default, use a fixed-width font |         '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__ ( |     def __init__ ( | ||||||
| @@ -347,7 +347,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|                 **kwargs ): |                 **kwargs ): | ||||||
| 
 | 
 | ||||||
|         # set defaults for control: |         # set defaults for control: | ||||||
|         dbg('setting defaults:') | ##        dbg('setting defaults:') | ||||||
|         for key, param_value in TimeCtrl.valid_ctrl_params.items(): |         for key, param_value in TimeCtrl.valid_ctrl_params.items(): | ||||||
|             # This is done this way to make setattr behave consistently with |             # This is done this way to make setattr behave consistently with | ||||||
|             # "private attribute" name mangling |             # "private attribute" name mangling | ||||||
| @@ -456,7 +456,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def SetParameters(self, **kwargs): |     def SetParameters(self, **kwargs): | ||||||
|         dbg('TimeCtrl::SetParameters(%s)' % repr(kwargs), indent=1) | ##        dbg('TimeCtrl::SetParameters(%s)' % repr(kwargs), indent=1) | ||||||
|         maskededit_kwargs = {} |         maskededit_kwargs = {} | ||||||
|         reset_format = False |         reset_format = False | ||||||
| 
 | 
 | ||||||
| @@ -553,10 +553,10 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|                 self.SetValue(value) |                 self.SetValue(value) | ||||||
|             except: |             except: | ||||||
|                 self.SetValue('12:00:00 AM') |                 self.SetValue('12:00:00 AM') | ||||||
|             dbg(indent=0) | ##            dbg(indent=0) | ||||||
|             return {}   # no arguments to return |             return {}   # no arguments to return | ||||||
|         else: |         else: | ||||||
|             dbg(indent=0) | ##            dbg(indent=0) | ||||||
|             return maskededit_kwargs |             return maskededit_kwargs | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @@ -565,7 +565,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|         This function binds an externally created spin button to the control, so that |         This function binds an externally created spin button to the control, so that | ||||||
|         up/down events from the button automatically change the control. |         up/down events from the button automatically change the control. | ||||||
|         """ |         """ | ||||||
|         dbg('TimeCtrl::BindSpinButton') | ##        dbg('TimeCtrl::BindSpinButton') | ||||||
|         self.__spinButton = sb |         self.__spinButton = sb | ||||||
|         if self.__spinButton: |         if self.__spinButton: | ||||||
|             # bind event handlers to spin ctrl |             # bind event handlers to spin ctrl | ||||||
| @@ -584,16 +584,16 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|         and convert wxDateTime, mxDateTime, or 12/24 format time string |         and convert wxDateTime, mxDateTime, or 12/24 format time string | ||||||
|         into the appropriate format string for the control. |         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: |         try: | ||||||
|             strtime = self._toGUI(self.__validateValue(value)) |             strtime = self._toGUI(self.__validateValue(value)) | ||||||
|         except: |         except: | ||||||
|             dbg('validation failed', indent=0) | ##            dbg('validation failed', indent=0) | ||||||
|             raise |             raise | ||||||
| 
 | 
 | ||||||
|         dbg('strtime:', strtime) | ##        dbg('strtime:', strtime) | ||||||
|         self._SetValue(strtime) |         self._SetValue(strtime) | ||||||
|         dbg(indent=0) | ##        dbg(indent=0) | ||||||
| 
 | 
 | ||||||
|     def GetValue(self, |     def GetValue(self, | ||||||
|                  as_wxDateTime = False, |                  as_wxDateTime = False, | ||||||
| @@ -641,12 +641,12 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|         raised. |         raised. | ||||||
|         """ |         """ | ||||||
|         global accept_mx |         global accept_mx | ||||||
|         dbg(suspend=1) | ##        dbg(suspend=1) | ||||||
|         dbg('TimeCtrl::GetWxDateTime(%s)' % repr(value), indent=1) | ##        dbg('TimeCtrl::GetWxDateTime(%s)' % repr(value), indent=1) | ||||||
|         if value is None: |         if value is None: | ||||||
|             dbg('getting control value') | ##            dbg('getting control value') | ||||||
|             value = self.GetValue() |             value = self.GetValue() | ||||||
|             dbg('value = "%s"' % value) | ##            dbg('value = "%s"' % value) | ||||||
| 
 | 
 | ||||||
|         if type(value) == types.UnicodeType: |         if type(value) == types.UnicodeType: | ||||||
|             value = str(value)  # convert to regular string |             value = str(value)  # convert to regular string | ||||||
| @@ -656,14 +656,14 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
| 
 | 
 | ||||||
|             # Construct constant wxDateTime, then try to parse the string: |             # Construct constant wxDateTime, then try to parse the string: | ||||||
|             wxdt = wx.DateTimeFromDMY(1, 0, 1970) |             wxdt = wx.DateTimeFromDMY(1, 0, 1970) | ||||||
|             dbg('attempting conversion') | ##            dbg('attempting conversion') | ||||||
|             value = value.strip()    # (parser doesn't like leading spaces) |             value = value.strip()    # (parser doesn't like leading spaces) | ||||||
|             checkTime    = wxdt.ParseTime(value) |             checkTime    = wxdt.ParseTime(value) | ||||||
|             valid = checkTime == len(value)     # entire string parsed? |             valid = checkTime == len(value)     # entire string parsed? | ||||||
|             dbg('checkTime == len(value)?', valid) | ##            dbg('checkTime == len(value)?', valid) | ||||||
| 
 | 
 | ||||||
|             if not valid: |             if not valid: | ||||||
|                 dbg(indent=0, suspend=0) | ##                dbg(indent=0, suspend=0) | ||||||
|                 raise ValueError('cannot convert string "%s" to valid time' % value) |                 raise ValueError('cannot convert string "%s" to valid time' % value) | ||||||
| 
 | 
 | ||||||
|         else: |         else: | ||||||
| @@ -685,7 +685,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|                     error = 'GetWxDateTime requires wxDateTime, mxDateTime or parsable time string, passed %s'% repr(value) |                     error = 'GetWxDateTime requires wxDateTime, mxDateTime or parsable time string, passed %s'% repr(value) | ||||||
|                 else: |                 else: | ||||||
|                     error = 'GetWxDateTime requires wxDateTime or parsable time string, passed %s'% repr(value) |                     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) |                 raise ValueError(error) | ||||||
| 
 | 
 | ||||||
|             wxdt = wx.DateTimeFromDMY(1, 0, 1970) |             wxdt = wx.DateTimeFromDMY(1, 0, 1970) | ||||||
| @@ -693,7 +693,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|             wxdt.SetMinute(minute) |             wxdt.SetMinute(minute) | ||||||
|             wxdt.SetSecond(second) |             wxdt.SetSecond(second) | ||||||
| 
 | 
 | ||||||
|         dbg('wxdt:', wxdt, indent=0, suspend=0) | ##        dbg('wxdt:', wxdt, indent=0, suspend=0) | ||||||
|         return wxdt |         return wxdt | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @@ -730,13 +730,13 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|         adjusted to the new minimum value; if not limited, the value in the |         adjusted to the new minimum value; if not limited, the value in the | ||||||
|         control will be colored as invalid. |         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: |         if min is not None: | ||||||
|             try: |             try: | ||||||
|                 min = self.GetWxDateTime(min) |                 min = self.GetWxDateTime(min) | ||||||
|                 self.__min = self._toGUI(min) |                 self.__min = self._toGUI(min) | ||||||
|             except: |             except: | ||||||
|                 dbg('exception occurred', indent=0) | ##                dbg('exception occurred', indent=0) | ||||||
|                 return False |                 return False | ||||||
|         else: |         else: | ||||||
|             self.__min = min |             self.__min = min | ||||||
| @@ -746,7 +746,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|         else: |         else: | ||||||
|             self._CheckValid() |             self._CheckValid() | ||||||
|         ret = True |         ret = True | ||||||
|         dbg('ret:', ret, indent=0) | ##        dbg('ret:', ret, indent=0) | ||||||
|         return ret |         return ret | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @@ -757,22 +757,23 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|         the current minimum bound on the control, as a wxDateTime |         the current minimum bound on the control, as a wxDateTime | ||||||
|         by default, or as a string if as_string argument is True. |         by default, or as a string if as_string argument is True. | ||||||
|         """ |         """ | ||||||
|         dbg(suspend=1) | ##        dbg(suspend=1) | ||||||
|         dbg('TimeCtrl::GetMin, as_string?', as_string, indent=1) | ##        dbg('TimeCtrl::GetMin, as_string?', as_string, indent=1) | ||||||
|         if self.__min is None: |         if self.__min is None: | ||||||
|             dbg('(min == None)') | ##            dbg('(min == None)') | ||||||
|             ret = self.__min |             ret = self.__min | ||||||
|         elif as_string: |         elif as_string: | ||||||
|             ret = self.__min |             ret = self.__min | ||||||
|             dbg('ret:', ret) | ##            dbg('ret:', ret) | ||||||
|         else: |         else: | ||||||
|             try: |             try: | ||||||
|                 ret = self.GetWxDateTime(self.__min) |                 ret = self.GetWxDateTime(self.__min) | ||||||
|             except: |             except: | ||||||
|                 dbg(suspend=0) | ##                dbg(suspend=0) | ||||||
|                 dbg('exception occurred', indent=0) | ##                dbg('exception occurred', indent=0) | ||||||
|             dbg('ret:', repr(ret)) |                 raise | ||||||
|         dbg(indent=0, suspend=0) | ##            dbg('ret:', repr(ret)) | ||||||
|  | ##        dbg(indent=0, suspend=0) | ||||||
|         return ret |         return ret | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @@ -789,23 +790,23 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|         adjusted to this maximum value; if not limited, the value in the |         adjusted to this maximum value; if not limited, the value in the | ||||||
|         control will be colored as invalid. |         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: |         if max is not None: | ||||||
|             try: |             try: | ||||||
|                 max = self.GetWxDateTime(max) |                 max = self.GetWxDateTime(max) | ||||||
|                 self.__max = self._toGUI(max) |                 self.__max = self._toGUI(max) | ||||||
|             except: |             except: | ||||||
|                 dbg('exception occurred', indent=0) | ##                dbg('exception occurred', indent=0) | ||||||
|                 return False |                 return False | ||||||
|         else: |         else: | ||||||
|             self.__max = max |             self.__max = max | ||||||
|         dbg('max:', repr(self.__max)) | ##        dbg('max:', repr(self.__max)) | ||||||
|         if self.IsLimited() and not self.IsInBounds(): |         if self.IsLimited() and not self.IsInBounds(): | ||||||
|             self.SetLimited(self.__limited) # force limited value: |             self.SetLimited(self.__limited) # force limited value: | ||||||
|         else: |         else: | ||||||
|             self._CheckValid() |             self._CheckValid() | ||||||
|         ret = True |         ret = True | ||||||
|         dbg('ret:', ret, indent=0) | ##        dbg('ret:', ret, indent=0) | ||||||
|         return ret |         return ret | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @@ -816,23 +817,23 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|         the current minimum bound on the control, as a wxDateTime |         the current minimum bound on the control, as a wxDateTime | ||||||
|         by default, or as a string if as_string argument is True. |         by default, or as a string if as_string argument is True. | ||||||
|         """ |         """ | ||||||
|         dbg(suspend=1) | ##        dbg(suspend=1) | ||||||
|         dbg('TimeCtrl::GetMin, as_string?', as_string, indent=1) | ##        dbg('TimeCtrl::GetMin, as_string?', as_string, indent=1) | ||||||
|         if self.__max is None: |         if self.__max is None: | ||||||
|             dbg('(max == None)') | ##            dbg('(max == None)') | ||||||
|             ret = self.__max |             ret = self.__max | ||||||
|         elif as_string: |         elif as_string: | ||||||
|             ret = self.__max |             ret = self.__max | ||||||
|             dbg('ret:', ret) | ##            dbg('ret:', ret) | ||||||
|         else: |         else: | ||||||
|             try: |             try: | ||||||
|                 ret = self.GetWxDateTime(self.__max) |                 ret = self.GetWxDateTime(self.__max) | ||||||
|             except: |             except: | ||||||
|                 dbg(suspend=0) | ##                dbg(suspend=0) | ||||||
|                 dbg('exception occurred', indent=0) | ##                dbg('exception occurred', indent=0) | ||||||
|                 raise |                 raise | ||||||
|             dbg('ret:', repr(ret)) | ##            dbg('ret:', repr(ret)) | ||||||
|         dbg(indent=0, suspend=0) | ##        dbg(indent=0, suspend=0) | ||||||
|         return ret |         return ret | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @@ -868,22 +869,22 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|         limiting, but coloring of out-of-bounds values will still take |         limiting, but coloring of out-of-bounds values will still take | ||||||
|         place if bounds have been set for the control. |         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 |         self.__limited = limited | ||||||
| 
 | 
 | ||||||
|         if not limited: |         if not limited: | ||||||
|             self.SetMaskParameters(validRequired = False) |             self.SetMaskParameters(validRequired = False) | ||||||
|             self._CheckValid() |             self._CheckValid() | ||||||
|             dbg(indent=0) | ##            dbg(indent=0) | ||||||
|             return |             return | ||||||
| 
 | 
 | ||||||
|         dbg('requiring valid value') | ##        dbg('requiring valid value') | ||||||
|         self.SetMaskParameters(validRequired = True) |         self.SetMaskParameters(validRequired = True) | ||||||
| 
 | 
 | ||||||
|         min = self.GetMin() |         min = self.GetMin() | ||||||
|         max = self.GetMax() |         max = self.GetMax() | ||||||
|         if min is None or max is None: |         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 |             return  # can't limit without 2 bounds | ||||||
| 
 | 
 | ||||||
|         elif not self.IsInBounds(): |         elif not self.IsInBounds(): | ||||||
| @@ -891,11 +892,11 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|             try: |             try: | ||||||
|                 value = self.GetWxDateTime() |                 value = self.GetWxDateTime() | ||||||
|             except: |             except: | ||||||
|                 dbg('exception occurred', indent=0) | ##                dbg('exception occurred', indent=0) | ||||||
|                 raise |                 raise | ||||||
| 
 | 
 | ||||||
|             if min <= max:   # valid range doesn't span midnight |             if min <= max:   # valid range doesn't span midnight | ||||||
|                 dbg('min <= max') | ##                dbg('min <= max') | ||||||
|                 # which makes the "nearest bound" computation trickier... |                 # which makes the "nearest bound" computation trickier... | ||||||
| 
 | 
 | ||||||
|                 # determine how long the "invalid" pie wedge is, and cut |                 # determine how long the "invalid" pie wedge is, and cut | ||||||
| @@ -918,24 +919,24 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|                     cmp_value = value |                     cmp_value = value | ||||||
| 
 | 
 | ||||||
|                 if (cmp_value - max) > half_interval: |                 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) |                     self.SetValue(min) | ||||||
|                 else: |                 else: | ||||||
|                     dbg('forcing value to max (%s)' % max.FormatTime()) | ##                    dbg('forcing value to max (%s)' % max.FormatTime()) | ||||||
|                     self.SetValue(max) |                     self.SetValue(max) | ||||||
|             else: |             else: | ||||||
|                 dbg('max < min') | ##                dbg('max < min') | ||||||
|                 # therefore  max < value < min guaranteed to be true, |                 # therefore  max < value < min guaranteed to be true, | ||||||
|                 # so "nearest bound" calculation is much easier: |                 # so "nearest bound" calculation is much easier: | ||||||
|                 if (value - max) >= (min - value): |                 if (value - max) >= (min - value): | ||||||
|                     # current value closer to min; pick that edge of pie wedge |                     # 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) |                     self.SetValue(min) | ||||||
|                 else: |                 else: | ||||||
|                     dbg('forcing value to max (%s)' % max.FormatTime()) | ##                    dbg('forcing value to max (%s)' % max.FormatTime()) | ||||||
|                     self.SetValue(max) |                     self.SetValue(max) | ||||||
| 
 | 
 | ||||||
|         dbg(indent=0) | ##        dbg(indent=0) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @@ -961,21 +962,22 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|             try: |             try: | ||||||
|                 value = self.GetWxDateTime(value)   # try to regularize passed value |                 value = self.GetWxDateTime(value)   # try to regularize passed value | ||||||
|             except ValueError: |             except ValueError: | ||||||
|                 dbg('ValueError getting wxDateTime for %s' % repr(value), indent=0) | ##                dbg('ValueError getting wxDateTime for %s' % repr(value), indent=0) | ||||||
|                 raise |                 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: |         if self.__min is None or self.__max is None: | ||||||
|             dbg(indent=0) | ##            dbg(indent=0) | ||||||
|             return True |             return True | ||||||
| 
 | 
 | ||||||
|         elif value is None: |         elif value is None: | ||||||
|             try: |             try: | ||||||
|                 value = self.GetWxDateTime() |                 value = self.GetWxDateTime() | ||||||
|             except: |             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: |         # Get wxDateTime representations of bounds: | ||||||
|         min = self.GetMin() |         min = self.GetMin() | ||||||
| @@ -990,7 +992,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|             # either "min" <= value (<= midnight of *next day*) |             # either "min" <= value (<= midnight of *next day*) | ||||||
|             # or midnight <= value <= "max" |             # or midnight <= value <= "max" | ||||||
|             ret = min <= value 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 |         return ret | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @@ -1021,7 +1023,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def __OnTextChange(self, event=None): |     def __OnTextChange(self, event=None): | ||||||
|         dbg('TimeCtrl::OnTextChange', indent=1) | ##        dbg('TimeCtrl::OnTextChange', indent=1) | ||||||
| 
 | 
 | ||||||
|         # Allow Maskedtext base control to color as appropriate, |         # Allow Maskedtext base control to color as appropriate, | ||||||
|         # and Skip the EVT_TEXT event (if appropriate.) |         # and Skip the EVT_TEXT event (if appropriate.) | ||||||
| @@ -1035,11 +1037,11 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|         if not BaseMaskedTextCtrl._OnTextChange(self, event): |         if not BaseMaskedTextCtrl._OnTextChange(self, event): | ||||||
|             return |             return | ||||||
| 
 | 
 | ||||||
|         dbg('firing TimeUpdatedEvent...') | ##        dbg('firing TimeUpdatedEvent...') | ||||||
|         evt = TimeUpdatedEvent(self.GetId(), self.GetValue()) |         evt = TimeUpdatedEvent(self.GetId(), self.GetValue()) | ||||||
|         evt.SetEventObject(self) |         evt.SetEventObject(self) | ||||||
|         self.GetEventHandler().ProcessEvent(evt) |         self.GetEventHandler().ProcessEvent(evt) | ||||||
|         dbg(indent=0) | ##        dbg(indent=0) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def SetInsertionPoint(self, pos): |     def SetInsertionPoint(self, pos): | ||||||
| @@ -1048,14 +1050,14 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|         This is necessary to handle the optional spin button, because the insertion |         This is necessary to handle the optional spin button, because the insertion | ||||||
|         point is lost when the focus shifts to the spin button. |         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) |         BaseMaskedTextCtrl.SetInsertionPoint(self, pos)                 # (causes EVT_TEXT event to fire) | ||||||
|         self.__posCurrent = self.GetInsertionPoint() |         self.__posCurrent = self.GetInsertionPoint() | ||||||
|         dbg(indent=0) | ##        dbg(indent=0) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def SetSelection(self, sel_start, sel_to): |     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 |         # Adjust selection range to legal extent if not already | ||||||
|         if sel_start < 0: |         if sel_start < 0: | ||||||
| @@ -1069,7 +1071,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
| 
 | 
 | ||||||
|         self.__bSelection = sel_start != sel_to |         self.__bSelection = sel_start != sel_to | ||||||
|         BaseMaskedTextCtrl.SetSelection(self, sel_start, sel_to) |         BaseMaskedTextCtrl.SetSelection(self, sel_start, sel_to) | ||||||
|         dbg(indent=0) | ##        dbg(indent=0) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def __OnSpin(self, key): |     def __OnSpin(self, key): | ||||||
| @@ -1085,7 +1087,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|         start, end = self._FindField(self.__posCurrent)._extent |         start, end = self._FindField(self.__posCurrent)._extent | ||||||
|         self.SetInsertionPoint(start) |         self.SetInsertionPoint(start) | ||||||
|         self.SetSelection(start, end) |         self.SetSelection(start, end) | ||||||
|         dbg('current position:', self.__posCurrent) | ##        dbg('current position:', self.__posCurrent) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def __OnSpinUp(self, event): |     def __OnSpinUp(self, event): | ||||||
| @@ -1093,10 +1095,10 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|         Event handler for any bound spin button on EVT_SPIN_UP; |         Event handler for any bound spin button on EVT_SPIN_UP; | ||||||
|         causes control to behave as if up arrow was pressed. |         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) |         self.__OnSpin(wx.WXK_UP) | ||||||
|         keep_processing = False |         keep_processing = False | ||||||
|         dbg(indent=0) | ##        dbg(indent=0) | ||||||
|         return keep_processing |         return keep_processing | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @@ -1105,10 +1107,10 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|         Event handler for any bound spin button on EVT_SPIN_DOWN; |         Event handler for any bound spin button on EVT_SPIN_DOWN; | ||||||
|         causes control to behave as if down arrow was pressed. |         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) |         self.__OnSpin(wx.WXK_DOWN) | ||||||
|         keep_processing = False |         keep_processing = False | ||||||
|         dbg(indent=0) | ##        dbg(indent=0) | ||||||
|         return keep_processing |         return keep_processing | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @@ -1119,14 +1121,14 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|         It then calls the base control's _OnChar routine with the modified |         It then calls the base control's _OnChar routine with the modified | ||||||
|         event instance. |         event instance. | ||||||
|         """ |         """ | ||||||
|         dbg('TimeCtrl::OnChar', indent=1) | ##        dbg('TimeCtrl::OnChar', indent=1) | ||||||
|         keycode = event.GetKeyCode() |         keycode = event.GetKeyCode() | ||||||
|         dbg('keycode:', keycode) | ##        dbg('keycode:', keycode) | ||||||
|         if keycode == ord(':'): |         if keycode == ord(':'): | ||||||
|             dbg('colon seen! removing shift attribute') | ##            dbg('colon seen! removing shift attribute') | ||||||
|             event.m_shiftDown = False |             event.m_shiftDown = False | ||||||
|         BaseMaskedTextCtrl._OnChar(self, event )              ## handle each keypress |         BaseMaskedTextCtrl._OnChar(self, event )              ## handle each keypress | ||||||
|         dbg(indent=0) | ##        dbg(indent=0) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def __OnSetToNow(self, event): |     def __OnSetToNow(self, event): | ||||||
| @@ -1144,7 +1146,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|         Event handler for motion events; this handler |         Event handler for motion events; this handler | ||||||
|         changes limits the selection to the new cell boundaries. |         changes limits the selection to the new cell boundaries. | ||||||
|         """ |         """ | ||||||
|         dbg('TimeCtrl::LimitSelection', indent=1) | ##        dbg('TimeCtrl::LimitSelection', indent=1) | ||||||
|         pos = self.GetInsertionPoint() |         pos = self.GetInsertionPoint() | ||||||
|         self.__posCurrent = pos |         self.__posCurrent = pos | ||||||
|         sel_start, sel_to = self.GetSelection() |         sel_start, sel_to = self.GetSelection() | ||||||
| @@ -1155,18 +1157,18 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|             if sel_to < pos:   sel_to = start |             if sel_to < pos:   sel_to = start | ||||||
|             elif sel_to > pos: sel_to = end |             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.SetInsertionPoint(self.__posCurrent) | ||||||
|         self.SetSelection(self.__posCurrent, sel_to) |         self.SetSelection(self.__posCurrent, sel_to) | ||||||
|         if event: event.Skip() |         if event: event.Skip() | ||||||
|         dbg(indent=0) | ##        dbg(indent=0) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def __IncrementValue(self, key, pos): |     def __IncrementValue(self, key, pos): | ||||||
|         dbg('TimeCtrl::IncrementValue', key, pos, indent=1) | ##        dbg('TimeCtrl::IncrementValue', key, pos, indent=1) | ||||||
|         text = self.GetValue() |         text = self.GetValue() | ||||||
|         field = self._FindField(pos) |         field = self._FindField(pos) | ||||||
|         dbg('field: ', field._index) | ##        dbg('field: ', field._index) | ||||||
|         start, end = field._extent |         start, end = field._extent | ||||||
|         slice = text[start:end] |         slice = text[start:end] | ||||||
|         if key == wx.WXK_UP: increment = 1 |         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: |             # am/pm setting.  So, we use wxDateTime to generate a new value for us: | ||||||
|             # (Use a fixed date not subject to DST variations:) |             # (Use a fixed date not subject to DST variations:) | ||||||
|             converter = wx.DateTimeFromDMY(1, 0, 1970) |             converter = wx.DateTimeFromDMY(1, 0, 1970) | ||||||
|             dbg('text: "%s"' % text) | ##            dbg('text: "%s"' % text) | ||||||
|             converter.ParseTime(text.strip()) |             converter.ParseTime(text.strip()) | ||||||
|             currenthour = converter.GetHour() |             currenthour = converter.GetHour() | ||||||
|             dbg('current hour:', currenthour) | ##            dbg('current hour:', currenthour) | ||||||
|             newhour = (currenthour + increment) % 24 |             newhour = (currenthour + increment) % 24 | ||||||
|             dbg('newhour:', newhour) | ##            dbg('newhour:', newhour) | ||||||
|             converter.SetHour(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() |             newvalue = converter     # take advantage of auto-conversion for am/pm in .SetValue() | ||||||
| 
 | 
 | ||||||
|         else:   # minute or second field; handled the same way: |         else:   # minute or second field; handled the same way: | ||||||
| @@ -1202,7 +1204,7 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|         except ValueError:  # must not be in bounds: |         except ValueError:  # must not be in bounds: | ||||||
|             if not wx.Validator_IsSilent(): |             if not wx.Validator_IsSilent(): | ||||||
|                 wx.Bell() |                 wx.Bell() | ||||||
|         dbg(indent=0) | ##        dbg(indent=0) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     def _toGUI( self, wxdt ): |     def _toGUI( self, wxdt ): | ||||||
| @@ -1227,23 +1229,23 @@ class TimeCtrl(BaseMaskedTextCtrl): | |||||||
|         not a valid value for the control as currently specified. |         not a valid value for the control as currently specified. | ||||||
|         It is used by both the SetValue() and the IsValid() methods. |         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: |         if not value: | ||||||
|             dbg(indent=0) | ##            dbg(indent=0) | ||||||
|             raise ValueError('%s not a valid time value' % repr(value)) |             raise ValueError('%s not a valid time value' % repr(value)) | ||||||
| 
 | 
 | ||||||
|         valid = True    # assume true |         valid = True    # assume true | ||||||
|         try: |         try: | ||||||
|             value = self.GetWxDateTime(value)   # regularize form; can generate ValueError if problem doing so |             value = self.GetWxDateTime(value)   # regularize form; can generate ValueError if problem doing so | ||||||
|         except: |         except: | ||||||
|             dbg('exception occurred', indent=0) | ##            dbg('exception occurred', indent=0) | ||||||
|             raise |             raise | ||||||
| 
 | 
 | ||||||
|         if self.IsLimited() and not self.IsInBounds(value): |         if self.IsLimited() and not self.IsInBounds(value): | ||||||
|             dbg(indent=0) | ##            dbg(indent=0) | ||||||
|             raise ValueError ( |             raise ValueError ( | ||||||
|                 'value %s is not within the bounds of the control' % str(value) ) |                 'value %s is not within the bounds of the control' % str(value) ) | ||||||
|         dbg(indent=0) | ##        dbg(indent=0) | ||||||
|         return value |         return value | ||||||
| 
 | 
 | ||||||
| #---------------------------------------------------------------------------- | #---------------------------------------------------------------------------- | ||||||
| @@ -1278,12 +1280,12 @@ if __name__ == '__main__': | |||||||
|             self.Bind(EVT_TIMEUPDATE, self.OnTimeChange, self.tc) |             self.Bind(EVT_TIMEUPDATE, self.OnTimeChange, self.tc) | ||||||
| 
 | 
 | ||||||
|         def OnTimeChange(self, event): |         def OnTimeChange(self, event): | ||||||
|             dbg('OnTimeChange: value = ', event.GetValue()) | ##            dbg('OnTimeChange: value = ', event.GetValue()) | ||||||
|             wxdt = self.tc.GetWxDateTime() |             wxdt = self.tc.GetWxDateTime() | ||||||
|             dbg('wxdt =', wxdt.GetHour(), wxdt.GetMinute(), wxdt.GetSecond()) | ##            dbg('wxdt =', wxdt.GetHour(), wxdt.GetMinute(), wxdt.GetSecond()) | ||||||
|             if self.test_mx: |             if self.test_mx: | ||||||
|                 mxdt = self.tc.GetMxDateTime() |                 mxdt = self.tc.GetMxDateTime() | ||||||
|                 dbg('mxdt =', mxdt.hour, mxdt.minute, mxdt.second) | ##                dbg('mxdt =', mxdt.hour, mxdt.minute, mxdt.second) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     class MyApp(wx.App): |     class MyApp(wx.App): | ||||||
| @@ -2,9 +2,21 @@ | |||||||
| ## backwards compatibility.  Some names will also have a 'wx' added on if | ## 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. | ## 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 | MASKEDTEXT  = wx.lib.masked.ctrl.TEXT | ||||||
| wxMaskedCtrl = wx.lib.maskedctrl.MaskedCtrl | 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 | ## 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 | ## 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. | ## 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 | wxMaskedEditMixin = wx.lib.masked.MaskedEditMixin | ||||||
| test = wx.lib.maskededit.test | wxMaskedTextCtrl = wx.lib.masked.TextCtrl | ||||||
| test2 = wx.lib.maskededit.test2 | wxMaskedComboBox = wx.lib.masked.ComboBox | ||||||
| wxIpAddrCtrl = wx.lib.maskededit.IpAddrCtrl | wxMaskedComboBoxSelectEvent = wx.lib.masked.MaskedComboBoxSelectEvent | ||||||
| wxMaskedComboBox = wx.lib.maskededit.MaskedComboBox | wxIpAddrCtrl = wx.lib.masked.IpAddrCtrl | ||||||
| wxMaskedComboBoxSelectEvent = wx.lib.maskededit.MaskedComboBoxSelectEvent |  | ||||||
| wxMaskedEditMixin = wx.lib.maskededit.MaskedEditMixin |  | ||||||
| wxMaskedTextCtrl = wx.lib.maskededit.MaskedTextCtrl |  | ||||||
|   | |||||||
| @@ -2,10 +2,10 @@ | |||||||
| ## backwards compatibility.  Some names will also have a 'wx' added on if | ## 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. | ## 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 | EVT_MASKEDNUM = wx.lib.masked.numctrl.EVT_NUM | ||||||
| wxMaskedNumCtrl = wx.lib.maskednumctrl.MaskedNumCtrl | wxMaskedNumCtrl = wx.lib.masked.numctrl.NumCtrl | ||||||
| wxMaskedNumNumberUpdatedEvent = wx.lib.maskednumctrl.MaskedNumNumberUpdatedEvent | wxMaskedNumNumberUpdatedEvent = wx.lib.masked.numctrl.NumberUpdatedEvent | ||||||
|   | |||||||
| @@ -2,10 +2,10 @@ | |||||||
| ## backwards compatibility.  Some names will also have a 'wx' added on if | ## 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. | ## 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 | EVT_TIMEUPDATE = wx.lib.masked.timectrl.EVT_TIMEUPDATE | ||||||
| TimeUpdatedEvent = wx.lib.timectrl.TimeUpdatedEvent | TimeUpdatedEvent = wx.lib.masked.timectrl.TimeUpdatedEvent | ||||||
| wxTimeCtrl = wx.lib.timectrl.TimeCtrl | wxTimeCtrl = wx.lib.masked.timectrl.TimeCtrl | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user