]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/wx/lib/maskededit.py
typo
[wxWidgets.git] / wxPython / wx / lib / maskededit.py
index ec91ae53e1dc6cb177189a383ae60cd44fa5451d..bdc463543e5eb03557c3b5924e51a88b88c24c30 100644 (file)
@@ -3,41 +3,57 @@
 # Authors:      Jeff Childers, Will Sadkin
 # Email:        jchilders_98@yahoo.com, wsadkin@nameconnector.com
 # Created:      02/11/2003
-# Copyright:    (c) 2003 by Jeff Childers, 2003
+# Copyright:    (c) 2003 by Jeff Childers, Will Sadkin, 2003
 # Portions:     (c) 2002 by Will Sadkin, 2002-2003
 # RCS-ID:       $Id$
-# License:      wxWindows license
+# License:      wxWidgets license
 #----------------------------------------------------------------------------
 # NOTE:
-#   This was written way it is because of the lack of masked edit controls
-#   in wxWindows/wxPython.
-#
-#   wxMaskedEdit controls are based on a suggestion made on [wxPython-Users] by
+#   MaskedEdit controls are based on a suggestion made on [wxPython-Users] by
 #   Jason Hihn, and borrows liberally from Will Sadkin's original masked edit
-#   control for time entry, wxTimeCtrl (which is now rewritten using this
+#   control for time entry, TimeCtrl (which is now rewritten using this
 #   control!).
 #
-#   wxMaskedEdit controls do not normally use validators, because they do
+#   MaskedEdit controls do not normally use validators, because they do
 #   careful manipulation of the cursor in the text window on each keystroke,
 #   and validation is cursor-position specific, so the control intercepts the
 #   key codes before the validator would fire.  However, validators can be
 #   provided to do data transfer to the controls.
-##
+#
+#----------------------------------------------------------------------------
+#
+# 12/09/2003 - Jeff Grimmett (grimmtooth@softhome.net)
+#
+# o Updated for wx namespace. No guarantees. This is one huge file.
+# 
+# 12/13/2003 - Jeff Grimmett (grimmtooth@softhome.net)
+#
+# o Missed wx.DateTime stuff earlier.
+# 
+# 12/20/2003 - Jeff Grimmett (grimmtooth@softhome.net)
+#
+# o wxMaskedEditMixin -> MaskedEditMixin
+# o wxMaskedTextCtrl -> MaskedTextCtrl
+# o wxMaskedComboBoxSelectEvent -> MaskedComboBoxSelectEvent
+# o wxMaskedComboBox -> MaskedComboBox
+# o wxIpAddrCtrl -> IpAddrCtrl
+# o wxTimeCtrl -> TimeCtrl
+#
 
 """\
 <b>Masked Edit Overview:
 =====================</b>
-<b>wxMaskedTextCtrl</b>
+<b>MaskedTextCtrl</b>
     is a sublassed text control that can carefully control the user's input
     based on a mask string you provide.
 
     General usage example:
-        control = wxMaskedTextCtrl( win, -1, '', mask = '(###) ###-####')
+        control = MaskedTextCtrl( win, -1, '', mask = '(###) ###-####')
 
     The example above will create a text control that allows only numbers to be
     entered and then only in the positions indicated in the mask by the # sign.
 
-<b>wxMaskedComboBox</b>
+<b>MaskedComboBox</b>
     is a similar subclass of wxComboBox that allows the same sort of masking,
     but also can do auto-complete of values, and can require the value typed
     to be in the list of choices to be colored appropriately.
 <b>wxMaskedCtrl</b>
     is actually a factory function for several types of masked edit controls:
 
-    <b>wxMaskedTextCtrl</b>   - standard masked edit text box
-    <b>wxMaskedComboBox</b>   - adds combobox capabilities
-    <b>wxIpAddrCtrl</b>       - adds special semantics for IP address entry
-    <b>wxTimeCtrl</b>         - special subclass handling lots of types as values
+    <b>MaskedTextCtrl</b>   - standard masked edit text box
+    <b>MaskedComboBox</b>   - adds combobox capabilities
+    <b>IpAddrCtrl</b>       - adds special semantics for IP address entry
+    <b>TimeCtrl</b>         - special subclass handling lots of types as values
     <b>wxMaskedNumCtrl</b>    - special subclass handling numeric values
 
     It works by looking for a <b><i>controlType</i></b> parameter in the keyword
     arguments of the control, to determine what kind of instance to return.
     If not specified as a keyword argument, the default control type returned
-    will be wxMaskedTextCtrl.
+    will be MaskedTextCtrl.
 
     Each of the above classes has its own set of arguments, but wxMaskedCtrl
     provides a single "unified" interface for masked controls.  Those for
-    wxMaskedTextCtrl, wxMaskedComboBox and wxIpAddrCtrl are all documented
+    MaskedTextCtrl, MaskedComboBox and IpAddrCtrl are all documented
     below; the others have their own demo pages and interface descriptions.
     (See end of following discussion for how to configure the wxMaskedCtrl()
     to select the above control types.)
@@ -242,7 +258,7 @@ decimalChar=</b>
         choices=        A list of strings that are allowed choices for the control.
         choiceRequired= value must be member of choices list
         compareNoCase=  Perform case-insensitive matching when validating against list
-                        <i>Note: for wxMaskedComboBox, this defaults to True.</i>
+                        <i>Note: for MaskedComboBox, this defaults to True.</i>
         emptyInvalid=   Boolean indicating whether an empty value should be considered invalid
 
         validFunc=      A function to call of the form: bool = func(candidate_value)
@@ -396,7 +412,7 @@ decimalChar=</b>
                     after construction; it takes a list of key/value pairs as arguments,
                     where the keys can be any of the mask-specific parameters in the constructor.
                     Eg:
-                        ctl = wxMaskedTextCtrl( self, -1 )
+                        ctl = MaskedTextCtrl( self, -1 )
                         ctl.SetCtrlParameters( mask='###-####',
                                                defaultValue='555-1212',
                                                formatcodes='F')
@@ -414,6 +430,11 @@ decimalChar=</b>
           ctl.GetChoiceRequired()
           ctl.GetFormatcodes()
 
+  <b><i>Note:</i></b> After any change in parameters, the choices for the
+      control are reevaluated to ensure that they are still legal.  If you
+      have large choice lists, it is therefore more efficient to set parameters
+      before setting the choices available.
+
   <b>.SetFieldParameters(field_index, **kwargs)</b>
                     This function allows you to specify change individual field
                     parameters after construction. (Indices are 0-based.)
@@ -427,7 +448,8 @@ The control detects certain common constructions. In order to use the signed fea
 decimal point. Without a decimal (e.g. '######', the control will treat it as an integer
 value. With a decimal (e.g. '###.##'), the control will act as a floating point control
 (i.e. press decimal to 'tab' to the decimal position). Pressing decimal in the
-integer control truncates the value.
+integer control truncates the value.  However, for a true numeric control,
+MaskedNumCtrl provides all this, and true numeric input/output support as well.
 
 
 Check your controls by calling each control's .IsValid() function and the
@@ -477,7 +499,7 @@ Naming Conventions
 
   The following methods must be used and/or defined when deriving a control
   from wxMaskedEditMixin.  NOTE: if deriving from a *masked edit* control
-  (eg. class wxIpAddrCtrl(wxMaskedTextCtrl) ), then this is NOT necessary,
+  (eg. class IpAddrCtrl(MaskedTextCtrl) ), then this is NOT necessary,
   as it's already been done for you in the base class.
 
         ._SetInitialValue()
@@ -507,8 +529,8 @@ Naming Conventions
                         Similarly to _GetSelection, each class derived from
                         wxMaskedEditMixin must define the function for setting
                         the start and end of the current text selection.
-                        (eg. .SetSelection() for wxMaskedTextCtrl, and .SetMark() for
-                        wxMaskedComboBox.
+                        (eg. .SetSelection() for MaskedTextCtrl, and .SetMark() for
+                        MaskedComboBox.
 
         ._GetInsertionPoint()
         ._SetInsertionPoint()
@@ -555,7 +577,7 @@ Naming Conventions
         ._IsEditable()  REQUIRED
                         Each class derived from wxMaskedEditMixin must define
                         the function used to determine if the base control is
-                        editable or not.  (For wxMaskedComboBox, this has to
+                        editable or not.  (For MaskedComboBox, this has to
                         be done with code, rather than specifying the proper
                         function in the base control, as there isn't one...)
         ._CalcSize()    REQUIRED
@@ -590,7 +612,7 @@ Event Handling
 
   These 5 handlers must be "wired up" for the wxMaskedEdit
   control to provide default behavior.  (The setupEventHandling
-  is an argument to wxMaskedTextCtrl and wxMaskedComboBox, so
+  is an argument to MaskedTextCtrl and MaskedComboBox, so
   that controls derived from *them* may replace one of these
   handlers if they so choose.)
 
@@ -618,7 +640,7 @@ Event Handling
         ._AddNavKeycode(keycode, handler=None)
         ._AddNavKey(char, handler=None)
                         Allows controls to specify other keys (and optional handlers)
-                        to be treated as navigational characters. (eg. '.' in wxIpAddrCtrl)
+                        to be treated as navigational characters. (eg. '.' in IpAddrCtrl)
 
         ._GetNavKeycodes()  Returns the current list of navigational keycodes.
 
@@ -647,7 +669,7 @@ Event Handling
                         By default, it adjusts the year in date fields if mask is a date,
                         It can be overridden by a derived class to
                         adjust the value of the control at that time.
-                        (eg. wxIpAddrCtrl reformats the address in this way.)
+                        (eg. IpAddrCtrl reformats the address in this way.)
 
         ._Change()      Called by internal EVT_TEXT handler. Return False to force
                         skip of the normal class change event.
@@ -675,20 +697,56 @@ Event Handling
         _OnCtrl_Z(event)        'undo'  - resets value to previous value (if any)
 
         _OnChangeField(event)   primarily used for tab events, but can be
-                                used for other keys (eg. '.' in wxIpAddrCtrl)
+                                used for other keys (eg. '.' in IpAddrCtrl)
 
         _OnErase(event)         used for backspace and delete
         _OnHome(event)
         _OnEnd(event)
 
+    The following routine provides a hook back to any class derivations, so that
+    they can react to parameter changes before any value is set/reset as a result of
+    those changes.  (eg. MaskedComboBox needs to detect when the choices list is
+    modified, either implicitly or explicitly, so it can reset the base control
+    to have the appropriate choice list *before* the initial value is reset to match.)
+
+        _OnCtrlParametersChanged()
+
+Accessor Functions
+------------------
+    For convenience, each class derived from MaskedEditMixin should
+    define an accessors mixin, so that it exposes only those parameters
+    that make sense for the derivation.  This is done with an intermediate
+    level of inheritance, ie:
+
+    class BaseMaskedTextCtrl( TextCtrl, MaskedEditMixin ):
+
+    class MaskedTextCtrl( BaseMaskedTextCtrl, MaskedEditAccessorsMixin ):
+    class MaskedNumCtrl( BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin ):
+    class IpAddrCtrl( BaseMaskedTextCtrl, IpAddrCtrlAccessorsMixin ):
+    class TimeCtrl( BaseMaskedTextCtrl, TimeCtrlAccessorsMixin ):
+
+    etc.
+
+    Each accessors mixin defines Get/Set functions for the base class parameters
+    that are appropriate for that derivation.
+    This allows the base classes to be "more generic," exposing the widest
+    set of options, while not requiring derived classes to be so general.
 """
 
-from wxPython.wx import *
-import string, re, copy, difflib, types
+import  copy
+import  difflib
+import  re
+import  string
+import  types
+
+import  wx
+
+# 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 
 
-from wxPython.tools.dbg import Logger
 dbg = Logger()
-dbg(enable=0)
+##dbg(enable=0)
 
 ## ---------- ---------- ---------- ---------- ---------- ---------- ----------
 
@@ -701,8 +759,15 @@ WXK_CTRL_V = (ord('V')+1) - ord('A')
 WXK_CTRL_X = (ord('X')+1) - ord('A')
 WXK_CTRL_Z = (ord('Z')+1) - ord('A')
 
-nav =     (WXK_BACK, WXK_LEFT, WXK_RIGHT, WXK_UP, WXK_DOWN, WXK_TAB, WXK_HOME, WXK_END, WXK_RETURN, WXK_PRIOR, WXK_NEXT)
-control = (WXK_BACK, WXK_DELETE, WXK_CTRL_A, WXK_CTRL_C, WXK_CTRL_S, WXK_CTRL_V, WXK_CTRL_X, WXK_CTRL_Z)
+nav = (
+    wx.WXK_BACK, wx.WXK_LEFT, wx.WXK_RIGHT, wx.WXK_UP, wx.WXK_DOWN, wx.WXK_TAB, 
+    wx.WXK_HOME, wx.WXK_END, wx.WXK_RETURN, wx.WXK_PRIOR, wx.WXK_NEXT
+    )
+
+control = (
+    wx.WXK_BACK, wx.WXK_DELETE, WXK_CTRL_A, WXK_CTRL_C, WXK_CTRL_S, WXK_CTRL_V, 
+    WXK_CTRL_X, WXK_CTRL_Z
+    )
 
 
 ## ---------- ---------- ---------- ---------- ---------- ---------- ----------
@@ -813,17 +878,17 @@ masktags = {
            'validRegex': '^' + months + '-' + days + '-' + '\d{4} ' + hours + ':' + minutes + ':' + seconds + ' (A|P)M',
            'description': "US Date + Time\n(w/hypens)"
            },
-       "USDATEMILTIMEMMDDYYYY/HHMMSS": {
+       "USDATE24HRTIMEMMDDYYYY/HHMMSS": {           
            'mask': "##/##/#### ##:##:##",
            'formatcodes': 'DF',
            'validRegex': '^' + months + '/' + days + '/' + '\d{4} ' + milhours + ':' + minutes + ':' + seconds,
-           'description': "US Date + Military Time"
+           'description': "US Date + 24Hr (Military) Time"           
            },
-       "USDATEMILTIMEMMDDYYYY-HHMMSS": {
+       "USDATE24HRTIMEMMDDYYYY-HHMMSS": {
            'mask': "##-##-#### ##:##:##",
            'formatcodes': 'DF',
            'validRegex': '^' + months + '-' + days + '-' + '\d{4} ' + milhours + ':' + minutes + ':' + seconds,
-           'description': "US Date + Military Time\n(w/hypens)"
+           'description': "US Date + 24Hr Time\n(w/hypens)"           
            },
        "USDATETIMEMMDDYYYY/HHMM": {
            'mask': "##/##/#### ##:## AM",
@@ -832,11 +897,11 @@ masktags = {
            'validRegex': '^' + months + '/' + days + '/' + '\d{4} ' + hours + ':' + minutes + ' (A|P)M',
            'description': "US Date + Time\n(without seconds)"
            },
-       "USDATEMILTIMEMMDDYYYY/HHMM": {
+       "USDATE24HRTIMEMMDDYYYY/HHMM": {
            'mask': "##/##/#### ##:##",
            'formatcodes': 'DF',
            'validRegex': '^' + months + '/' + days + '/' + '\d{4} ' + milhours + ':' + minutes,
-           'description': "US Date + Military Time\n(without seconds)"
+           'description': "US Date + 24Hr Time\n(without seconds)"           
            },
        "USDATETIMEMMDDYYYY-HHMM": {
            'mask': "##-##-#### ##:## AM",
@@ -845,11 +910,11 @@ masktags = {
            'validRegex': '^' + months + '-' + days + '-' + '\d{4} ' + hours + ':' + minutes + ' (A|P)M',
            'description': "US Date + Time\n(w/hypens and w/o secs)"
            },
-       "USDATEMILTIMEMMDDYYYY-HHMM": {
+       "USDATE24HRTIMEMMDDYYYY-HHMM": {
            'mask': "##-##-#### ##:##",
            'formatcodes': 'DF',
            'validRegex': '^' + months + '-' + days + '-' + '\d{4} ' + milhours + ':' + minutes,
-           'description': "US Date + Military Time\n(w/hyphens and w/o seconds)"
+           'description': "US Date + 24Hr Time\n(w/hyphens and w/o seconds)"
            },
        "USDATEMMDDYYYY/": {
            'mask': "##/##/####",
@@ -965,52 +1030,52 @@ masktags = {
            'description': "DD.MM.YYYY HH:MM"
            },
 
-       "EUDATEMILTIMEYYYYMMDD/HHMMSS": {
+       "EUDATE24HRTIMEYYYYMMDD/HHMMSS": {
            'mask': "####/##/## ##:##:##",
            'formatcodes': 'DF',
            'validRegex': '^' + '\d{4}'+ '/' + months + '/' + days + ' ' + milhours + ':' + minutes + ':' + seconds,
-           'description': "YYYY/MM/DD Mil. Time"
+           'description': "YYYY/MM/DD 24Hr Time"
            },
-       "EUDATEMILTIMEYYYYMMDD.HHMMSS": {
+       "EUDATE24HRTIMEYYYYMMDD.HHMMSS": {
            'mask': "####.##.## ##:##:##",
            'formatcodes': 'DF',
            'validRegex': '^' + '\d{4}'+ '.' + months + '.' + days + ' ' + milhours + ':' + minutes + ':' + seconds,
-           'description': "YYYY.MM.DD Mil. Time"
+           'description': "YYYY.MM.DD 24Hr Time"
            },
-       "EUDATEMILTIMEDDMMYYYY/HHMMSS": {
+       "EUDATE24HRTIMEDDMMYYYY/HHMMSS": {
            'mask': "##/##/#### ##:##:##",
            'formatcodes': 'DF',
            'validRegex': '^' + days + '/' + months + '/' + '\d{4} ' + milhours + ':' + minutes + ':' + seconds,
-           'description': "DD/MM/YYYY Mil. Time"
+           'description': "DD/MM/YYYY 24Hr Time"
            },
-       "EUDATEMILTIMEDDMMYYYY.HHMMSS": {
+       "EUDATE24HRTIMEDDMMYYYY.HHMMSS": {
            'mask': "##.##.#### ##:##:##",
            'formatcodes': 'DF',
            'validRegex': '^' + days + '.' + months + '.' + '\d{4} ' + milhours + ':' + minutes + ':' + seconds,
-           'description': "DD.MM.YYYY Mil. Time"
+           'description': "DD.MM.YYYY 24Hr Time"
            },
-       "EUDATEMILTIMEYYYYMMDD/HHMM": {
+       "EUDATE24HRTIMEYYYYMMDD/HHMM": {
            'mask': "####/##/## ##:##",
            'formatcodes': 'DF','validRegex': '^' + '\d{4}'+ '/' + months + '/' + days + ' ' + milhours + ':' + minutes,
-           'description': "YYYY/MM/DD Mil. Time\n(w/o seconds)"
+           'description': "YYYY/MM/DD 24Hr Time\n(w/o seconds)"
            },
-       "EUDATEMILTIMEYYYYMMDD.HHMM": {
+       "EUDATE24HRTIMEYYYYMMDD.HHMM": {
            'mask': "####.##.## ##:##",
            'formatcodes': 'DF',
            'validRegex': '^' + '\d{4}'+ '.' + months + '.' + days + ' ' + milhours + ':' + minutes,
-           'description': "YYYY.MM.DD Mil. Time\n(w/o seconds)"
+           'description': "YYYY.MM.DD 24Hr Time\n(w/o seconds)"
            },
-       "EUDATEMILTIMEDDMMYYYY/HHMM": {
+       "EUDATE24HRTIMEDDMMYYYY/HHMM": {
            'mask': "##/##/#### ##:##",
            'formatcodes': 'DF',
            'validRegex': '^' + days + '/' + months + '/' + '\d{4} ' + milhours + ':' + minutes,
-           'description': "DD/MM/YYYY Mil. Time\n(w/o seconds)"
+           'description': "DD/MM/YYYY 24Hr Time\n(w/o seconds)"
            },
-       "EUDATEMILTIMEDDMMYYYY.HHMM": {
+       "EUDATE24HRTIMEDDMMYYYY.HHMM": {
            'mask': "##.##.#### ##:##",
            'formatcodes': 'DF',
            'validRegex': '^' + days + '.' + months + '.' + '\d{4} ' + milhours + ':' + minutes,
-           'description': "DD.MM.YYYY Mil. Time\n(w/o seconds)"
+           'description': "DD.MM.YYYY 24Hr Time\n(w/o seconds)"
            },
 
        "TIMEHHMMSS": {
@@ -1018,26 +1083,26 @@ masktags = {
            'excludeChars': am_pm_exclude,
            'formatcodes': 'TF!',
            'validRegex': '^' + hours + ':' + minutes + ':' + seconds + ' (A|P)M',
-           'description': "HH:MM:SS (A|P)M\n(see wxTimeCtrl)"
+           'description': "HH:MM:SS (A|P)M\n(see TimeCtrl)"
            },
        "TIMEHHMM": {
            'mask': "##:## AM",
            'excludeChars': am_pm_exclude,
            'formatcodes': 'TF!',
            'validRegex': '^' + hours + ':' + minutes + ' (A|P)M',
-           'description': "HH:MM (A|P)M\n(see wxTimeCtrl)"
+           'description': "HH:MM (A|P)M\n(see TimeCtrl)"
            },
-       "MILTIMEHHMMSS": {
+       "24HRTIMEHHMMSS": {
            'mask': "##:##:##",
            'formatcodes': 'TF',
            'validRegex': '^' + milhours + ':' + minutes + ':' + seconds,
-           'description': "Military HH:MM:SS\n(see wxTimeCtrl)"
+           'description': "24Hr HH:MM:SS\n(see TimeCtrl)"
            },
-       "MILTIMEHHMM": {
+       "24HRTIMEHHMM": {
            'mask': "##:##",
            'formatcodes': 'TF',
            'validRegex': '^' + milhours + ':' + minutes,
-           'description': "Military HH:MM\n(see wxTimeCtrl)"
+           'description': "24Hr HH:MM\n(see TimeCtrl)"
            },
        "USSOCIALSEC": {
            'mask': "###-##-####",
@@ -1092,7 +1157,7 @@ masktags = {
            'mask': "###.###.###.###",
            'formatcodes': 'F_Sr',
            '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}",
-           'description': "IP Address\n(see wxIpAddrCtrl)"
+           'description': "IP Address\n(see IpAddrCtrl)"
            }
        }
 
@@ -1140,11 +1205,11 @@ class Field:
         This is the "constructor" for setting up parameters for fields.
         a field_index of -1 is used to indicate "the entire control."
         """
-##        dbg('Field::Field', indent=1)
+####        dbg('Field::Field', indent=1)
         # Validate legitimate set of parameters:
         for key in kwargs.keys():
             if key not in Field.valid_params.keys():
-##                dbg(indent=0)
+####                dbg(indent=0)
                 raise TypeError('invalid parameter "%s"' % (key))
 
         # Set defaults for each parameter for this instance, and fully
@@ -1158,7 +1223,7 @@ class Field:
         self._SetParameters(**kwargs)
         self._ValidateParameters(**kwargs)
 
-##        dbg(indent=0)
+####        dbg(indent=0)
 
 
     def _SetParameters(self, **kwargs):
@@ -1166,19 +1231,21 @@ class Field:
         This function can be used to set individual or multiple parameters for
         a masked edit field parameter after construction.
         """
-        dbg(suspend=1)
-        dbg('maskededit.Field::_SetParameters', indent=1)
+##        dbg(suspend=1)
+##        dbg('maskededit.Field::_SetParameters', indent=1)
         # Validate keyword arguments:
         for key in kwargs.keys():
             if key not in Field.valid_params.keys():
-                dbg(indent=0, suspend=0)
+##                dbg(indent=0, suspend=0)
                 raise AttributeError('invalid keyword argument "%s"' % key)
 
         if self._index is not None: dbg('field index:', self._index)
-        dbg('parameters:', indent=1)
+##        dbg('parameters:', indent=1)
         for key, value in kwargs.items():
-            dbg('%s:' % key, value)
-        dbg(indent=0)
+##            dbg('%s:' % key, value)
+            pass
+##        dbg(indent=0)
+
 
         old_fillChar = self._fillChar   # store so we can change choice lists accordingly if it changes
 
@@ -1212,13 +1279,13 @@ class Field:
 
         if kwargs.has_key('fillChar'):
             self._old_fillChar = old_fillChar
-##            dbg("self._old_fillChar: '%s'" % self._old_fillChar)
+####            dbg("self._old_fillChar: '%s'" % self._old_fillChar)
 
         if kwargs.has_key('mask') or kwargs.has_key('validRegex'):  # (set/changed)
             self._isInt = isInteger(self._mask)
-            dbg('isInt?', self._isInt, 'self._mask:"%s"' % self._mask)
+##            dbg('isInt?', self._isInt, 'self._mask:"%s"' % self._mask)
 
-        dbg(indent=0, suspend=0)
+##        dbg(indent=0, suspend=0)
 
 
     def _ValidateParameters(self, **kwargs):
@@ -1226,18 +1293,18 @@ class Field:
         This function can be used to validate individual or multiple parameters for
         a masked edit field parameter after construction.
         """
-        dbg(suspend=1)
-        dbg('maskededit.Field::_ValidateParameters', indent=1)
+##        dbg(suspend=1)
+##        dbg('maskededit.Field::_ValidateParameters', indent=1)
         if self._index is not None: dbg('field index:', self._index)
-##        dbg('parameters:', indent=1)
+####        dbg('parameters:', indent=1)
 ##        for key, value in kwargs.items():
-##            dbg('%s:' % key, value)
-##        dbg(indent=0)
-##        dbg("self._old_fillChar: '%s'" % self._old_fillChar)
+####            dbg('%s:' % key, value)
+####        dbg(indent=0)
+####        dbg("self._old_fillChar: '%s'" % self._old_fillChar)
 
         # Verify proper numeric format params:
         if self._groupdigits and self._groupChar == self._decimalChar:
-            dbg(indent=0, suspend=0)
+##            dbg(indent=0, suspend=0)
             raise AttributeError("groupChar '%s' cannot be the same as decimalChar '%s'" % (self._groupChar, self._decimalChar))
 
 
@@ -1261,7 +1328,7 @@ class Field:
                     else:
                         self._filter = re.compile(self._validRegex)
                 except:
-                    dbg(indent=0, suspend=0)
+##                    dbg(indent=0, suspend=0)
                     raise TypeError('%s: validRegex "%s" not a legal regular expression' % (str(self._index), self._validRegex))
             else:
                 self._filter = None
@@ -1272,7 +1339,7 @@ class Field:
             self._rangeLow  = 0
             if self._validRange:
                 if type(self._validRange) != types.TupleType or len( self._validRange )!= 2 or self._validRange[0] > self._validRange[1]:
-                    dbg(indent=0, suspend=0)
+##                    dbg(indent=0, suspend=0)
                     raise TypeError('%s: validRange %s parameter must be tuple of form (a,b) where a <= b'
                                     % (str(self._index), repr(self._validRange)) )
 
@@ -1283,16 +1350,16 @@ class Field:
         if kwargs.has_key('choices') or (len(self._choices) and len(self._choices[0]) != len(self._mask)):       # (set/changed)
             self._hasList   = False
             if self._choices and type(self._choices) not in (types.TupleType, types.ListType):
-                dbg(indent=0, suspend=0)
+##                dbg(indent=0, suspend=0)
                 raise TypeError('%s: choices must be a sequence of strings' % str(self._index))
             elif len( self._choices) > 0:
                 for choice in self._choices:
                     if type(choice) not in (types.StringType, types.UnicodeType):
-                        dbg(indent=0, suspend=0)
+##                        dbg(indent=0, suspend=0)
                         raise TypeError('%s: choices must be a sequence of strings' % str(self._index))
 
                 length = len(self._mask)
-                dbg('len(%s)' % self._mask, length, 'len(self._choices):', len(self._choices), 'length:', length, 'self._alignRight?', self._alignRight)
+##                dbg('len(%s)' % self._mask, length, 'len(self._choices):', len(self._choices), 'length:', length, 'self._alignRight?', self._alignRight)
                 if len(self._choices) and length:
                     if len(self._choices[0]) > length:
                         # changed mask without respecifying choices; readjust the width as appropriate:
@@ -1301,7 +1368,7 @@ class Field:
                         self._choices = [choice.rjust( length ) for choice in self._choices]
                     else:
                         self._choices = [choice.ljust( length ) for choice in self._choices]
-                    dbg('aligned choices:', self._choices)
+##                    dbg('aligned choices:', self._choices)
 
                 if hasattr(self, '_template'):
                     # Verify each choice specified is valid:
@@ -1310,28 +1377,28 @@ class Field:
                             # allow empty values even if invalid, (just colored differently)
                             continue
                         if not self.IsValid(choice):
-                            dbg(indent=0, suspend=0)
+##                            dbg(indent=0, suspend=0)
                             raise ValueError('%s: "%s" is not a valid value for the control as specified.' % (str(self._index), choice))
                 self._hasList = True
 
-##        dbg("kwargs.has_key('fillChar')?", kwargs.has_key('fillChar'), "len(self._choices) > 0?", len(self._choices) > 0)
-##        dbg("self._old_fillChar:'%s'" % self._old_fillChar, "self._fillChar: '%s'" % self._fillChar)
+####        dbg("kwargs.has_key('fillChar')?", kwargs.has_key('fillChar'), "len(self._choices) > 0?", len(self._choices) > 0)
+####        dbg("self._old_fillChar:'%s'" % self._old_fillChar, "self._fillChar: '%s'" % self._fillChar)
         if kwargs.has_key('fillChar') and len(self._choices) > 0:
             if kwargs['fillChar'] != ' ':
                 self._choices = [choice.replace(' ', self._fillChar) for choice in self._choices]
             else:
                 self._choices = [choice.replace(self._old_fillChar, self._fillChar) for choice in self._choices]
-            dbg('updated choices:', self._choices)
+##            dbg('updated choices:', self._choices)
 
 
         if kwargs.has_key('autoSelect') and kwargs['autoSelect']:
             if not self._hasList:
-                dbg('no list to auto complete; ignoring "autoSelect=True"')
+##                dbg('no list to auto complete; ignoring "autoSelect=True"')
                 self._autoSelect = False
 
         # reset field validity assumption:
         self._valid = True
-        dbg(indent=0, suspend=0)
+##        dbg(indent=0, suspend=0)
 
 
     def _GetParameter(self, paramname):
@@ -1349,28 +1416,28 @@ class Field:
         Indicates whether the specified slice is considered empty for the
         field.
         """
-        dbg('Field::IsEmpty("%s")' % slice, indent=1)
+##        dbg('Field::IsEmpty("%s")' % slice, indent=1)
         if not hasattr(self, '_template'):
-            dbg(indent=0)
+##            dbg(indent=0)
             raise AttributeError('_template')
 
-        dbg('self._template: "%s"' % self._template)
-        dbg('self._defaultValue: "%s"' % str(self._defaultValue))
+##        dbg('self._template: "%s"' % self._template)
+##        dbg('self._defaultValue: "%s"' % str(self._defaultValue))
         if slice == self._template and not self._defaultValue:
-            dbg(indent=0)
+##            dbg(indent=0)
             return True
 
         elif slice == self._template:
             empty = True
             for pos in range(len(self._template)):
-##                dbg('slice[%(pos)d] != self._fillChar?' %locals(), slice[pos] != self._fillChar[pos])
+####                dbg('slice[%(pos)d] != self._fillChar?' %locals(), slice[pos] != self._fillChar[pos])
                 if slice[pos] not in (' ', self._fillChar):
                     empty = False
                     break
-            dbg("IsEmpty? %(empty)d (do all mask chars == fillChar?)" % locals(), indent=0)
+##            dbg("IsEmpty? %(empty)d (do all mask chars == fillChar?)" % locals(), indent=0)
             return empty
         else:
-            dbg("IsEmpty? 0 (slice doesn't match template)", indent=0)
+##            dbg("IsEmpty? 0 (slice doesn't match template)", indent=0)
             return False
 
 
@@ -1379,23 +1446,23 @@ class Field:
         Indicates whether the specified slice is considered a valid value for the
         field.
         """
-        dbg(suspend=1)
-        dbg('Field[%s]::IsValid("%s")' % (str(self._index), slice), indent=1)
+##        dbg(suspend=1)
+##        dbg('Field[%s]::IsValid("%s")' % (str(self._index), slice), indent=1)
         valid = True    # assume true to start
 
         if self.IsEmpty(slice):
-            dbg(indent=0, suspend=0)
+##            dbg(indent=0, suspend=0)
             if self._emptyInvalid:
                 return False
             else:
                 return True
 
         elif self._hasList and self._choiceRequired:
-            dbg("(member of list required)")
+##            dbg("(member of list required)")
             # do case-insensitive match on list; strip surrounding whitespace from slice (already done for choices):
             if self._fillChar != ' ':
                 slice = slice.replace(self._fillChar, ' ')
-                dbg('updated slice:"%s"' % slice)
+##                dbg('updated slice:"%s"' % slice)
             compareStr = slice.strip()
 
             if self._compareNoCase:
@@ -1403,7 +1470,7 @@ class Field:
             valid = compareStr in self._compareChoices
 
         elif self._hasRange and not self.IsEmpty(slice):
-            dbg('validating against range')
+##            dbg('validating against range')
             try:
                 # allow float as well as int ranges (int comparisons for free.)
                 valid = self._rangeLow <= float(slice) <= self._rangeHigh
@@ -1411,22 +1478,22 @@ class Field:
                 valid = False
 
         elif self._validRegex and self._filter:
-            dbg('validating against regex')
+##            dbg('validating against regex')
             valid = (re.match( self._filter, slice) is not None)
 
         if valid and self._validFunc:
-            dbg('validating against supplied function')
+##            dbg('validating against supplied function')
             valid = self._validFunc(slice)
-        dbg('valid?', valid, indent=0, suspend=0)
+##        dbg('valid?', valid, indent=0, suspend=0)
         return valid
 
 
     def _AdjustField(self, slice):
         """ 'Fixes' an integer field. Right or left-justifies, as required."""
-        dbg('Field::_AdjustField("%s")' % slice, indent=1)
+##        dbg('Field::_AdjustField("%s")' % slice, indent=1)
         length = len(self._mask)
-##        dbg('length(self._mask):', length)
-##        dbg('self._useParensForNegatives?', self._useParensForNegatives)
+####        dbg('length(self._mask):', length)
+####        dbg('self._useParensForNegatives?', self._useParensForNegatives)
         if self._isInt:
             if self._useParensForNegatives:
                 signpos = slice.find('(')
@@ -1441,13 +1508,13 @@ class Field:
             intStr = string.replace(intStr,self._fillChar,"")       # drop extra fillchars
             intStr = string.replace(intStr,"-","")                  # drop sign, if any
             intStr = string.replace(intStr, self._groupChar, "")    # lose commas/dots
-##            dbg('intStr:"%s"' % intStr)
+####            dbg('intStr:"%s"' % intStr)
             start, end = self._extent
             field_len = end - start
             if not self._padZero and len(intStr) != field_len and intStr.strip():
                 intStr = str(long(intStr))
-##            dbg('raw int str: "%s"' % intStr)
-##            dbg('self._groupdigits:', self._groupdigits, 'self._formatcodes:', self._formatcodes)
+####            dbg('raw int str: "%s"' % intStr)
+####            dbg('self._groupdigits:', self._groupdigits, 'self._formatcodes:', self._formatcodes)
             if self._groupdigits:
                 new = ''
                 cnt = 1
@@ -1463,8 +1530,8 @@ class Field:
                     intStr = new
                 # else... leave it without the commas...
 
-            dbg('padzero?', self._padZero)
-            dbg('len(intStr):', len(intStr), 'field length:', length)
+##            dbg('padzero?', self._padZero)
+##            dbg('len(intStr):', len(intStr), 'field length:', length)
             if self._padZero and len(intStr) < length:
                 intStr = '0' * (length - len(intStr)) + intStr
                 if signpos != -1:   # we had a sign before; restore it
@@ -1494,13 +1561,13 @@ class Field:
             slice = slice.ljust( length )
         if self._fillChar != ' ':
             slice = slice.replace(' ', self._fillChar)
-        dbg('adjusted slice: "%s"' % slice, indent=0)
+##        dbg('adjusted slice: "%s"' % slice, indent=0)
         return slice
 
 
 ## ---------- ---------- ---------- ---------- ---------- ---------- ----------
 
-class wxMaskedEditMixin:
+class MaskedEditMixin:
     """
     This class allows us to abstract the masked edit functionality that could
     be associated with any text entry control. (eg. wxTextCtrl, wxComboBox, etc.)
@@ -1541,7 +1608,7 @@ class wxMaskedEditMixin:
 
         # Validate legitimate set of parameters:
         for key in kwargs.keys():
-            if key.replace('Color', 'Colour') not in wxMaskedEditMixin.valid_ctrl_params.keys() + Field.valid_params.keys():
+            if key.replace('Color', 'Colour') not in MaskedEditMixin.valid_ctrl_params.keys() + Field.valid_params.keys():
                 raise TypeError('%s: invalid parameter "%s"' % (name, key))
 
         ## Set up dictionary that can be used by subclasses to override or add to default
@@ -1554,20 +1621,20 @@ class wxMaskedEditMixin:
         ## Initially populated with navigation and function control keys:
         self._keyhandlers = {
             # default navigation keys and handlers:
-            WXK_BACK:   self._OnErase,
-            WXK_LEFT:   self._OnArrow,
-            WXK_RIGHT:  self._OnArrow,
-            WXK_UP:     self._OnAutoCompleteField,
-            WXK_DOWN:   self._OnAutoCompleteField,
-            WXK_TAB:    self._OnChangeField,
-            WXK_HOME:   self._OnHome,
-            WXK_END:    self._OnEnd,
-            WXK_RETURN: self._OnReturn,
-            WXK_PRIOR:  self._OnAutoCompleteField,
-            WXK_NEXT:   self._OnAutoCompleteField,
+            wx.WXK_BACK:   self._OnErase,
+            wx.WXK_LEFT:   self._OnArrow,
+            wx.WXK_RIGHT:  self._OnArrow,
+            wx.WXK_UP:     self._OnAutoCompleteField,
+            wx.WXK_DOWN:   self._OnAutoCompleteField,
+            wx.WXK_TAB:    self._OnChangeField,
+            wx.WXK_HOME:   self._OnHome,
+            wx.WXK_END:    self._OnEnd,
+            wx.WXK_RETURN: self._OnReturn,
+            wx.WXK_PRIOR:  self._OnAutoCompleteField,
+            wx.WXK_NEXT:   self._OnAutoCompleteField,
 
             # default function control keys and handlers:
-            WXK_DELETE: self._OnErase,
+            wx.WXK_DELETE: self._OnErase,
             WXK_CTRL_A: self._OnCtrl_A,
             WXK_CTRL_C: self._OnCtrl_C,
             WXK_CTRL_S: self._OnCtrl_S,
@@ -1595,7 +1662,7 @@ class wxMaskedEditMixin:
             '&': string.punctuation
         }
 
-        ## self._ignoreChange is used by wxMaskedComboBox, because
+        ## self._ignoreChange is used by MaskedComboBox, because
         ## of the hack necessary to determine the selection; it causes
         ## EVT_TEXT messages from the combobox to be ignored if set.
         self._ignoreChange = False
@@ -1608,10 +1675,10 @@ class wxMaskedEditMixin:
 
         # Set defaults for each parameter for this instance, and fully
         # populate initial parameter list for configuration:
-        for key, value in wxMaskedEditMixin.valid_ctrl_params.items():
+        for key, value in MaskedEditMixin.valid_ctrl_params.items():
             setattr(self, '_' + key, copy.copy(value))
             if not kwargs.has_key(key):
-##                dbg('%s: "%s"' % (key, repr(value)))
+####                dbg('%s: "%s"' % (key, repr(value)))
                 kwargs[key] = copy.copy(value)
 
         # Create a "field" that holds global parameters for control constraints
@@ -1625,20 +1692,20 @@ class wxMaskedEditMixin:
         This public function can be used to set individual or multiple masked edit
         parameters after construction.
         """
-        dbg(suspend=1)
-        dbg('wxMaskedEditMixin::SetCtrlParameters', indent=1)
-##        dbg('kwargs:', indent=1)
+##        dbg(suspend=1)
+##        dbg('MaskedEditMixin::SetCtrlParameters', indent=1)
+####        dbg('kwargs:', indent=1)
 ##        for key, value in kwargs.items():
-##            dbg(key, '=', value)
-##        dbg(indent=0)
+####            dbg(key, '=', value)
+####        dbg(indent=0)
 
         # Validate keyword arguments:
         constraint_kwargs = {}
         ctrl_kwargs = {}
         for key, value in kwargs.items():
             key = key.replace('Color', 'Colour')    # for b-c, and standard wxPython spelling
-            if key not in wxMaskedEditMixin.valid_ctrl_params.keys() + Field.valid_params.keys():
-                dbg(indent=0, suspend=0)
+            if key not in MaskedEditMixin.valid_ctrl_params.keys() + Field.valid_params.keys():
+##                dbg(indent=0, suspend=0)
                 raise TypeError('Invalid keyword argument "%s" for control "%s"' % (key, self.name))
             elif key in Field.valid_params.keys():
                 constraint_kwargs[key] = value
@@ -1653,8 +1720,12 @@ class wxMaskedEditMixin:
         else:
             autoformat = None
 
+        # handle "parochial name" backward compatibility:
+        if autoformat and autoformat.find('MILTIME') != -1 and autoformat not in masktags.keys():
+            autoformat = autoformat.replace('MILTIME', '24HRTIME')
+
         if autoformat != self._autoformat and autoformat in masktags.keys():
-            dbg('autoformat:', autoformat)
+##            dbg('autoformat:', autoformat)
             self._autoformat                  = autoformat
             mask                              = masktags[self._autoformat]['mask']
             # gather rest of any autoformat parameters:
@@ -1665,17 +1736,17 @@ class wxMaskedEditMixin:
         elif autoformat and not autoformat in masktags.keys():
             raise AttributeError('invalid value for autoformat parameter: %s' % repr(autoformat))
         else:
-            dbg('autoformat not selected')
+##            dbg('autoformat not selected')
             if kwargs.has_key('mask'):
                 mask = kwargs['mask']
-                dbg('mask:', mask)
+##                dbg('mask:', mask)
 
         ## Assign style flags
         if mask is None:
-            dbg('preserving previous mask')
+##            dbg('preserving previous mask')
             mask = self._previous_mask   # preserve previous mask
         else:
-            dbg('mask (re)set')
+##            dbg('mask (re)set')
             reset_args['reset_mask'] = mask
             constraint_kwargs['mask'] = mask
 
@@ -1691,28 +1762,28 @@ class wxMaskedEditMixin:
                 for i in range(len(fields)):
                     field = fields[i]
                     if not isinstance(field, Field):
-                        dbg(indent=0, suspend=0)
+##                        dbg(indent=0, suspend=0)
                         raise AttributeError('invalid type for field parameter: %s' % repr(field))
                     self._fields[i] = field
 
             elif type(fields) == types.DictionaryType:
                 for index, field in fields.items():
                     if not isinstance(field, Field):
-                        dbg(indent=0, suspend=0)
+##                        dbg(indent=0, suspend=0)
                         raise AttributeError('invalid type for field parameter: %s' % repr(field))
                     self._fields[index] = field
             else:
-                dbg(indent=0, suspend=0)
+##                dbg(indent=0, suspend=0)
                 raise AttributeError('fields parameter must be a list or dictionary; not %s' % repr(fields))
 
         # Assign constraint parameters for entire control:
-##        dbg('control constraints:', indent=1)
+####        dbg('control constraints:', indent=1)
 ##        for key, value in constraint_kwargs.items():
-##            dbg('%s:' % key, value)
-##        dbg(indent=0)
+####            dbg('%s:' % key, value)
+####        dbg(indent=0)
 
         # determine if changing parameters that should affect the entire control:
-        for key in wxMaskedEditMixin.valid_ctrl_params.keys():
+        for key in MaskedEditMixin.valid_ctrl_params.keys():
             if key in ( 'mask', 'fields' ): continue    # (processed separately)
             if ctrl_kwargs.has_key(key):
                 setattr(self, '_' + key, ctrl_kwargs[key])
@@ -1723,7 +1794,7 @@ class wxMaskedEditMixin:
                     'foregroundColour', 'signedForegroundColour'):
             if ctrl_kwargs.has_key(key):
                 if type(ctrl_kwargs[key]) in (types.StringType, types.UnicodeType):
-                    c = wxNamedColor(ctrl_kwargs[key])
+                    c = wx.NamedColour(ctrl_kwargs[key])
                     if c.Get() == (-1, -1, -1):
                         raise TypeError('%s not a legal color specification for %s' % (repr(ctrl_kwargs[key]), key))
                     else:
@@ -1732,19 +1803,19 @@ class wxMaskedEditMixin:
                         # attach a python dynamic attribute to wxColour for debug printouts
                         c._name = ctrl_kwargs[key]
 
-                elif type(ctrl_kwargs[key]) != type(wxBLACK):
+                elif type(ctrl_kwargs[key]) != type(wx.BLACK):
                     raise TypeError('%s not a legal color specification for %s' % (repr(ctrl_kwargs[key]), key))
 
 
-        dbg('self._retainFieldValidation:', self._retainFieldValidation)
+##        dbg('self._retainFieldValidation:', self._retainFieldValidation)
         if not self._retainFieldValidation:
             # Build dictionary of any changing parameters which should be propagated to the
             # component fields:
             for arg in Field.propagating_params:
-##                dbg('kwargs.has_key(%s)?' % arg, kwargs.has_key(arg))
-##                dbg('getattr(self._ctrl_constraints, _%s)?' % arg, getattr(self._ctrl_constraints, '_'+arg))
+####                dbg('kwargs.has_key(%s)?' % arg, kwargs.has_key(arg))
+####                dbg('getattr(self._ctrl_constraints, _%s)?' % arg, getattr(self._ctrl_constraints, '_'+arg))
                 reset_args[arg] = kwargs.has_key(arg) and kwargs[arg] != getattr(self._ctrl_constraints, '_'+arg)
-##                dbg('reset_args[%s]?' % arg, reset_args[arg])
+####                dbg('reset_args[%s]?' % arg, reset_args[arg])
 
         # Set the control-level constraints:
         self._ctrl_constraints._SetParameters(**constraint_kwargs)
@@ -1761,7 +1832,7 @@ class wxMaskedEditMixin:
         # Validate that all choices for given fields are at least of the
         # necessary length, and that they all would be valid pastes if pasted
         # into their respective fields:
-##        dbg('validating choices')
+####        dbg('validating choices')
         self._validateChoices()
 
 
@@ -1788,6 +1859,9 @@ class wxMaskedEditMixin:
             elif self._autoformat.find('DMMY')  != -1: self._datestyle = 'DMY'
             elif self._autoformat.find('DMMMY') != -1: self._datestyle = 'DMY'
 
+        # Give derived controls a chance to react to parameter changes before
+        # potentially changing current value of the control.
+        self._OnCtrlParametersChanged()
 
         if self.controlInitialized:
             # Then the base control is available for configuration;
@@ -1797,18 +1871,18 @@ class wxMaskedEditMixin:
                 self._setFont()
 
             if reset_args.has_key('reset_mask'):
-                dbg('reset mask')
+##                dbg('reset mask')
                 curvalue = self._GetValue()
                 if curvalue.strip():
                     try:
-                        dbg('attempting to _SetInitialValue(%s)' % self._GetValue())
+##                        dbg('attempting to _SetInitialValue(%s)' % self._GetValue())
                         self._SetInitialValue(self._GetValue())
                     except Exception, e:
-                        dbg('exception caught:', e)
-                        dbg("current value doesn't work; attempting to reset to template")
+##                        dbg('exception caught:', e)
+##                        dbg("current value doesn't work; attempting to reset to template")
                         self._SetInitialValue()
                 else:
-                    dbg('attempting to _SetInitialValue() with template')
+##                    dbg('attempting to _SetInitialValue() with template')
                     self._SetInitialValue()
 
             elif kwargs.has_key('useParensForNegatives'):
@@ -1822,19 +1896,19 @@ class wxMaskedEditMixin:
                         if newvalue[-1] in (' ', ')'):
                             newvalue = newvalue[:-1]
 
-                    dbg('reconfiguring value for parens:"%s"' % newvalue)
+##                    dbg('reconfiguring value for parens:"%s"' % newvalue)
                     self._SetValue(newvalue)
 
                     if self._prevValue != newvalue:
                         self._prevValue = newvalue  # disallow undo of sign type
 
             if self._autofit:
-                dbg('setting client size to:', self._CalcSize())
+##                dbg('setting client size to:', self._CalcSize())
                 self.SetClientSize(self._CalcSize())
 
             # Set value/type-specific formatting
             self._applyFormatting()
-        dbg(indent=0, suspend=0)
+##        dbg(indent=0, suspend=0)
 
     def SetMaskParameters(self, **kwargs):
         """ old name for this function """
@@ -1845,7 +1919,7 @@ class wxMaskedEditMixin:
         """
         Routine for retrieving the value of any given parameter
         """
-        if wxMaskedEditMixin.valid_ctrl_params.has_key(paramname.replace('Color','Colour')):
+        if MaskedEditMixin.valid_ctrl_params.has_key(paramname.replace('Color','Colour')):
             return getattr(self, '_' + paramname.replace('Color', 'Colour'))
         elif Field.valid_params.has_key(paramname):
             return self._ctrl_constraints._GetParameter(paramname)
@@ -1857,23 +1931,30 @@ class wxMaskedEditMixin:
         return self.GetCtrlParameter(paramname)
 
 
-    # ## 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.)
-    # ##
-    for param in valid_ctrl_params.keys() + Field.valid_params.keys():
-        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))
+## This idea worked, but Boa was unable to use this solution...
+##    def _attachMethod(self, func):
+##        import new
+##        setattr(self, func.__name__, new.instancemethod(func, self, self.__class__))
+##
+##
+##    def _DefinePropertyFunctions(exposed_params):
+##        for param in exposed_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))
+##            self._attachMethod(locals()['Set%s' % propname])
+##            self._attachMethod(locals()['Get%s' % propname])
+##
+##            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))
+##                self._attachMethod(locals()['Set%s' % propname])
+##                self._attachMethod(locals()['Get%s' % propname])
+##
 
 
     def SetFieldParameters(self, field_index, **kwargs):
@@ -1979,7 +2060,7 @@ class wxMaskedEditMixin:
         of booleans indicating whether or not a given position in the mask is
         a mask character or not.
         """
-        dbg('_processMask: mask', mask, indent=1)
+##        dbg('_processMask: mask', mask, indent=1)
         # regular expression for parsing c{n} syntax:
         rex = re.compile('([' +string.join(maskchars,"") + '])\{(\d+)\}')
         s = mask
@@ -1999,8 +2080,8 @@ class wxMaskedEditMixin:
         self._signOk     = '-' in self._ctrl_constraints._formatcodes and (self._isFloat or self._isInt)
         self._useParens  = self._ctrl_constraints._useParensForNegatives
         self._isNeg      = False
-##        dbg('self._signOk?', self._signOk, 'self._useParens?', self._useParens)
-##        dbg('isFloatingPoint(%s)?' % (s), isFloatingPoint(s),
+####        dbg('self._signOk?', self._signOk, 'self._useParens?', self._useParens)
+####        dbg('isFloatingPoint(%s)?' % (s), isFloatingPoint(s),
 ##            'ctrl regex:', self._ctrl_constraints._validRegex)
 
         if self._signOk and s[0] != ' ':
@@ -2027,10 +2108,10 @@ class wxMaskedEditMixin:
                         s = s[:i] + s[i+1:]     # elide the 2nd '\' as well
             else:                       # else if special char, mark position accordingly
                 ismasked[i] = s[i] in maskchars
-##            dbg('ismasked[%d]:' % i, ismasked[i], s)
+####            dbg('ismasked[%d]:' % i, ismasked[i], s)
             i += 1                      # increment to next char
-##        dbg('ismasked:', ismasked)
-        dbg('new mask: "%s"' % s, indent=0)
+####        dbg('ismasked:', ismasked)
+##        dbg('new mask: "%s"' % s, indent=0)
 
         return s, ismasked
 
@@ -2067,7 +2148,7 @@ class wxMaskedEditMixin:
                     self._fields[1] = Field()
 
                 self._decimalpos = string.find( self._mask, '.')
-                dbg('decimal pos =', self._decimalpos)
+##                dbg('decimal pos =', self._decimalpos)
 
                 formatcodes = self._fields[0]._GetParameter('formatcodes')
                 if 'R' not in formatcodes: formatcodes += 'R'
@@ -2108,18 +2189,18 @@ class wxMaskedEditMixin:
                     pos = i       # figure out field for 1st editable space:
 
                 while i <= len(self._mask):
-##                    dbg('searching: outer field loop: i = ', i)
+####                    dbg('searching: outer field loop: i = ', i)
                     if self._isMaskChar(i):
-##                        dbg('1st char is mask char; recording edit_start=', i)
+####                        dbg('1st char is mask char; recording edit_start=', i)
                         edit_start = i
                         # Skip to end of editable part of current field:
                         while i < len(self._mask) and self._isMaskChar(i):
                             self._lookupField[i] = field_index
                             i += 1
-##                        dbg('edit_end =', i)
+####                        dbg('edit_end =', i)
                         edit_end = i
                         self._lookupField[i] = field_index
-##                        dbg('self._fields.has_key(%d)?' % field_index, self._fields.has_key(field_index))
+####                        dbg('self._fields.has_key(%d)?' % field_index, self._fields.has_key(field_index))
                         if not self._fields.has_key(field_index):
                             kwargs = Field.valid_params.copy()
                             kwargs['index'] = field_index
@@ -2140,15 +2221,15 @@ class wxMaskedEditMixin:
                         break           # if past end, we're done
                     else:
                         field_index += 1
-##                        dbg('next field:', field_index)
+####                        dbg('next field:', field_index)
 
         indices = self._fields.keys()
         indices.sort()
         self._field_indices = indices[1:]
-##        dbg('lookupField map:', indent=1)
+####        dbg('lookupField map:', indent=1)
 ##        for i in range(len(self._mask)):
-##            dbg('pos %d:' % i, self._lookupField[i])
-##        dbg(indent=0)
+####            dbg('pos %d:' % i, self._lookupField[i])
+####        dbg(indent=0)
 
         # Verify that all field indices specified are valid for mask:
         for index in self._fields.keys():
@@ -2169,7 +2250,7 @@ class wxMaskedEditMixin:
             for field in self._fields.values():
                 if field._defaultValue and not reset_default:
                     default_set = True
-        dbg('default set?', default_set)
+##        dbg('default set?', default_set)
 
         # Determine overall new template for control, and keep track of previous
         # values, so that current control value can be modified as appropriate:
@@ -2191,9 +2272,9 @@ class wxMaskedEditMixin:
             field._template = ""
 
         for pos in range(len(self._mask)):
-##            dbg('pos:', pos)
+####            dbg('pos:', pos)
             field = self._FindField(pos)
-##            dbg('field:', field._index)
+####            dbg('field:', field._index)
             start, end = field._extent
 
             if pos == 0 and self._signOk:
@@ -2216,32 +2297,32 @@ class wxMaskedEditMixin:
                         curvalue[pos] = fillChar
 
                 if not field._defaultValue and not self._ctrl_constraints._defaultValue:
-##                    dbg('no default value')
+####                    dbg('no default value')
                     self._template += fillChar
                     field._template += fillChar
 
                 elif field._defaultValue and not reset_default:
-##                    dbg('len(field._defaultValue):', len(field._defaultValue))
-##                    dbg('pos-start:', pos-start)
+####                    dbg('len(field._defaultValue):', len(field._defaultValue))
+####                    dbg('pos-start:', pos-start)
                     if len(field._defaultValue) > pos-start:
-##                        dbg('field._defaultValue[pos-start]: "%s"' % field._defaultValue[pos-start])
+####                        dbg('field._defaultValue[pos-start]: "%s"' % field._defaultValue[pos-start])
                         self._template += field._defaultValue[pos-start]
                         field._template += field._defaultValue[pos-start]
                     else:
-##                        dbg('field default not long enough; using fillChar')
+####                        dbg('field default not long enough; using fillChar')
                         self._template += fillChar
                         field._template += fillChar
                 else:
                     if len(self._ctrl_constraints._defaultValue) > pos:
-##                        dbg('using control default')
+####                        dbg('using control default')
                         self._template += self._ctrl_constraints._defaultValue[pos]
                         field._template += self._ctrl_constraints._defaultValue[pos]
                     else:
-##                        dbg('ctrl default not long enough; using fillChar')
+####                        dbg('ctrl default not long enough; using fillChar')
                         self._template += fillChar
                         field._template += fillChar
-##                dbg('field[%d]._template now "%s"' % (field._index, field._template))
-##                dbg('self._template now "%s"' % self._template)
+####                dbg('field[%d]._template now "%s"' % (field._index, field._template))
+####                dbg('self._template now "%s"' % self._template)
             else:
                 self._template += self._mask[pos]
 
@@ -2254,20 +2335,20 @@ class wxMaskedEditMixin:
 
         if default_set:
             self._defaultValue = self._template
-            dbg('self._defaultValue:', self._defaultValue)
+##            dbg('self._defaultValue:', self._defaultValue)
             if not self.IsEmpty(self._defaultValue) and not self.IsValid(self._defaultValue):
-##                dbg(indent=0)
+####                dbg(indent=0)
                 raise ValueError('Default value of "%s" is not a valid value for control "%s"' % (self._defaultValue, self.name))
 
             # if no fillchar change, but old value == old template, replace it:
             if newvalue == old_template:
                 newvalue = self._template
-                reset_value = true
+                reset_value = True
         else:
             self._defaultValue = None
 
         if reset_value:
-            dbg('resetting value to: "%s"' % newvalue)
+##            dbg('resetting value to: "%s"' % newvalue)
             pos = self._GetInsertionPoint()
             sel_start, sel_to = self._GetSelection()
             self._SetValue(newvalue)
@@ -2313,11 +2394,11 @@ class wxMaskedEditMixin:
                 inherit_args['defaultValue'] = ""   # (reset for field)
 
             for param in Field.propagating_params:
-##                dbg('reset_args.has_key(%s)?' % param, reset_args.has_key(param))
-##                dbg('reset_args.has_key(%(param)s) and reset_args[%(param)s]?' % locals(), reset_args.has_key(param) and reset_args[param])
+####                dbg('reset_args.has_key(%s)?' % param, reset_args.has_key(param))
+####                dbg('reset_args.has_key(%(param)s) and reset_args[%(param)s]?' % locals(), reset_args.has_key(param) and reset_args[param])
                 if reset_args.has_key(param):
                     inherit_args[param] = self.GetCtrlParameter(param)
-##                    dbg('inherit_args[%s]' % param, inherit_args[param])
+####                    dbg('inherit_args[%s]' % param, inherit_args[param])
 
             if inherit_args:
                 field._SetParameters(**inherit_args)
@@ -2334,22 +2415,22 @@ class wxMaskedEditMixin:
             if field._choices:
                 index = field._index
                 if len(self._field_indices) == 1 and index == 0 and field._choices == self._ctrl_constraints._choices:
-                    dbg('skipping (duplicate) choice validation of field 0')
+##                    dbg('skipping (duplicate) choice validation of field 0')
                     continue
-##                dbg('checking for choices for field', field._index)
+####                dbg('checking for choices for field', field._index)
                 start, end = field._extent
                 field_length = end - start
-##                dbg('start, end, length:', start, end, field_length)
+####                dbg('start, end, length:', start, end, field_length)
                 for choice in field._choices:
-##                    dbg('testing "%s"' % choice)
+####                    dbg('testing "%s"' % choice)
                     valid_paste, ignore, replace_to = self._validatePaste(choice, start, end)
                     if not valid_paste:
-##                        dbg(indent=0)
+####                        dbg(indent=0)
                         raise ValueError('"%s" could not be entered into field %d of control "%s"' % (choice, index, self.name))
                     elif replace_to > end:
-##                        dbg(indent=0)
+####                        dbg(indent=0)
                         raise ValueError('"%s" will not fit into field %d of control "%s"' (choice, index, self.name))
-##                    dbg(choice, 'valid in field', index)
+####                    dbg(choice, 'valid in field', index)
 
 
     def _configure(self, mask, **reset_args):
@@ -2367,19 +2448,19 @@ class wxMaskedEditMixin:
         whole control.
 
         """
-        dbg(suspend=1)
-        dbg('wxMaskedEditMixin::_configure("%s")' % mask, indent=1)
+##        dbg(suspend=1)
+##        dbg('MaskedEditMixin::_configure("%s")' % mask, indent=1)
 
         # Preprocess specified mask to expand {n} syntax, handle escaped
         # mask characters, etc and build the resulting positionally keyed
         # dictionary for which positions are mask vs. template characters:
         self._mask, self.ismasked = self._processMask(mask)
         self._masklength = len(self._mask)
-##        dbg('processed mask:', self._mask)
+####        dbg('processed mask:', self._mask)
 
         # Preserve original mask specified, for subsequent reprocessing
         # if parameters change.
-        dbg('mask: "%s"' % self._mask, 'previous mask: "%s"' % self._previous_mask)
+##        dbg('mask: "%s"' % self._mask, 'previous mask: "%s"' % self._previous_mask)
         self._previous_mask = mask    # save unexpanded mask for next time
             # Set expanded mask and extent of field -1 to width of entire control:
         self._ctrl_constraints._SetParameters(mask = self._mask, extent=(0,self._masklength))
@@ -2388,7 +2469,7 @@ class wxMaskedEditMixin:
         # instances as necessary, configure them with those extents, and
         # build lookup table mapping each position for control to its corresponding
         # field.
-##        dbg('calculating field extents')
+####        dbg('calculating field extents')
 
         self._calcFieldExtents()
 
@@ -2398,13 +2479,13 @@ class wxMaskedEditMixin:
         reset_fillchar = reset_args.has_key('fillChar') and reset_args['fillChar']
         reset_default = reset_args.has_key('defaultValue') and reset_args['defaultValue']
 
-##        dbg('calculating template')
+####        dbg('calculating template')
         self._calcTemplate(reset_fillchar, reset_default)
 
         # Propagate control-level formatting and character constraints to each
         # field if they don't already have them; if only one field, propagate
         # control-level validation constraints to field as well:
-##        dbg('propagating constraints')
+####        dbg('propagating constraints')
         self._propagateConstraints(**reset_args)
 
 
@@ -2412,10 +2493,10 @@ class wxMaskedEditMixin:
             raise AttributeError('groupChar (%s) and decimalChar (%s) must be distinct.' %
                                  (self._fields[0]._groupChar, self._decimalChar) )
 
-##        dbg('fields:', indent=1)
+####        dbg('fields:', indent=1)
 ##        for i in [-1] + self._field_indices:
-##            dbg('field %d:' % i, self._fields[i].__dict__)
-##        dbg(indent=0)
+####            dbg('field %d:' % i, self._fields[i].__dict__)
+####        dbg(indent=0)
 
         # Set up special parameters for numeric control, if appropriate:
         if self._signOk:
@@ -2433,7 +2514,7 @@ class wxMaskedEditMixin:
         if self._isFloat or self._isInt:
             if self.controlInitialized:
                 value = self._GetValue()
-##                dbg('value: "%s"' % value, 'len(value):', len(value),
+####                dbg('value: "%s"' % value, 'len(value):', len(value),
 ##                    'len(self._ctrl_constraints._mask):',len(self._ctrl_constraints._mask))
                 if len(value) < len(self._ctrl_constraints._mask):
                     newvalue = value
@@ -2446,12 +2527,12 @@ class wxMaskedEditMixin:
                             newvalue = newvalue.rjust(len(self._ctrl_constraints._mask))
                         else:
                             newvalue = newvalue.ljust(len(self._ctrl_constraints._mask))
-                    dbg('old value: "%s"' % value)
-                    dbg('new value: "%s"' % newvalue)
+##                    dbg('old value: "%s"' % value)
+##                    dbg('new value: "%s"' % newvalue)
                     try:
                         self._SetValue(newvalue)
                     except Exception, e:
-                        dbg('exception raised:', e, 'resetting to initial value')
+##                        dbg('exception raised:', e, 'resetting to initial value')
                         self._SetInitialValue()
 
                 elif len(value) > len(self._ctrl_constraints._mask):
@@ -2463,31 +2544,31 @@ class wxMaskedEditMixin:
                     if not self._signOk:
                         newvalue, signpos, right_signpos = self._getSignedValue(newvalue)
 
-                    dbg('old value: "%s"' % value)
-                    dbg('new value: "%s"' % newvalue)
+##                    dbg('old value: "%s"' % value)
+##                    dbg('new value: "%s"' % newvalue)
                     try:
                         self._SetValue(newvalue)
                     except Exception, e:
-                        dbg('exception raised:', e, 'resetting to initial value')
+##                        dbg('exception raised:', e, 'resetting to initial value')
                         self._SetInitialValue()
                 elif not self._signOk and ('(' in value or '-' in value):
                     newvalue, signpos, right_signpos = self._getSignedValue(value)
-                    dbg('old value: "%s"' % value)
-                    dbg('new value: "%s"' % newvalue)
+##                    dbg('old value: "%s"' % value)
+##                    dbg('new value: "%s"' % newvalue)
                     try:
                         self._SetValue(newvalue)
                     except e:
-                        dbg('exception raised:', e, 'resetting to initial value')
+##                        dbg('exception raised:', e, 'resetting to initial value')
                         self._SetInitialValue()
 
             # Replace up/down arrow default handling:
             # make down act like tab, up act like shift-tab:
 
-##            dbg('Registering numeric navigation and control handlers (if not already set)')
-            if not self._keyhandlers.has_key(WXK_DOWN):
-                self._SetKeycodeHandler(WXK_DOWN, self._OnChangeField)
-            if not self._keyhandlers.has_key(WXK_UP):
-                self._SetKeycodeHandler(WXK_UP, self._OnUpNumeric)  # (adds "shift" to up arrow, and calls _OnChangeField)
+####            dbg('Registering numeric navigation and control handlers (if not already set)')
+            if not self._keyhandlers.has_key(wx.WXK_DOWN):
+                self._SetKeycodeHandler(wx.WXK_DOWN, self._OnChangeField)
+            if not self._keyhandlers.has_key(wx.WXK_UP):
+                self._SetKeycodeHandler(wx.WXK_UP, self._OnUpNumeric)  # (adds "shift" to up arrow, and calls _OnChangeField)
 
             # On ., truncate contents right of cursor to decimal point (if any)
             # leaves cusor after decimal point if floating point, otherwise at 0.
@@ -2500,7 +2581,7 @@ class wxMaskedEditMixin:
             if not self._keyhandlers.has_key(ord(self._fields[0]._groupChar)):
                 self._SetKeyHandler(self._fields[0]._groupChar, self._OnGroupChar)
 
-        dbg(indent=0, suspend=0)
+##        dbg(indent=0, suspend=0)
 
 
     def _SetInitialValue(self, value=""):
@@ -2509,7 +2590,7 @@ class wxMaskedEditMixin:
         It will also set/reset the font if necessary and apply
         formatting to the control at this time.
         """
-        dbg('wxMaskedEditMixin::_SetInitialValue("%s")' % value, indent=1)
+##        dbg('MaskedEditMixin::_SetInitialValue("%s")' % value, indent=1)
         if not value:
             self._prevValue = self._curValue = self._template
             # don't apply external validation rules in this case, as template may
@@ -2517,58 +2598,58 @@ class wxMaskedEditMixin:
             try:
                 self._SetValue(self._curValue)  # note the use of "raw" ._SetValue()...
             except Exception, e:
-                dbg('exception thrown:', e, indent=0)
+##                dbg('exception thrown:', e, indent=0)
                 raise
         else:
             # Otherwise apply validation as appropriate to passed value:
-##            dbg('value = "%s", length:' % value, len(value))
+####            dbg('value = "%s", length:' % value, len(value))
             self._prevValue = self._curValue = value
             try:
                 self.SetValue(value)            # use public (validating) .SetValue()
             except Exception, e:
-                dbg('exception thrown:', e, indent=0)
+##                dbg('exception thrown:', e, indent=0)
                 raise
 
 
         # Set value/type-specific formatting
         self._applyFormatting()
-        dbg(indent=0)
+##        dbg(indent=0)
 
 
     def _calcSize(self, size=None):
         """ Calculate automatic size if allowed; must be called after the base control is instantiated"""
-##        dbg('wxMaskedEditMixin::_calcSize', indent=1)
-        cont = (size is None or size == wxDefaultSize)
+####        dbg('MaskedEditMixin::_calcSize', indent=1)
+        cont = (size is None or size == wx.DefaultSize)
 
         if cont and self._autofit:
             sizing_text = 'M' * self._masklength
-            if wxPlatform != "__WXMSW__":   # give it a little extra space
+            if wx.Platform != "__WXMSW__":   # give it a little extra space
                 sizing_text += 'M'
-            if wxPlatform == "__WXMAC__":   # give it even a little more...
+            if wx.Platform == "__WXMAC__":   # give it even a little more...
                 sizing_text += 'M'
-##            dbg('len(sizing_text):', len(sizing_text), 'sizing_text: "%s"' % sizing_text)
+####            dbg('len(sizing_text):', len(sizing_text), 'sizing_text: "%s"' % sizing_text)
             w, h = self.GetTextExtent(sizing_text)
             size = (w+4, self.GetClientSize().height)
-##            dbg('size:', size, indent=0)
+####            dbg('size:', size, indent=0)
         return size
 
 
     def _setFont(self):
         """ Set the control's font typeface -- pass the font name as str."""
-##        dbg('wxMaskedEditMixin::_setFont', indent=1)
+####        dbg('MaskedEditMixin::_setFont', indent=1)
         if not self._useFixedWidthFont:
-            self._font = wxSystemSettings_GetFont(wxSYS_DEFAULT_GUI_FONT)
+            self._font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
         else:
             font = self.GetFont()   # get size, weight, etc from current font
 
-            # Set to teletype font (guaranteed to be mappable to all wxWindows
+            # Set to teletype font (guaranteed to be mappable to all wxWidgets
             # platforms:
-            self._font = wxFont( font.GetPointSize(), wxTELETYPE, font.GetStyle(),
+            self._font = wx.Font( font.GetPointSize(), wx.TELETYPE, font.GetStyle(),
                                  font.GetWeight(), font.GetUnderlined())
-##            dbg('font string: "%s"' % font.GetNativeFontInfo().ToString())
+####            dbg('font string: "%s"' % font.GetNativeFontInfo().ToString())
 
         self.SetFont(self._font)
-##        dbg(indent=0)
+####        dbg(indent=0)
 
 
     def _OnTextChange(self, event):
@@ -2582,31 +2663,32 @@ class wxMaskedEditMixin:
         EVT_TEXT events for the same change.)
         """
         newvalue = self._GetValue()
-        dbg('wxMaskedEditMixin::_OnTextChange: value: "%s"' % newvalue, indent=1)
+##        dbg('MaskedEditMixin::_OnTextChange: value: "%s"' % newvalue, indent=1)
         bValid = False
         if self._ignoreChange:      # ie. if an "intermediate text change event"
-            dbg(indent=0)
+##            dbg(indent=0)
             return bValid
 
         ##! WS: For some inexplicable reason, every wxTextCtrl.SetValue
         ## call is generating two (2) EVT_TEXT events.
         ## This is the only mechanism I can find to mask this problem:
         if newvalue == self._curValue:
-            dbg('ignoring bogus text change event', indent=0)
+##            dbg('ignoring bogus text change event', indent=0)
+            pass
         else:
-            dbg('curvalue: "%s", newvalue: "%s"' % (self._curValue, newvalue))
+##            dbg('curvalue: "%s", newvalue: "%s"' % (self._curValue, newvalue))
             if self._Change():
                 if self._signOk and self._isNeg and newvalue.find('-') == -1 and newvalue.find('(') == -1:
-                    dbg('clearing self._isNeg')
+##                    dbg('clearing self._isNeg')
                     self._isNeg = False
                     text, self._signpos, self._right_signpos = self._getSignedValue()
                 self._CheckValid()  # Recolor control as appropriate
-            dbg('calling event.Skip()')
+##            dbg('calling event.Skip()')
             event.Skip()
             bValid = True
         self._prevValue = self._curValue    # save for undo
         self._curValue = newvalue           # Save last seen value for next iteration
-        dbg(indent=0)
+##        dbg(indent=0)
         return bValid
 
 
@@ -2620,7 +2702,7 @@ class wxMaskedEditMixin:
         if key in self._nav and event.ControlDown():
             # then this is the only place we will likely see these events;
             # process them now:
-            dbg('wxMaskedEditMixin::OnKeyDown: calling _OnChar')
+##            dbg('MaskedEditMixin::OnKeyDown: calling _OnChar')
             self._OnChar(event)
             return
         # else allow regular EVT_CHAR key processing
@@ -2632,25 +2714,25 @@ class wxMaskedEditMixin:
         This is the engine of wxMaskedEdit controls.  It examines each keystroke,
         decides if it's allowed, where it should go or what action to take.
         """
-        dbg('wxMaskedEditMixin::_OnChar', indent=1)
+##        dbg('MaskedEditMixin::_OnChar', indent=1)
 
         # Get keypress value, adjusted by control options (e.g. convert to upper etc)
         key = event.GetKeyCode()
         orig_pos = self._GetInsertionPoint()
         orig_value = self._GetValue()
-        dbg('keycode = ', key)
-        dbg('current pos = ', orig_pos)
-        dbg('current selection = ', self._GetSelection())
+##        dbg('keycode = ', key)
+##        dbg('current pos = ', orig_pos)
+##        dbg('current selection = ', self._GetSelection())
 
         if not self._Keypress(key):
-            dbg(indent=0)
+##            dbg(indent=0)
             return
 
         # If no format string for this control, or the control is marked as "read-only",
         # skip the rest of the special processing, and just "do the standard thing:"
         if not self._mask or not self._IsEditable():
             event.Skip()
-            dbg(indent=0)
+##            dbg(indent=0)
             return
 
         # Process navigation and control keys first, with
@@ -2661,79 +2743,79 @@ class wxMaskedEditMixin:
                 if self._GetValue() != orig_value:
                     self.modified = True
                 if not keep_processing:
-                    dbg(indent=0)
+##                    dbg(indent=0)
                     return
                 self._applyFormatting()
-                dbg(indent=0)
+##                dbg(indent=0)
                 return
 
         # Else... adjust the position as necessary for next input key,
         # and determine resulting selection:
         pos = self._adjustPos( orig_pos, key )    ## get insertion position, adjusted as needed
         sel_start, sel_to = self._GetSelection()                ## check for a range of selected text
-        dbg("pos, sel_start, sel_to:", pos, sel_start, sel_to)
+##        dbg("pos, sel_start, sel_to:", pos, sel_start, sel_to)
 
         keep_processing = True
         # Capture user past end of format field
         if pos > len(self.maskdict):
-            dbg("field length exceeded:",pos)
+##            dbg("field length exceeded:",pos)
             keep_processing = False
 
         if keep_processing:
             if self._isMaskChar(pos):  ## Get string of allowed characters for validation
                 okchars = self._getAllowedChars(pos)
             else:
-                dbg('Not a valid position: pos = ', pos,"chars=",maskchars)
+##                dbg('Not a valid position: pos = ', pos,"chars=",maskchars)
                 okchars = ""
 
         key = self._adjustKey(pos, key)     # apply formatting constraints to key:
 
         if self._keyhandlers.has_key(key):
             # there's an override for default behavior; use override function instead
-            dbg('using supplied key handler:', self._keyhandlers[key])
+##            dbg('using supplied key handler:', self._keyhandlers[key])
             keep_processing = self._keyhandlers[key](event)
             if self._GetValue() != orig_value:
                 self.modified = True
             if not keep_processing:
-                dbg(indent=0)
+##                dbg(indent=0)
                 return
             # else skip default processing, but do final formatting
-        if key < WXK_SPACE or key > 255:
-            dbg('key < WXK_SPACE or key > 255')
+        if key < wx.WXK_SPACE or key > 255:
+##            dbg('key < WXK_SPACE or key > 255')
             event.Skip()                # non alphanumeric
             keep_processing = False
         else:
             field = self._FindField(pos)
-            dbg("key ='%s'" % chr(key))
+##            dbg("key ='%s'" % chr(key))
             if chr(key) == ' ':
-                dbg('okSpaces?', field._okSpaces)
-
+##                dbg('okSpaces?', field._okSpaces)
+                pass
 
 
             if chr(key) in field._excludeChars + self._ctrl_constraints._excludeChars:
                 keep_processing = False
 
             if keep_processing and self._isCharAllowed( chr(key), pos, checkRegex = True ):
-                dbg("key allowed by mask")
+##                dbg("key allowed by mask")
                 # insert key into candidate new value, but don't change control yet:
                 oldstr = self._GetValue()
                 newstr, newpos, new_select_to, match_field, match_index = self._insertKey(
                                 chr(key), pos, sel_start, sel_to, self._GetValue(), allowAutoSelect = True)
-                dbg("str with '%s' inserted:" % chr(key), '"%s"' % newstr)
+##                dbg("str with '%s' inserted:" % chr(key), '"%s"' % newstr)
                 if self._ctrl_constraints._validRequired and not self.IsValid(newstr):
-                    dbg('not valid; checking to see if adjusted string is:')
+##                    dbg('not valid; checking to see if adjusted string is:')
                     keep_processing = False
                     if self._isFloat and newstr != self._template:
                         newstr = self._adjustFloat(newstr)
-                        dbg('adjusted str:', newstr)
+##                        dbg('adjusted str:', newstr)
                         if self.IsValid(newstr):
-                            dbg("it is!")
+##                            dbg("it is!")
                             keep_processing = True
-                            wxCallAfter(self._SetInsertionPoint, self._decimalpos)
+                            wx.CallAfter(self._SetInsertionPoint, self._decimalpos)
                     if not keep_processing:
-                        dbg("key disallowed by validation")
-                        if not wxValidator_IsSilent() and orig_pos == pos:
-                            wxBell()
+##                        dbg("key disallowed by validation")
+                        if not wx.Validator_IsSilent() and orig_pos == pos:
+                            wx.Bell()
 
                 if keep_processing:
                     unadjusted = newstr
@@ -2741,12 +2823,12 @@ class wxMaskedEditMixin:
                     # special case: adjust date value as necessary:
                     if self._isDate and newstr != self._template:
                         newstr = self._adjustDate(newstr)
-                    dbg('adjusted newstr:', newstr)
+##                    dbg('adjusted newstr:', newstr)
 
                     if newstr != orig_value:
                         self.modified = True
 
-                    wxCallAfter(self._SetValue, newstr)
+                    wx.CallAfter(self._SetValue, newstr)
 
                     # Adjust insertion point on date if just entered 2 digit year, and there are now 4 digits:
                     if not self.IsDefault() and self._isDate and self._4digityear:
@@ -2754,27 +2836,27 @@ class wxMaskedEditMixin:
                         if pos == year2dig and unadjusted[year2dig] != newstr[year2dig]:
                             newpos = pos+2
 
-                    wxCallAfter(self._SetInsertionPoint, newpos)
+                    wx.CallAfter(self._SetInsertionPoint, newpos)
 
                     if match_field is not None:
-                        dbg('matched field')
+##                        dbg('matched field')
                         self._OnAutoSelect(match_field, match_index)
 
                     if new_select_to != newpos:
-                        dbg('queuing selection: (%d, %d)' % (newpos, new_select_to))
-                        wxCallAfter(self._SetSelection, newpos, new_select_to)
+##                        dbg('queuing selection: (%d, %d)' % (newpos, new_select_to))
+                        wx.CallAfter(self._SetSelection, newpos, new_select_to)
                     else:
                         newfield = self._FindField(newpos)
                         if newfield != field and newfield._selectOnFieldEntry:
-                            dbg('queuing selection: (%d, %d)' % (newfield._extent[0], newfield._extent[1]))
-                            wxCallAfter(self._SetSelection, newfield._extent[0], newfield._extent[1])
-                    keep_processing = false
+##                            dbg('queuing selection: (%d, %d)' % (newfield._extent[0], newfield._extent[1]))
+                            wx.CallAfter(self._SetSelection, newfield._extent[0], newfield._extent[1])
+                    keep_processing = False
 
             elif keep_processing:
-                dbg('char not allowed')
+##                dbg('char not allowed')
                 keep_processing = False
-                if (not wxValidator_IsSilent()) and orig_pos == pos:
-                    wxBell()
+                if (not wx.Validator_IsSilent()) and orig_pos == pos:
+                    wx.Bell()
 
         self._applyFormatting()
 
@@ -2783,12 +2865,12 @@ class wxMaskedEditMixin:
             pos = self._GetInsertionPoint()
             next_entry = self._findNextEntry( pos )
             if pos != next_entry:
-                dbg("moving from %(pos)d to next valid entry: %(next_entry)d" % locals())
-                wxCallAfter(self._SetInsertionPoint, next_entry )
+##                dbg("moving from %(pos)d to next valid entry: %(next_entry)d" % locals())
+                wx.CallAfter(self._SetInsertionPoint, next_entry )
 
             if self._isTemplateChar(pos):
                 self._AdjustField(pos)
-        dbg(indent=0)
+##        dbg(indent=0)
 
 
     def _FindFieldExtent(self, pos=None, getslice=False, value=None):
@@ -2812,8 +2894,7 @@ class wxMaskedEditMixin:
         10, 14
         etc.
         """
-        dbg('wxMaskedEditMixin::_FindFieldExtent(pos=%s, getslice=%s)' % (
-                str(pos), str(getslice)) ,indent=1)
+##        dbg('MaskedEditMixin::_FindFieldExtent(pos=%s, getslice=%s)' % (str(pos), str(getslice)) ,indent=1)
 
         field = self._FindField(pos)
         if not field:
@@ -2825,12 +2906,12 @@ class wxMaskedEditMixin:
         if getslice:
             if value is None: value = self._GetValue()
             slice = value[edit_start:edit_end]
-            dbg('edit_start:', edit_start, 'edit_end:', edit_end, 'slice: "%s"' % slice)
-            dbg(indent=0)
+##            dbg('edit_start:', edit_start, 'edit_end:', edit_end, 'slice: "%s"' % slice)
+##            dbg(indent=0)
             return edit_start, edit_end, slice
         else:
-            dbg('edit_start:', edit_start, 'edit_end:', edit_end)
-            dbg(indent=0)
+##            dbg('edit_start:', edit_start, 'edit_end:', edit_end)
+##            dbg(indent=0)
             return edit_start, edit_end
 
 
@@ -2842,23 +2923,23 @@ class wxMaskedEditMixin:
         when calculating the current field.
 
         """
-##        dbg('wxMaskedEditMixin::_FindField(pos=%s)' % str(pos) ,indent=1)
+####        dbg('MaskedEditMixin::_FindField(pos=%s)' % str(pos) ,indent=1)
         if pos is None: pos = self._GetInsertionPoint()
         elif pos < 0 or pos > self._masklength:
             raise IndexError('position %s out of range of control' % str(pos))
 
         if len(self._fields) == 0:
-            dbg(indent=0)
+##            dbg(indent=0)
             return None
 
         # else...
-##        dbg(indent=0)
+####        dbg(indent=0)
         return self._fields[self._lookupField[pos]]
 
 
     def ClearValue(self):
         """ Blanks the current control value by replacing it with the default value."""
-        dbg("wxMaskedEditMixin::ClearValue - value reset to default value (template)")
+##        dbg("MaskedEditMixin::ClearValue - value reset to default value (template)")
         self._SetValue( self._template )
         self._SetInsertionPoint(0)
         self.Refresh()
@@ -2877,11 +2958,11 @@ class wxMaskedEditMixin:
         Makes up-arrow act like shift-tab should; ie. take you to start of
         previous field.
         """
-        dbg('wxMaskedEditMixin::_OnUpNumeric', indent=1)
+##        dbg('MaskedEditMixin::_OnUpNumeric', indent=1)
         event.m_shiftDown = 1
-        dbg('event.ShiftDown()?', event.ShiftDown())
+##        dbg('event.ShiftDown()?', event.ShiftDown())
         self._OnChangeField(event)
-        dbg(indent=0)
+##        dbg(indent=0)
 
 
     def _OnArrow(self, event):
@@ -2889,30 +2970,30 @@ class wxMaskedEditMixin:
         Used in response to left/right navigation keys; makes these actions skip
         over mask template chars.
         """
-        dbg("wxMaskedEditMixin::_OnArrow", indent=1)
+##        dbg("MaskedEditMixin::_OnArrow", indent=1)
         pos = self._GetInsertionPoint()
         keycode = event.GetKeyCode()
         sel_start, sel_to = self._GetSelection()
         entry_end = self._goEnd(getPosOnly=True)
-        if keycode in (WXK_RIGHT, WXK_DOWN):
+        if keycode in (wx.WXK_RIGHT, wx.WXK_DOWN):
             if( ( not self._isTemplateChar(pos) and pos+1 > entry_end)
                 or ( self._isTemplateChar(pos) and pos >= entry_end) ):
-                dbg("can't advance", indent=0)
+##                dbg("can't advance", indent=0)
                 return False
             elif self._isTemplateChar(pos):
                 self._AdjustField(pos)
-        elif keycode in (WXK_LEFT,WXK_UP) and sel_start == sel_to and pos > 0 and self._isTemplateChar(pos-1):
-            dbg('adjusting field')
+        elif keycode in (wx.WXK_LEFT,wx.WXK_UP) and sel_start == sel_to and pos > 0 and self._isTemplateChar(pos-1):
+##            dbg('adjusting field')
             self._AdjustField(pos)
 
         # treat as shifted up/down arrows as tab/reverse tab:
-        if event.ShiftDown() and keycode in (WXK_UP, WXK_DOWN):
+        if event.ShiftDown() and keycode in (wx.WXK_UP, wx.WXK_DOWN):
             # remove "shifting" and treat as (forward) tab:
             event.m_shiftDown = False
             keep_processing = self._OnChangeField(event)
 
         elif self._FindField(pos)._selectOnFieldEntry:
-            if( keycode in (WXK_UP, WXK_LEFT)
+            if( keycode in (wx.WXK_UP, wx.WXK_LEFT)
                 and sel_start != 0
                 and self._isTemplateChar(sel_start-1)
                 and sel_start != self._masklength
@@ -2923,7 +3004,7 @@ class wxMaskedEditMixin:
                 event.m_shiftDown = True
                 event.m_ControlDown = True
                 keep_processing = self._OnChangeField(event)
-            elif( keycode in (WXK_DOWN, WXK_RIGHT)
+            elif( keycode in (wx.WXK_DOWN, wx.WXK_RIGHT)
                   and sel_to != self._masklength
                   and self._isTemplateChar(sel_to)):
 
@@ -2933,29 +3014,29 @@ class wxMaskedEditMixin:
             else:
                 # treat arrows as normal, allowing selection
                 # as appropriate:
-                dbg('using base ctrl event processing')
+##                dbg('using base ctrl event processing')
                 event.Skip()
         else:
-            if( (sel_to == self._fields[0]._extent[0] and keycode == WXK_LEFT)
-                or (sel_to == self._masklength and keycode == WXK_RIGHT) ):
-                if not wxValidator_IsSilent():
-                    wxBell()
+            if( (sel_to == self._fields[0]._extent[0] and keycode == wx.WXK_LEFT)
+                or (sel_to == self._masklength and keycode == wx.WXK_RIGHT) ):
+                if not wx.Validator_IsSilent():
+                    wx.Bell()
             else:
                 # treat arrows as normal, allowing selection
                 # as appropriate:
-                dbg('using base event processing')
+##                dbg('using base event processing')
                 event.Skip()
 
         keep_processing = False
-        dbg(indent=0)
+##        dbg(indent=0)
         return keep_processing
 
 
     def _OnCtrl_S(self, event):
         """ Default Ctrl-S handler; prints value information if demo enabled. """
-        dbg("wxMaskedEditMixin::_OnCtrl_S")
+##        dbg("MaskedEditMixin::_OnCtrl_S")
         if self._demo:
-            print 'wxMaskedEditMixin.GetValue()       = "%s"\nwxMaskedEditMixin.GetPlainValue() = "%s"' % (self.GetValue(), self.GetPlainValue())
+            print 'MaskedEditMixin.GetValue()       = "%s"\nMaskedEditMixin.GetPlainValue() = "%s"' % (self.GetValue(), self.GetPlainValue())
             print "Valid? => " + str(self.IsValid())
             print "Current field, start, end, value =", str( self._FindFieldExtent(getslice=True))
         return False
@@ -2964,9 +3045,9 @@ class wxMaskedEditMixin:
     def _OnCtrl_X(self, event=None):
         """ Handles ctrl-x keypress in control and Cut operation on context menu.
             Should return False to skip other processing. """
-        dbg("wxMaskedEditMixin::_OnCtrl_X", indent=1)
+##        dbg("MaskedEditMixin::_OnCtrl_X", indent=1)
         self.Cut()
-        dbg(indent=0)
+##        dbg(indent=0)
         return False
 
     def _OnCtrl_C(self, event=None):
@@ -2978,38 +3059,38 @@ class wxMaskedEditMixin:
     def _OnCtrl_V(self, event=None):
         """ Handles ctrl-V keypress in control and Paste operation on context menu.
             Should return False to skip other processing. """
-        dbg("wxMaskedEditMixin::_OnCtrl_V", indent=1)
+##        dbg("MaskedEditMixin::_OnCtrl_V", indent=1)
         self.Paste()
-        dbg(indent=0)
+##        dbg(indent=0)
         return False
 
     def _OnCtrl_Z(self, event=None):
         """ Handles ctrl-Z keypress in control and Undo operation on context menu.
-            Should return false to skip other processing. """
-        dbg("wxMaskedEditMixin::_OnCtrl_Z", indent=1)
+            Should return False to skip other processing. """
+##        dbg("MaskedEditMixin::_OnCtrl_Z", indent=1)
         self.Undo()
-        dbg(indent=0)
+##        dbg(indent=0)
         return False
 
     def _OnCtrl_A(self,event=None):
         """ Handles ctrl-a keypress in control. Should return False to skip other processing. """
         end = self._goEnd(getPosOnly=True)
         if not event or event.ShiftDown():
-            wxCallAfter(self._SetInsertionPoint, 0)
-            wxCallAfter(self._SetSelection, 0, self._masklength)
+            wx.CallAfter(self._SetInsertionPoint, 0)
+            wx.CallAfter(self._SetSelection, 0, self._masklength)
         else:
-            wxCallAfter(self._SetInsertionPoint, 0)
-            wxCallAfter(self._SetSelection, 0, end)
+            wx.CallAfter(self._SetInsertionPoint, 0)
+            wx.CallAfter(self._SetSelection, 0, end)
         return False
 
 
     def _OnErase(self, event=None):
         """ Handles backspace and delete keypress in control. Should return False to skip other processing."""
-        dbg("wxMaskedEditMixin::_OnErase", indent=1)
+##        dbg("MaskedEditMixin::_OnErase", indent=1)
         sel_start, sel_to = self._GetSelection()                   ## check for a range of selected text
 
         if event is None:   # called as action routine from Cut() operation.
-            key = WXK_DELETE
+            key = wx.WXK_DELETE
         else:
             key = event.GetKeyCode()
 
@@ -3019,16 +3100,16 @@ class wxMaskedEditMixin:
         oldstart = sel_start
 
         # If trying to erase beyond "legal" bounds, disallow operation:
-        if( (sel_to == 0 and key == WXK_BACK)
-            or (self._signOk and sel_to == 1 and value[0] == ' ' and key == WXK_BACK)
-            or (sel_to == self._masklength and sel_start == sel_to and key == WXK_DELETE and not field._insertRight)
+        if( (sel_to == 0 and key == wx.WXK_BACK)
+            or (self._signOk and sel_to == 1 and value[0] == ' ' and key == wx.WXK_BACK)
+            or (sel_to == self._masklength and sel_start == sel_to and key == wx.WXK_DELETE and not field._insertRight)
             or (self._signOk and self._useParens
                 and sel_start == sel_to
                 and sel_to == self._masklength - 1
-                and value[sel_to] == ' ' and key == WXK_DELETE and not field._insertRight) ):
-            if not wxValidator_IsSilent():
-                wxBell()
-            dbg(indent=0)
+                and value[sel_to] == ' ' and key == wx.WXK_DELETE and not field._insertRight) ):
+            if not wx.Validator_IsSilent():
+                wx.Bell()
+##            dbg(indent=0)
             return False
 
 
@@ -3037,22 +3118,22 @@ class wxMaskedEditMixin:
             and sel_start >= start                              # and selection starts in field
             and ((sel_to == sel_start                           # and no selection
                   and sel_to == end                             # and cursor at right edge
-                  and key in (WXK_BACK, WXK_DELETE))            # and either delete or backspace key
+                  and key in (wx.WXK_BACK, wx.WXK_DELETE))            # and either delete or backspace key
                  or                                             # or
-                 (key == WXK_BACK                               # backspacing
+                 (key == wx.WXK_BACK                               # backspacing
                     and (sel_to == end                          # and selection ends at right edge
                          or sel_to < end and field._allowInsert)) ) ):  # or allow right insert at any point in field
 
-            dbg('delete left')
+##            dbg('delete left')
             # if backspace but left of cursor is empty, adjust cursor right before deleting
-            while( key == WXK_BACK
+            while( key == wx.WXK_BACK
                    and sel_start == sel_to
                    and sel_start < end
                    and value[start:sel_start] == self._template[start:sel_start]):
                 sel_start += 1
                 sel_to = sel_start
 
-            dbg('sel_start, start:', sel_start, start)
+##            dbg('sel_start, start:', sel_start, start)
 
             if sel_start == sel_to:
                 keep = sel_start -1
@@ -3066,7 +3147,7 @@ class wxMaskedEditMixin:
                 signchar = value[0]
                 newfield = signchar + newfield
                 move_sign_into_field = True
-            dbg('cut newfield: "%s"' % newfield)
+##            dbg('cut newfield: "%s"' % newfield)
 
             # handle what should fill in from the left:
             left = ""
@@ -3080,7 +3161,7 @@ class wxMaskedEditMixin:
                 else:
                     left += self._template[i]   # this can produce strange results in combination with default values...
             newfield = left + newfield
-            dbg('filled newfield: "%s"' % newfield)
+##            dbg('filled newfield: "%s"' % newfield)
 
             newstr = value[:start] + newfield + value[end:]
 
@@ -3098,7 +3179,7 @@ class wxMaskedEditMixin:
                 # selection (if any) falls within current insert-capable field:
                 select_len = sel_to - sel_start
                 # determine where cursor should end up:
-                if key == WXK_BACK:
+                if key == wx.WXK_BACK:
                     if select_len == 0:
                         newpos = sel_start -1
                     else:
@@ -3130,7 +3211,7 @@ class wxMaskedEditMixin:
                     erase_len = erase_to - newpos
 
                     left = value[start:newpos]
-                    dbg("retained ='%s'" % value[erase_to:end], 'sel_to:', sel_to, "fill: '%s'" % self._template[end - erase_len:end])
+##                    dbg("retained ='%s'" % value[erase_to:end], 'sel_to:', sel_to, "fill: '%s'" % self._template[end - erase_len:end])
                     right = value[erase_to:end] + self._template[end-erase_len:end]
                     pos_adjust = 0
                     if field._alignRight:
@@ -3148,24 +3229,24 @@ class wxMaskedEditMixin:
                     if pos_adjust:
                         newfield = newfield.rjust(end-start)
                         newpos += pos_adjust
-                    dbg("left='%s', right ='%s', newfield='%s'" %(left, right, newfield))
+##                    dbg("left='%s', right ='%s', newfield='%s'" %(left, right, newfield))
                     newstr = value[:start] + newfield + value[end:]
 
                 pos = newpos
 
             else:
                 if sel_start == sel_to:
-                    dbg("current sel_start, sel_to:", sel_start, sel_to)
-                    if key == WXK_BACK:
+##                    dbg("current sel_start, sel_to:", sel_start, sel_to)
+                    if key == wx.WXK_BACK:
                         sel_start, sel_to = sel_to-1, sel_to-1
-                        dbg("new sel_start, sel_to:", sel_start, sel_to)
+##                        dbg("new sel_start, sel_to:", sel_start, sel_to)
 
                     if field._padZero and not value[start:sel_to].replace('0', '').replace(' ','').replace(field._fillChar, ''):
                         # preceding chars (if any) are zeros, blanks or fillchar; new char should be 0:
                         newchar = '0'
                     else:
                         newchar = self._template[sel_to] ## get an original template character to "clear" the current char
-                    dbg('value = "%s"' % value, 'value[%d] = "%s"' %(sel_start, value[sel_start]))
+##                    dbg('value = "%s"' % value, 'value[%d] = "%s"' %(sel_start, value[sel_start]))
 
                     if self._isTemplateChar(sel_to):
                         if sel_to == 0 and self._signOk and value[sel_to] == '-':   # erasing "template" sign char
@@ -3202,36 +3283,38 @@ class wxMaskedEditMixin:
                 # erased right-sign marker; get rid of left-sign marker:
                 newstr = newstr[:left_signpos] + ' ' + newstr[left_signpos+1:]
 
-        dbg("oldstr:'%s'" % value, 'oldpos:', oldstart)
-        dbg("newstr:'%s'" % newstr, 'pos:', pos)
+##        dbg("oldstr:'%s'" % value, 'oldpos:', oldstart)
+##        dbg("newstr:'%s'" % newstr, 'pos:', pos)
 
         # if erasure results in an invalid field, disallow it:
-        dbg('field._validRequired?', field._validRequired)
-        dbg('field.IsValid("%s")?' % newstr[start:end], field.IsValid(newstr[start:end]))
+##        dbg('field._validRequired?', field._validRequired)
+##        dbg('field.IsValid("%s")?' % newstr[start:end], field.IsValid(newstr[start:end]))
         if field._validRequired and not field.IsValid(newstr[start:end]):
-            if not wxValidator_IsSilent():
-                wxBell()
-            dbg(indent=0)
+            if not wx.Validator_IsSilent():
+                wx.Bell()
+##            dbg(indent=0)
             return False
 
         # if erasure results in an invalid value, disallow it:
         if self._ctrl_constraints._validRequired and not self.IsValid(newstr):
-            if not wxValidator_IsSilent():
-                wxBell()
-            dbg(indent=0)
+            if not wx.Validator_IsSilent():
+                wx.Bell()
+##            dbg(indent=0)
             return False
 
-        dbg('setting value (later) to', newstr)
-        wxCallAfter(self._SetValue, newstr)
-        dbg('setting insertion point (later) to', pos)
-        wxCallAfter(self._SetInsertionPoint, pos)
-        dbg(indent=0)
+##        dbg('setting value (later) to', newstr)
+        wx.CallAfter(self._SetValue, newstr)
+##        dbg('setting insertion point (later) to', pos)
+        wx.CallAfter(self._SetInsertionPoint, pos)
+##        dbg(indent=0)
+        if newstr != value:
+            self.modified = True
         return False
 
 
     def _OnEnd(self,event):
         """ Handles End keypress in control. Should return False to skip other processing. """
-        dbg("wxMaskedEditMixin::_OnEnd", indent=1)
+##        dbg("MaskedEditMixin::_OnEnd", indent=1)
         pos = self._adjustPos(self._GetInsertionPoint(), event.GetKeyCode())
         if not event.ControlDown():
             end = self._masklength  # go to end of control
@@ -3248,48 +3331,51 @@ class wxMaskedEditMixin:
             # - cursor not in same field
             # - or at or past last input already
             # - or current selection = end of current field:
-##            dbg('field != field_end?', field != field_end)
-##            dbg('sel_to >= end_of_input?', sel_to >= end_of_input)
+####            dbg('field != field_end?', field != field_end)
+####            dbg('sel_to >= end_of_input?', sel_to >= end_of_input)
             if field != field_end or sel_to >= end_of_input:
                 edit_start, edit_end = field._extent
-##                dbg('edit_end:', edit_end)
-##                dbg('sel_to:', sel_to)
-##                dbg('sel_to == edit_end?', sel_to == edit_end)
-##                dbg('field._index < self._field_indices[-1]?', field._index < self._field_indices[-1])
+####                dbg('edit_end:', edit_end)
+####                dbg('sel_to:', sel_to)
+####                dbg('sel_to == edit_end?', sel_to == edit_end)
+####                dbg('field._index < self._field_indices[-1]?', field._index < self._field_indices[-1])
 
                 if sel_to == edit_end and field._index < self._field_indices[-1]:
                     edit_start, edit_end = self._FindFieldExtent(self._findNextEntry(edit_end))  # go to end of next field:
                     end = edit_end
-                    dbg('end moved to', end)
+##                    dbg('end moved to', end)
 
                 elif sel_to == edit_end and field._index == self._field_indices[-1]:
                     # already at edit end of last field; select to end of control:
                     end = self._masklength
-                    dbg('end moved to', end)
+##                    dbg('end moved to', end)
                 else:
                     end = edit_end  # select to end of current field
-                    dbg('end moved to ', end)
+##                    dbg('end moved to ', end)
             else:
                 # select to current end of input
                 end = end_of_input
 
 
-##        dbg('pos:', pos, 'end:', end)
+####        dbg('pos:', pos, 'end:', end)
 
         if event.ShiftDown():
             if not event.ControlDown():
-                dbg("shift-end; select to end of control")
+##                dbg("shift-end; select to end of control")
+                pass
             else:
-                dbg("shift-ctrl-end; select to end of non-whitespace")
-            wxCallAfter(self._SetInsertionPoint, pos)
-            wxCallAfter(self._SetSelection, pos, end)
+##                dbg("shift-ctrl-end; select to end of non-whitespace")
+                pass                
+            wx.CallAfter(self._SetInsertionPoint, pos)
+            wx.CallAfter(self._SetSelection, pos, end)
         else:
             if not event.ControlDown():
-                dbg('go to end of control:')
-            wxCallAfter(self._SetInsertionPoint, end)
-            wxCallAfter(self._SetSelection, end, end)
+##                dbg('go to end of control:')
+                pass
+            wx.CallAfter(self._SetInsertionPoint, end)
+            wx.CallAfter(self._SetSelection, end, end)
 
-        dbg(indent=0)
+##        dbg(indent=0)
         return False
 
 
@@ -3298,14 +3384,14 @@ class wxMaskedEditMixin:
          Changes the event to look like a tab event, so we can then call
          event.Skip() on it, and have the parent form "do the right thing."
          """
-         dbg('wxMaskedEditMixin::OnReturn')
-         event.m_keyCode = WXK_TAB
+##         dbg('MaskedEditMixin::OnReturn')
+         event.m_keyCode = wx.WXK_TAB
          event.Skip()
 
 
     def _OnHome(self,event):
         """ Handles Home keypress in control. Should return False to skip other processing."""
-        dbg("wxMaskedEditMixin::_OnHome", indent=1)
+##        dbg("MaskedEditMixin::_OnHome", indent=1)
         pos = self._adjustPos(self._GetInsertionPoint(), event.GetKeyCode())
         sel_start, sel_to = self._GetSelection()
 
@@ -3314,13 +3400,13 @@ class wxMaskedEditMixin:
         # 1) shift: select from start of control to end of current
         #    selection.
         if event.ShiftDown() and not event.ControlDown():
-            dbg("shift-home; select to start of control")
+##            dbg("shift-home; select to start of control")
             start = 0
             end = sel_start
 
         # 2) no shift, no control: move cursor to beginning of control.
         elif not event.ControlDown():
-            dbg("home; move to start of control")
+##            dbg("home; move to start of control")
             start = 0
             end = 0
 
@@ -3346,10 +3432,10 @@ class wxMaskedEditMixin:
                 start = 0
 
             if not event.ShiftDown():
-                dbg("ctrl-home; move to beginning of field")
+##                dbg("ctrl-home; move to beginning of field")
                 end = start
             else:
-                dbg("shift-ctrl-home; select to beginning of field")
+##                dbg("shift-ctrl-home; select to beginning of field")
                 end = sel_to
 
         else:
@@ -3368,12 +3454,12 @@ class wxMaskedEditMixin:
             else:
                 end = start
                 end_of_field = False
-            dbg("shift-ctrl-home; unselect to beginning of field")
+##            dbg("shift-ctrl-home; unselect to beginning of field")
 
-        dbg('queuing new sel_start, sel_to:', (start, end))
-        wxCallAfter(self._SetInsertionPoint, start)
-        wxCallAfter(self._SetSelection, start, end)
-        dbg(indent=0)
+##        dbg('queuing new sel_start, sel_to:', (start, end))
+        wx.CallAfter(self._SetInsertionPoint, start)
+        wx.CallAfter(self._SetSelection, start, end)
+##        dbg(indent=0)
         return False
 
 
@@ -3385,19 +3471,19 @@ class wxMaskedEditMixin:
         control-shift-TAB, these events are not sent to the controls
         by the framework.
         """
-        dbg('wxMaskedEditMixin::_OnChangeField', indent = 1)
+##        dbg('MaskedEditMixin::_OnChangeField', indent = 1)
         # determine end of current field:
         pos = self._GetInsertionPoint()
-        dbg('current pos:', pos)
+##        dbg('current pos:', pos)
         sel_start, sel_to = self._GetSelection()
 
         if self._masklength < 0:   # no fields; process tab normally
             self._AdjustField(pos)
-            if event.GetKeyCode() == WXK_TAB:
-                dbg('tab to next ctrl')
+            if event.GetKeyCode() == wx.WXK_TAB:
+##                dbg('tab to next ctrl')
                 event.Skip()
             #else: do nothing
-            dbg(indent=0)
+##            dbg(indent=0)
             return False
 
 
@@ -3407,46 +3493,46 @@ class wxMaskedEditMixin:
 
             # NOTE: doesn't yet work with SHIFT-tab under wx; the control
             # never sees this event! (But I've coded for it should it ever work,
-            # and it *does* work for '.' in wxIpAddrCtrl.)
+            # and it *does* work for '.' in IpAddrCtrl.)
             field = self._FindField(pos)
             index = field._index
             field_start = field._extent[0]
             if pos < field_start:
-                dbg('cursor before 1st field; cannot change to a previous field')
-                if not wxValidator_IsSilent():
-                    wxBell()
-                return false
+##                dbg('cursor before 1st field; cannot change to a previous field')
+                if not wx.Validator_IsSilent():
+                    wx.Bell()
+                return False
 
             if event.ControlDown():
-                dbg('queuing select to beginning of field:', field_start, pos)
-                wxCallAfter(self._SetInsertionPoint, field_start)
-                wxCallAfter(self._SetSelection, field_start, pos)
-                dbg(indent=0)
+##                dbg('queuing select to beginning of field:', field_start, pos)
+                wx.CallAfter(self._SetInsertionPoint, field_start)
+                wx.CallAfter(self._SetSelection, field_start, pos)
+##                dbg(indent=0)
                 return False
 
             elif index == 0:
                   # We're already in the 1st field; process shift-tab normally:
                 self._AdjustField(pos)
-                if event.GetKeyCode() == WXK_TAB:
-                    dbg('tab to previous ctrl')
+                if event.GetKeyCode() == wx.WXK_TAB:
+##                    dbg('tab to previous ctrl')
                     event.Skip()
                 else:
-                    dbg('position at beginning')
-                    wxCallAfter(self._SetInsertionPoint, field_start)
-                dbg(indent=0)
+##                    dbg('position at beginning')
+                    wx.CallAfter(self._SetInsertionPoint, field_start)
+##                dbg(indent=0)
                 return False
             else:
                 # find beginning of previous field:
                 begin_prev = self._FindField(field_start-1)._extent[0]
                 self._AdjustField(pos)
-                dbg('repositioning to', begin_prev)
-                wxCallAfter(self._SetInsertionPoint, begin_prev)
+##                dbg('repositioning to', begin_prev)
+                wx.CallAfter(self._SetInsertionPoint, begin_prev)
                 if self._FindField(begin_prev)._selectOnFieldEntry:
                     edit_start, edit_end = self._FindFieldExtent(begin_prev)
-                    dbg('queuing selection to (%d, %d)' % (edit_start, edit_end))
-                    wxCallAfter(self._SetInsertionPoint, edit_start)
-                    wxCallAfter(self._SetSelection, edit_start, edit_end)
-                dbg(indent=0)
+##                    dbg('queuing selection to (%d, %d)' % (edit_start, edit_end))
+                    wx.CallAfter(self._SetInsertionPoint, edit_start)
+                    wx.CallAfter(self._SetSelection, edit_start, edit_end)
+##                dbg(indent=0)
                 return False
 
         else:
@@ -3454,44 +3540,44 @@ class wxMaskedEditMixin:
             field = self._FindField(sel_to)
             field_start, field_end = field._extent
             if event.ControlDown():
-                dbg('queuing select to end of field:', pos, field_end)
-                wxCallAfter(self._SetInsertionPoint, pos)
-                wxCallAfter(self._SetSelection, pos, field_end)
-                dbg(indent=0)
+##                dbg('queuing select to end of field:', pos, field_end)
+                wx.CallAfter(self._SetInsertionPoint, pos)
+                wx.CallAfter(self._SetSelection, pos, field_end)
+##                dbg(indent=0)
                 return False
             else:
                 if pos < field_start:
-                    dbg('cursor before 1st field; go to start of field')
-                    wxCallAfter(self._SetInsertionPoint, field_start)
+##                    dbg('cursor before 1st field; go to start of field')
+                    wx.CallAfter(self._SetInsertionPoint, field_start)
                     if field._selectOnFieldEntry:
-                        wxCallAfter(self._SetSelection, field_start, field_end)
+                        wx.CallAfter(self._SetSelection, field_start, field_end)
                     else:
-                        wxCallAfter(self._SetSelection, field_start, field_start)
+                        wx.CallAfter(self._SetSelection, field_start, field_start)
                     return False
                 # else...
-                dbg('end of current field:', field_end)
-                dbg('go to next field')
+##                dbg('end of current field:', field_end)
+##                dbg('go to next field')
                 if field_end == self._fields[self._field_indices[-1]]._extent[1]:
                     self._AdjustField(pos)
-                    if event.GetKeyCode() == WXK_TAB:
-                        dbg('tab to next ctrl')
+                    if event.GetKeyCode() == wx.WXK_TAB:
+##                        dbg('tab to next ctrl')
                         event.Skip()
                     else:
-                        dbg('position at end')
-                        wxCallAfter(self._SetInsertionPoint, field_end)
-                    dbg(indent=0)
+##                        dbg('position at end')
+                        wx.CallAfter(self._SetInsertionPoint, field_end)
+##                    dbg(indent=0)
                     return False
                 else:
                     # we have to find the start of the next field
                     next_pos = self._findNextEntry(field_end)
                     if next_pos == field_end:
-                        dbg('already in last field')
+##                        dbg('already in last field')
                         self._AdjustField(pos)
-                        if event.GetKeyCode() == WXK_TAB:
-                            dbg('tab to next ctrl')
+                        if event.GetKeyCode() == wx.WXK_TAB:
+##                            dbg('tab to next ctrl')
                             event.Skip()
                         #else: do nothing
-                        dbg(indent=0)
+##                        dbg(indent=0)
                         return False
                     else:
                         self._AdjustField( pos )
@@ -3500,79 +3586,79 @@ class wxMaskedEditMixin:
                         field = self._FindField(next_pos)
                         edit_start, edit_end = field._extent
                         if field._selectOnFieldEntry:
-                            dbg('move to ', next_pos)
-                            wxCallAfter(self._SetInsertionPoint, next_pos)
+##                            dbg('move to ', next_pos)
+                            wx.CallAfter(self._SetInsertionPoint, next_pos)
                             edit_start, edit_end = self._FindFieldExtent(next_pos)
-                            dbg('queuing select', edit_start, edit_end)
-                            wxCallAfter(self._SetSelection, edit_start, edit_end)
+##                            dbg('queuing select', edit_start, edit_end)
+                            wx.CallAfter(self._SetSelection, edit_start, edit_end)
                         else:
                             if field._insertRight:
                                 next_pos = field._extent[1]
-                            dbg('move to ', next_pos)
-                            wxCallAfter(self._SetInsertionPoint, next_pos)
-                        dbg(indent=0)
+##                            dbg('move to ', next_pos)
+                            wx.CallAfter(self._SetInsertionPoint, next_pos)
+##                        dbg(indent=0)
                         return False
 
 
     def _OnDecimalPoint(self, event):
-        dbg('wxMaskedEditMixin::_OnDecimalPoint', indent=1)
+##        dbg('MaskedEditMixin::_OnDecimalPoint', indent=1)
 
         pos = self._adjustPos(self._GetInsertionPoint(), event.GetKeyCode())
 
         if self._isFloat:       ## handle float value, move to decimal place
-            dbg('key == Decimal tab; decimal pos:', self._decimalpos)
+##            dbg('key == Decimal tab; decimal pos:', self._decimalpos)
             value = self._GetValue()
             if pos < self._decimalpos:
                 clipped_text = value[0:pos] + self._decimalChar + value[self._decimalpos+1:]
-                dbg('value: "%s"' % self._GetValue(), "clipped_text:'%s'" % clipped_text)
+##                dbg('value: "%s"' % self._GetValue(), "clipped_text:'%s'" % clipped_text)
                 newstr = self._adjustFloat(clipped_text)
             else:
                 newstr = self._adjustFloat(value)
-            wxCallAfter(self._SetValue, newstr)
+            wx.CallAfter(self._SetValue, newstr)
             fraction = self._fields[1]
             start, end = fraction._extent
-            wxCallAfter(self._SetInsertionPoint, start)
+            wx.CallAfter(self._SetInsertionPoint, start)
             if fraction._selectOnFieldEntry:
-                dbg('queuing selection after decimal point to:', (start, end))
-                wxCallAfter(self._SetSelection, start, end)
+##                dbg('queuing selection after decimal point to:', (start, end))
+                wx.CallAfter(self._SetSelection, start, end)
             keep_processing = False
 
         if self._isInt:      ## handle integer value, truncate from current position
-            dbg('key == Integer decimal event')
+##            dbg('key == Integer decimal event')
             value = self._GetValue()
             clipped_text = value[0:pos]
-            dbg('value: "%s"' % self._GetValue(), "clipped_text:'%s'" % clipped_text)
+##            dbg('value: "%s"' % self._GetValue(), "clipped_text:'%s'" % clipped_text)
             newstr = self._adjustInt(clipped_text)
-            dbg('newstr: "%s"' % newstr)
-            wxCallAfter(self._SetValue, newstr)
+##            dbg('newstr: "%s"' % newstr)
+            wx.CallAfter(self._SetValue, newstr)
             newpos = len(newstr.rstrip())
             if newstr.find(')') != -1:
                 newpos -= 1     # (don't move past right paren)
-            wxCallAfter(self._SetInsertionPoint, newpos)
+            wx.CallAfter(self._SetInsertionPoint, newpos)
             keep_processing = False
-        dbg(indent=0)
+##        dbg(indent=0)
 
 
     def _OnChangeSign(self, event):
-        dbg('wxMaskedEditMixin::_OnChangeSign', indent=1)
+##        dbg('MaskedEditMixin::_OnChangeSign', indent=1)
         key = event.GetKeyCode()
         pos = self._adjustPos(self._GetInsertionPoint(), key)
         value = self._eraseSelection()
         integer = self._fields[0]
         start, end = integer._extent
 
-##        dbg('adjusted pos:', pos)
+####        dbg('adjusted pos:', pos)
         if chr(key) in ('-','+','(', ')') or (chr(key) == " " and pos == self._signpos):
             cursign = self._isNeg
-            dbg('cursign:', cursign)
+##            dbg('cursign:', cursign)
             if chr(key) in ('-','(', ')'):
                 self._isNeg = (not self._isNeg)   ## flip value
             else:
                 self._isNeg = False
-            dbg('isNeg?', self._isNeg)
+##            dbg('isNeg?', self._isNeg)
 
             text, self._signpos, self._right_signpos = self._getSignedValue(candidate=value)
-            dbg('text:"%s"' % text, 'signpos:', self._signpos, 'right_signpos:', self._right_signpos)
+##            dbg('text:"%s"' % text, 'signpos:', self._signpos, 'right_signpos:', self._right_signpos)
             if text is None:
                 text = value
 
@@ -3582,26 +3668,26 @@ class wxMaskedEditMixin:
                 else:
                     text = text[:self._signpos] + '-' + text[self._signpos+1:]
             else:
-##                dbg('self._isNeg?', self._isNeg, 'self.IsValid(%s)' % text, self.IsValid(text))
+####                dbg('self._isNeg?', self._isNeg, 'self.IsValid(%s)' % text, self.IsValid(text))
                 if self._useParens:
                     text = text[:self._signpos] + ' ' + text[self._signpos+1:self._right_signpos] + ' ' + text[self._right_signpos+1:]
                 else:
                     text = text[:self._signpos] + ' ' + text[self._signpos+1:]
-                dbg('clearing self._isNeg')
+##                dbg('clearing self._isNeg')
                 self._isNeg = False
 
-            wxCallAfter(self._SetValue, text)
-            wxCallAfter(self._applyFormatting)
-            dbg('pos:', pos, 'signpos:', self._signpos)
+            wx.CallAfter(self._SetValue, text)
+            wx.CallAfter(self._applyFormatting)
+##            dbg('pos:', pos, 'signpos:', self._signpos)
             if pos == self._signpos or integer.IsEmpty(text[start:end]):
-                wxCallAfter(self._SetInsertionPoint, self._signpos+1)
+                wx.CallAfter(self._SetInsertionPoint, self._signpos+1)
             else:
-                wxCallAfter(self._SetInsertionPoint, pos)
+                wx.CallAfter(self._SetInsertionPoint, pos)
 
             keep_processing = False
         else:
             keep_processing = True
-        dbg(indent=0)
+##        dbg(indent=0)
         return keep_processing
 
 
@@ -3610,29 +3696,29 @@ class wxMaskedEditMixin:
         This handler is only registered if the mask is a numeric mask.
         It allows the insertion of ',' or '.' if appropriate.
         """
-        dbg('wxMaskedEditMixin::_OnGroupChar', indent=1)
+##        dbg('MaskedEditMixin::_OnGroupChar', indent=1)
         keep_processing = True
         pos = self._adjustPos(self._GetInsertionPoint(), event.GetKeyCode())
         sel_start, sel_to = self._GetSelection()
         groupchar = self._fields[0]._groupChar
         if not self._isCharAllowed(groupchar, pos, checkRegex=True):
             keep_processing = False
-            if not wxValidator_IsSilent():
-                wxBell()
+            if not wx.Validator_IsSilent():
+                wx.Bell()
 
         if keep_processing:
             newstr, newpos = self._insertKey(groupchar, pos, sel_start, sel_to, self._GetValue() )
-            dbg("str with '%s' inserted:" % groupchar, '"%s"' % newstr)
+##            dbg("str with '%s' inserted:" % groupchar, '"%s"' % newstr)
             if self._ctrl_constraints._validRequired and not self.IsValid(newstr):
                 keep_processing = False
-                if not wxValidator_IsSilent():
-                        wxBell()
+                if not wx.Validator_IsSilent():
+                        wx.Bell()
 
         if keep_processing:
-            wxCallAfter(self._SetValue, newstr)
-            wxCallAfter(self._SetInsertionPoint, newpos)
+            wx.CallAfter(self._SetValue, newstr)
+            wx.CallAfter(self._SetInsertionPoint, newpos)
         keep_processing = False
-        dbg(indent=0)
+##        dbg(indent=0)
         return keep_processing
 
 
@@ -3666,7 +3752,7 @@ class wxMaskedEditMixin:
 
 
     def _OnAutoCompleteField(self, event):
-        dbg('wxMaskedEditMixin::_OnAutoCompleteField', indent =1)
+##        dbg('MaskedEditMixin::_OnAutoCompleteField', indent =1)
         pos = self._GetInsertionPoint()
         field = self._FindField(pos)
         edit_start, edit_end, slice = self._FindFieldExtent(pos, getslice=True)
@@ -3680,42 +3766,42 @@ class wxMaskedEditMixin:
             text = slice
         text = text.strip()
         keep_processing = True  # (assume True to start)
-        dbg('field._hasList?', field._hasList)
+##        dbg('field._hasList?', field._hasList)
         if field._hasList:
-            dbg('choices:', field._choices)
-            dbg('compareChoices:', field._compareChoices)
+##            dbg('choices:', field._choices)
+##            dbg('compareChoices:', field._compareChoices)
             choices, choice_required = field._compareChoices, field._choiceRequired
-            if keycode in (WXK_PRIOR, WXK_UP):
+            if keycode in (wx.WXK_PRIOR, wx.WXK_UP):
                 direction = -1
             else:
                 direction = 1
             match_index, partial_match = self._autoComplete(direction, choices, text, compareNoCase=field._compareNoCase, current_index = field._autoCompleteIndex)
             if( match_index is None
-                and (keycode in self._autoCompleteKeycodes + [WXK_PRIOR, WXK_NEXT]
-                     or (keycode in [WXK_UP, WXK_DOWN] and event.ShiftDown() ) ) ):
+                and (keycode in self._autoCompleteKeycodes + [wx.WXK_PRIOR, wx.WXK_NEXT]
+                     or (keycode in [wx.WXK_UP, wx.WXK_DOWN] and event.ShiftDown() ) ) ):
                 # Select the 1st thing from the list:
                 match_index = 0
 
             if( match_index is not None
-                and ( keycode in self._autoCompleteKeycodes + [WXK_PRIOR, WXK_NEXT]
-                      or (keycode in [WXK_UP, WXK_DOWN] and event.ShiftDown())
-                      or (keycode == WXK_DOWN and partial_match) ) ):
+                and ( keycode in self._autoCompleteKeycodes + [wx.WXK_PRIOR, wx.WXK_NEXT]
+                      or (keycode in [wx.WXK_UP, wx.WXK_DOWN] and event.ShiftDown())
+                      or (keycode == wx.WXK_DOWN and partial_match) ) ):
 
                 # We're allowed to auto-complete:
-                dbg('match found')
+##                dbg('match found')
                 value = self._GetValue()
                 newvalue = value[:edit_start] + field._choices[match_index] + value[edit_end:]
-                dbg('setting value to "%s"' % newvalue)
+##                dbg('setting value to "%s"' % newvalue)
                 self._SetValue(newvalue)
                 self._SetInsertionPoint(min(edit_end, len(newvalue.rstrip())))
                 self._OnAutoSelect(field, match_index)
                 self._CheckValid()  # recolor as appopriate
 
 
-        if keycode in (WXK_UP, WXK_DOWN, WXK_LEFT, WXK_RIGHT):
+        if keycode in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT, wx.WXK_RIGHT):
             # treat as left right arrow if unshifted, tab/shift tab if shifted.
             if event.ShiftDown():
-                if keycode in (WXK_DOWN, WXK_RIGHT):
+                if keycode in (wx.WXK_DOWN, wx.WXK_RIGHT):
                     # remove "shifting" and treat as (forward) tab:
                     event.m_shiftDown = False
                 keep_processing = self._OnChangeField(event)
@@ -3723,7 +3809,7 @@ class wxMaskedEditMixin:
                 keep_processing = self._OnArrow(event)
         # else some other key; keep processing the key
 
-        dbg('keep processing?', keep_processing, indent=0)
+##        dbg('keep processing?', keep_processing, indent=0)
         return keep_processing
 
 
@@ -3732,7 +3818,7 @@ class wxMaskedEditMixin:
         Function called if autoselect feature is enabled and entire control
         is selected:
         """
-        dbg('wxMaskedEditMixin::OnAutoSelect', field._index)
+##        dbg('MaskedEditMixin::OnAutoSelect', field._index)
         if match_index is not None:
             field._autoCompleteIndex = match_index
 
@@ -3749,9 +3835,9 @@ class wxMaskedEditMixin:
         The function returns a 2-tuple, with the 2nd element being a boolean
         that indicates if partial match was necessary.
         """
-        dbg('autoComplete(direction=', direction, 'choices=',choices, 'value=',value,'compareNoCase?', compareNoCase, 'current_index:', current_index, indent=1)
+##        dbg('autoComplete(direction=', direction, 'choices=',choices, 'value=',value,'compareNoCase?', compareNoCase, 'current_index:', current_index, indent=1)
         if value is None:
-            dbg('nothing to match against', indent=0)
+##            dbg('nothing to match against', indent=0)
             return (None, False)
 
         partial_match = False
@@ -3761,28 +3847,28 @@ class wxMaskedEditMixin:
 
         last_index = len(choices) - 1
         if value in choices:
-            dbg('"%s" in', choices)
+##            dbg('"%s" in', choices)
             if current_index is not None and choices[current_index] == value:
                 index = current_index
             else:
                 index = choices.index(value)
 
-            dbg('matched "%s" (%d)' % (choices[index], index))
+##            dbg('matched "%s" (%d)' % (choices[index], index))
             if direction == -1:
-                dbg('going to previous')
+##                dbg('going to previous')
                 if index == 0: index = len(choices) - 1
                 else: index -= 1
             else:
                 if index == len(choices) - 1: index = 0
                 else: index += 1
-            dbg('change value to "%s" (%d)' % (choices[index], index))
+##            dbg('change value to "%s" (%d)' % (choices[index], index))
             match = index
         else:
             partial_match = True
             value = value.strip()
-            dbg('no match; try to auto-complete:')
+##            dbg('no match; try to auto-complete:')
             match = None
-            dbg('searching for "%s"' % value)
+##            dbg('searching for "%s"' % value)
             if current_index is None:
                 indices = range(len(choices))
                 if direction == -1:
@@ -3790,23 +3876,25 @@ class wxMaskedEditMixin:
             else:
                 if direction == 1:
                     indices = range(current_index +1, len(choices)) + range(current_index+1)
-                    dbg('range(current_index+1 (%d), len(choices) (%d)) + range(%d):' % (current_index+1, len(choices), current_index+1), indices)
+##                    dbg('range(current_index+1 (%d), len(choices) (%d)) + range(%d):' % (current_index+1, len(choices), current_index+1), indices)
                 else:
                     indices = range(current_index-1, -1, -1) + range(len(choices)-1, current_index-1, -1)
-                    dbg('range(current_index-1 (%d), -1) + range(len(choices)-1 (%d)), current_index-1 (%d):' % (current_index-1, len(choices)-1, current_index-1), indices)
-##            dbg('indices:', indices)
+##                    dbg('range(current_index-1 (%d), -1) + range(len(choices)-1 (%d)), current_index-1 (%d):' % (current_index-1, len(choices)-1, current_index-1), indices)
+####            dbg('indices:', indices)
             for index in indices:
                 choice = choices[index]
                 if choice.find(value, 0) == 0:
-                    dbg('match found:', choice)
+##                    dbg('match found:', choice)
                     match = index
                     break
                 else: dbg('choice: "%s" - no match' % choice)
             if match is not None:
-                dbg('matched', match)
+##                dbg('matched', match)
+                pass
             else:
-                dbg('no match found')
-        dbg(indent=0)
+##                dbg('no match found')
+                pass
+##        dbg(indent=0)
         return (match, partial_match)
 
 
@@ -3863,31 +3951,31 @@ class wxMaskedEditMixin:
         Checks the current insertion point position and adjusts it if
         necessary to skip over non-editable characters.
         """
-        dbg('_adjustPos', pos, key, indent=1)
+##        dbg('_adjustPos', pos, key, indent=1)
         sel_start, sel_to = self._GetSelection()
         # If a numeric or decimal mask, and negatives allowed, reserve the
         # first space for sign, and last one if using parens.
         if( self._signOk
             and ((pos == self._signpos and key in (ord('-'), ord('+'), ord(' ')) )
                  or self._useParens and pos == self._masklength -1)):
-            dbg('adjusted pos:', pos, indent=0)
+##            dbg('adjusted pos:', pos, indent=0)
             return pos
 
         if key not in self._nav:
             field = self._FindField(pos)
 
-            dbg('field._insertRight?', field._insertRight)
+##            dbg('field._insertRight?', field._insertRight)
             if field._insertRight:              # if allow right-insert
                 start, end = field._extent
                 slice = self._GetValue()[start:end].strip()
                 field_len = end - start
                 if pos == end:                      # if cursor at right edge of field
                     # if not filled or supposed to stay in field, keep current position
-##                    dbg('pos==end')
-##                    dbg('len (slice):', len(slice))
-##                    dbg('field_len?', field_len)
-##                    dbg('pos==end; len (slice) < field_len?', len(slice) < field_len)
-##                    dbg('not field._moveOnFieldFull?', not field._moveOnFieldFull)
+####                    dbg('pos==end')
+####                    dbg('len (slice):', len(slice))
+####                    dbg('field_len?', field_len)
+####                    dbg('pos==end; len (slice) < field_len?', len(slice) < field_len)
+####                    dbg('not field._moveOnFieldFull?', not field._moveOnFieldFull)
                     if len(slice) == field_len and field._moveOnFieldFull:
                         # move cursor to next field:
                         pos = self._findNextEntry(pos)
@@ -3933,7 +4021,7 @@ class wxMaskedEditMixin:
                     self._SetInsertionPoint(pos)
                     if pos < sel_to:    # restore selection
                         self._SetSelection(pos, sel_to)
-        dbg('adjusted pos:', pos, indent=0)
+##        dbg('adjusted pos:', pos, indent=0)
         return pos
 
 
@@ -3941,24 +4029,24 @@ class wxMaskedEditMixin:
         """
         'Fixes' an floating point control. Collapses spaces, right-justifies, etc.
         """
-        dbg('wxMaskedEditMixin::_adjustFloat, candidate = "%s"' % candidate, indent=1)
+##        dbg('MaskedEditMixin::_adjustFloat, candidate = "%s"' % candidate, indent=1)
         lenInt,lenFraction  = [len(s) for s in self._mask.split('.')]  ## Get integer, fraction lengths
 
         if candidate is None: value = self._GetValue()
         else: value = candidate
-        dbg('value = "%(value)s"' % locals(), 'len(value):', len(value))
+##        dbg('value = "%(value)s"' % locals(), 'len(value):', len(value))
         intStr, fracStr = value.split(self._decimalChar)
 
         intStr = self._fields[0]._AdjustField(intStr)
-        dbg('adjusted intStr: "%s"' % intStr)
+##        dbg('adjusted intStr: "%s"' % intStr)
         lenInt = len(intStr)
         fracStr = fracStr + ('0'*(lenFraction-len(fracStr)))  # add trailing spaces to decimal
 
-        dbg('intStr "%(intStr)s"' % locals())
-        dbg('lenInt:', lenInt)
+##        dbg('intStr "%(intStr)s"' % locals())
+##        dbg('lenInt:', lenInt)
 
         intStr = string.rjust( intStr[-lenInt:], lenInt)
-        dbg('right-justifed intStr = "%(intStr)s"' % locals())
+##        dbg('right-justifed intStr = "%(intStr)s"' % locals())
         newvalue = intStr + self._decimalChar + fracStr
 
         if self._signOk:
@@ -3980,23 +4068,23 @@ class wxMaskedEditMixin:
             else:
                 newvalue = newvalue[:-1] + ' '
 
-        dbg('newvalue = "%s"' % newvalue)
+##        dbg('newvalue = "%s"' % newvalue)
         if candidate is None:
-            wxCallAfter(self._SetValue, newvalue)
-        dbg(indent=0)
+            wx.CallAfter(self._SetValue, newvalue)
+##        dbg(indent=0)
         return newvalue
 
 
     def _adjustInt(self, candidate=None):
         """ 'Fixes' an integer control. Collapses spaces, right or left-justifies."""
-        dbg("wxMaskedEditMixin::_adjustInt", candidate)
+##        dbg("MaskedEditMixin::_adjustInt", candidate)
         lenInt = self._masklength
         if candidate is None: value = self._GetValue()
         else: value = candidate
 
         intStr = self._fields[0]._AdjustField(value)
         intStr = intStr.strip() # drop extra spaces
-        dbg('adjusted field: "%s"' % intStr)
+##        dbg('adjusted field: "%s"' % intStr)
 
         if self._isNeg and intStr.find('-') == -1 and intStr.find('(') == -1:
             if self._useParens:
@@ -4022,7 +4110,7 @@ class wxMaskedEditMixin:
             intStr = intStr.ljust( lenInt )
 
         if candidate is None:
-            wxCallAfter(self._SetValue, intStr )
+            wx.CallAfter(self._SetValue, intStr )
         return intStr
 
 
@@ -4031,20 +4119,20 @@ class wxMaskedEditMixin:
         'Fixes' a date control, expanding the year if it can.
         Applies various self-formatting options.
         """
-        dbg("wxMaskedEditMixin::_adjustDate", indent=1)
+##        dbg("MaskedEditMixin::_adjustDate", indent=1)
         if candidate is None: text    = self._GetValue()
         else: text = candidate
-        dbg('text=', text)
+##        dbg('text=', text)
         if self._datestyle == "YMD":
             year_field = 0
         else:
             year_field = 2
 
-        dbg('getYear: "%s"' % getYear(text, self._datestyle))
+##        dbg('getYear: "%s"' % getYear(text, self._datestyle))
         year    = string.replace( getYear( text, self._datestyle),self._fields[year_field]._fillChar,"")  # drop extra fillChars
         month   = getMonth( text, self._datestyle)
         day     = getDay( text, self._datestyle)
-        dbg('self._datestyle:', self._datestyle, 'year:', year, 'Month', month, 'day:', day)
+##        dbg('self._datestyle:', self._datestyle, 'year:', year, 'Month', month, 'day:', day)
 
         yearVal = None
         yearstart = self._dateExtent - 4
@@ -4058,14 +4146,14 @@ class wxMaskedEditMixin:
             try:
                 yearVal = int(year)
             except:
-                dbg('bad year=', year)
+##                dbg('bad year=', year)
                 year = text[yearstart:self._dateExtent]
 
         if len(year) < 4 and yearVal:
             if len(year) == 2:
                 # Fix year adjustment to be less "20th century" :-) and to adjust heuristic as the
                 # years pass...
-                now = wxDateTime_Now()
+                now = wx.DateTime_Now()
                 century = (now.GetYear() /100) * 100        # "this century"
                 twodig_year = now.GetYear() - century       # "this year" (2 digits)
                 # if separation between today's 2-digit year and typed value > 50,
@@ -4085,22 +4173,22 @@ class wxMaskedEditMixin:
                 year = "%04d" % yearVal
             if self._4digityear or force4digit_year:
                 text = makeDate(year, month, day, self._datestyle, text) + text[self._dateExtent:]
-        dbg('newdate: "%s"' % text, indent=0)
+##        dbg('newdate: "%s"' % text, indent=0)
         return text
 
 
     def _goEnd(self, getPosOnly=False):
         """ Moves the insertion point to the end of user-entry """
-        dbg("wxMaskedEditMixin::_goEnd; getPosOnly:", getPosOnly, indent=1)
+##        dbg("MaskedEditMixin::_goEnd; getPosOnly:", getPosOnly, indent=1)
         text = self._GetValue()
-##        dbg('text: "%s"' % text)
+####        dbg('text: "%s"' % text)
         i = 0
         if len(text.rstrip()):
             for i in range( min( self._masklength-1, len(text.rstrip())), -1, -1):
-##                dbg('i:', i, 'self._isMaskChar(%d)' % i, self._isMaskChar(i))
+####                dbg('i:', i, 'self._isMaskChar(%d)' % i, self._isMaskChar(i))
                 if self._isMaskChar(i):
                     char = text[i]
-##                    dbg("text[%d]: '%s'" % (i, char))
+####                    dbg("text[%d]: '%s'" % (i, char))
                     if char != ' ':
                         i += 1
                         break
@@ -4114,8 +4202,8 @@ class wxMaskedEditMixin:
         start, end = field._extent
         if field._insertRight and pos < end:
             pos = end
-        dbg('next pos:', pos)
-        dbg(indent=0)
+##        dbg('next pos:', pos)
+##        dbg(indent=0)
         if getPosOnly:
             return pos
         else:
@@ -4124,13 +4212,13 @@ class wxMaskedEditMixin:
 
     def _goHome(self, getPosOnly=False):
         """ Moves the insertion point to the beginning of user-entry """
-        dbg("wxMaskedEditMixin::_goHome; getPosOnly:", getPosOnly, indent=1)
+##        dbg("MaskedEditMixin::_goHome; getPosOnly:", getPosOnly, indent=1)
         text = self._GetValue()
         for i in range(self._masklength):
             if self._isMaskChar(i):
                 break
         pos = max(i, 0)
-        dbg(indent=0)
+##        dbg(indent=0)
         if getPosOnly:
             return pos
         else:
@@ -4149,7 +4237,7 @@ class wxMaskedEditMixin:
             okchars += " "
         if okchars and field._includeChars:      ## any additional included characters?
             okchars += field._includeChars
-##        dbg('okchars[%d]:' % pos, okchars)
+####        dbg('okchars[%d]:' % pos, okchars)
         return okchars
 
 
@@ -4173,7 +4261,7 @@ class wxMaskedEditMixin:
 
     def _isCharAllowed(self, char, pos, checkRegex=False, allowAutoSelect=True, ignoreInsertRight=False):
         """ Returns True if character is allowed at the specific position, otherwise False."""
-        dbg('_isCharAllowed', char, pos, checkRegex, indent=1)
+##        dbg('_isCharAllowed', char, pos, checkRegex, indent=1)
         field = self._FindField(pos)
         right_insert = False
 
@@ -4204,21 +4292,21 @@ class wxMaskedEditMixin:
             if( (sel_start, sel_to) == field._extent
                 or (pos == end and input_len < field_len)):
                 pos = end - 1
-                dbg('pos = end - 1 = ', pos, 'right_insert? 1')
+##                dbg('pos = end - 1 = ', pos, 'right_insert? 1')
                 right_insert = True
             elif( field._allowInsert and sel_start == sel_to
                   and (sel_to == end or (sel_to < self._masklength and value[sel_start] != field._fillChar))
                   and input_len < field_len ):
                 pos = sel_to - 1    # where character will go
-                dbg('pos = sel_to - 1 = ', pos, 'right_insert? 1')
+##                dbg('pos = sel_to - 1 = ', pos, 'right_insert? 1')
                 right_insert = True
             # else leave pos alone...
             else:
-                dbg('pos stays ', pos, 'right_insert? 0')
-
+##                dbg('pos stays ', pos, 'right_insert? 0')
+                pass
 
         if self._isTemplateChar( pos ):  ## if a template character, return empty
-            dbg('%d is a template character; returning false' % pos, indent=0)
+##            dbg('%d is a template character; returning False' % pos, indent=0)
             return False
 
         if self._isMaskChar( pos ):
@@ -4235,11 +4323,11 @@ class wxMaskedEditMixin:
                 elif self._useParens and (self._isInt or (self._isFloat and pos > self._decimalpos)):
                     okChars += ')'
 
-##            dbg('%s in %s?' % (char, okChars), char in okChars)
+####            dbg('%s in %s?' % (char, okChars), char in okChars)
             approved = char in okChars
 
             if approved and checkRegex:
-                dbg("checking appropriate regex's")
+##                dbg("checking appropriate regex's")
                 value = self._eraseSelection(self._GetValue())
                 if right_insert:
                     at = pos+1
@@ -4249,21 +4337,21 @@ class wxMaskedEditMixin:
                     newvalue, ignore, ignore, ignore, ignore = self._insertKey(char, at, sel_start, sel_to, value, allowAutoSelect=True)
                 else:
                     newvalue, ignore = self._insertKey(char, at, sel_start, sel_to, value)
-                dbg('newvalue: "%s"' % newvalue)
+##                dbg('newvalue: "%s"' % newvalue)
 
                 fields = [self._FindField(pos)] + [self._ctrl_constraints]
                 for field in fields:    # includes fields[-1] == "ctrl_constraints"
                     if field._regexMask and field._filter:
-                        dbg('checking vs. regex')
+##                        dbg('checking vs. regex')
                         start, end = field._extent
                         slice = newvalue[start:end]
                         approved = (re.match( field._filter, slice) is not None)
-                        dbg('approved?', approved)
+##                        dbg('approved?', approved)
                     if not approved: break
-            dbg(indent=0)
+##            dbg(indent=0)
             return approved
         else:
-            dbg('%d is a !???! character; returning false', indent=0)
+##            dbg('%d is a !???! character; returning False', indent=0)
             return False
 
 
@@ -4272,22 +4360,22 @@ class wxMaskedEditMixin:
             Need to find a way to call this whenever the value changes, in case the control's
             value has been changed or set programatically.
         """
-        dbg(suspend=1)
-        dbg('wxMaskedEditMixin::_applyFormatting', indent=1)
+##        dbg(suspend=1)
+##        dbg('MaskedEditMixin::_applyFormatting', indent=1)
 
         # Handle negative numbers
         if self._signOk:
             text, signpos, right_signpos = self._getSignedValue()
-            dbg('text: "%s", signpos:' % text, signpos)
+##            dbg('text: "%s", signpos:' % text, signpos)
             if not text or text[signpos] not in ('-','('):
                 self._isNeg = False
-                dbg('no valid sign found; new sign:', self._isNeg)
+##                dbg('no valid sign found; new sign:', self._isNeg)
                 if text and signpos != self._signpos:
                     self._signpos = signpos
             elif text and self._valid and not self._isNeg and text[signpos] in ('-', '('):
-                dbg('setting _isNeg to True')
+##                dbg('setting _isNeg to True')
                 self._isNeg = True
-            dbg('self._isNeg:', self._isNeg)
+##            dbg('self._isNeg:', self._isNeg)
 
         if self._signOk and self._isNeg:
             fc = self._signedForegroundColour
@@ -4298,32 +4386,32 @@ class wxMaskedEditMixin:
             c =fc._name
         else:
             c = fc
-        dbg('setting foreground to', c)
+##        dbg('setting foreground to', c)
         self.SetForegroundColour(fc)
 
         if self._valid:
-            dbg('valid')
+##            dbg('valid')
             if self.IsEmpty():
                 bc = self._emptyBackgroundColour
             else:
                 bc = self._validBackgroundColour
         else:
-            dbg('invalid')
+##            dbg('invalid')
             bc = self._invalidBackgroundColour
         if hasattr(bc, '_name'):
             c =bc._name
         else:
             c = bc
-        dbg('setting background to', c)
+##        dbg('setting background to', c)
         self.SetBackgroundColour(bc)
         self._Refresh()
-        dbg(indent=0, suspend=0)
+##        dbg(indent=0, suspend=0)
 
 
     def _getAbsValue(self, candidate=None):
         """ Return an unsigned value (i.e. strip the '-' prefix if any), and sign position(s).
         """
-        dbg('wxMaskedEditMixin::_getAbsValue; candidate="%s"' % candidate, indent=1)
+##        dbg('MaskedEditMixin::_getAbsValue; candidate="%s"' % candidate, indent=1)
         if candidate is None: text = self._GetValue()
         else: text = candidate
         right_signpos = text.find(')')
@@ -4332,14 +4420,15 @@ class wxMaskedEditMixin:
             if self._ctrl_constraints._alignRight and self._fields[0]._fillChar == ' ':
                 signpos = text.find('-')
                 if signpos == -1:
-                    dbg('no - found; searching for (')
+##                    dbg('no - found; searching for (')
                     signpos = text.find('(')
                 elif signpos != -1:
-                    dbg('- found at', signpos)
+##                    dbg('- found at', signpos)
+                    pass
 
                 if signpos == -1:
-                    dbg('signpos still -1')
-                    dbg('len(%s) (%d) < len(%s) (%d)?' % (text, len(text), self._mask, self._masklength), len(text) < self._masklength)
+##                    dbg('signpos still -1')
+##                    dbg('len(%s) (%d) < len(%s) (%d)?' % (text, len(text), self._mask, self._masklength), len(text) < self._masklength)
                     if len(text) < self._masklength:
                         text = ' ' + text
                     if len(text) < self._masklength:
@@ -4347,13 +4436,13 @@ class wxMaskedEditMixin:
                     if len(text) > self._masklength and text[-1] in (')', ' '):
                         text = text[:-1]
                     else:
-                        dbg('len(%s) (%d), len(%s) (%d)' % (text, len(text), self._mask, self._masklength))
-                        dbg('len(%s) - (len(%s) + 1):' % (text, text.lstrip()) , len(text) - (len(text.lstrip()) + 1))
+##                        dbg('len(%s) (%d), len(%s) (%d)' % (text, len(text), self._mask, self._masklength))
+##                        dbg('len(%s) - (len(%s) + 1):' % (text, text.lstrip()) , len(text) - (len(text.lstrip()) + 1))
                         signpos = len(text) - (len(text.lstrip()) + 1)
 
                         if self._useParens and not text.strip():
                             signpos -= 1    # empty value; use penultimate space
-                dbg('signpos:', signpos)
+##                dbg('signpos:', signpos)
                 if signpos >= 0:
                     text = text[:signpos] + ' ' + text[signpos+1:]
 
@@ -4376,25 +4465,25 @@ class wxMaskedEditMixin:
                 # figure out where it ought to go:
                 right_signpos = self._masklength - 1     # initial guess
                 if not self._ctrl_constraints._alignRight:
-                    dbg('not right-aligned')
+##                    dbg('not right-aligned')
                     if len(text.strip()) == 0:
                         right_signpos = signpos + 1
                     elif len(text.strip()) < self._masklength:
                         right_signpos = len(text.rstrip())
-                dbg('right_signpos:', right_signpos)
+##                dbg('right_signpos:', right_signpos)
 
             groupchar = self._fields[0]._groupChar
             try:
                 value = long(text.replace(groupchar,'').replace('(','-').replace(')','').replace(' ', ''))
             except:
-                dbg('invalid number', indent=0)
+##                dbg('invalid number', indent=0)
                 return None, signpos, right_signpos
 
         else:   # float value
             try:
                 groupchar = self._fields[0]._groupChar
                 value = float(text.replace(groupchar,'').replace(self._decimalChar, '.').replace('(', '-').replace(')','').replace(' ', ''))
-                dbg('value:', value)
+##                dbg('value:', value)
             except:
                 value = None
 
@@ -4406,15 +4495,16 @@ class wxMaskedEditMixin:
                 text = text[:signpos] + self._template[signpos] + text[signpos+1:]
             else:
                 # look forwards up to the decimal point for the 1st non-digit
-                dbg('decimal pos:', self._decimalpos)
-                dbg('text: "%s"' % text)
+##                dbg('decimal pos:', self._decimalpos)
+##                dbg('text: "%s"' % text)
                 if self._signOk:
                     signpos = self._decimalpos - (len(text[:self._decimalpos].lstrip()) + 1)
-                    if text[signpos+1] in ('-','('):
+                    # prevent checking for empty string - Tomo - Wed 14 Jan 2004 03:19:09 PM CET
+                    if len(text) >= signpos+1 and  text[signpos+1] in ('-','('):
                         signpos += 1
                 else:
                     signpos = -1
-                dbg('signpos:', signpos)
+##                dbg('signpos:', signpos)
 
             if self._useParens:
                 if self._signOk:
@@ -4429,11 +4519,11 @@ class wxMaskedEditMixin:
                         right_signpos = -1
 
             if value is None:
-                dbg('invalid number')
+##                dbg('invalid number')
                 text = None
 
-        dbg('abstext = "%s"' % text, 'signpos:', signpos, 'right_signpos:', right_signpos)
-        dbg(indent=0)
+##        dbg('abstext = "%s"' % text, 'signpos:', signpos, 'right_signpos:', right_signpos)
+##        dbg(indent=0)
         return text, signpos, right_signpos
 
 
@@ -4441,7 +4531,7 @@ class wxMaskedEditMixin:
         """ Return a signed value by adding a "-" prefix if the value
             is set to negative, or a space if positive.
         """
-        dbg('wxMaskedEditMixin::_getSignedValue; candidate="%s"' % candidate, indent=1)
+##        dbg('MaskedEditMixin::_getSignedValue; candidate="%s"' % candidate, indent=1)
         if candidate is None: text = self._GetValue()
         else: text = candidate
 
@@ -4449,7 +4539,7 @@ class wxMaskedEditMixin:
         abstext, signpos, right_signpos = self._getAbsValue(text)
         if self._signOk:
             if abstext is None:
-                dbg(indent=0)
+##                dbg(indent=0)
                 return abstext, signpos, right_signpos
 
             if self._isNeg or text[signpos] in ('-', '('):
@@ -4469,22 +4559,22 @@ class wxMaskedEditMixin:
                 text = text[:right_signpos] + ')' + text[right_signpos+1:]
         else:
             text = abstext
-        dbg('signedtext = "%s"' % text, 'signpos:', signpos, 'right_signpos', right_signpos)
-        dbg(indent=0)
+##        dbg('signedtext = "%s"' % text, 'signpos:', signpos, 'right_signpos', right_signpos)
+##        dbg(indent=0)
         return text, signpos, right_signpos
 
 
     def GetPlainValue(self, candidate=None):
         """ Returns control's value stripped of the template text.
-            plainvalue = wxMaskedEditMixin.GetPlainValue()
+            plainvalue = MaskedEditMixin.GetPlainValue()
         """
-        dbg('wxMaskedEditMixin::GetPlainValue; candidate="%s"' % candidate, indent=1)
+##        dbg('MaskedEditMixin::GetPlainValue; candidate="%s"' % candidate, indent=1)
 
         if candidate is None: text = self._GetValue()
         else: text = candidate
 
         if self.IsEmpty():
-            dbg('returned ""', indent=0)
+##            dbg('returned ""', indent=0)
             return ""
         else:
             plain = ""
@@ -4493,9 +4583,9 @@ class wxMaskedEditMixin:
                     plain += text[idx]
 
             if self._isFloat or self._isInt:
-                dbg('plain so far: "%s"' % plain)
+##                dbg('plain so far: "%s"' % plain)
                 plain = plain.replace('(', '-').replace(')', ' ')
-                dbg('plain after sign regularization: "%s"' % plain)
+##                dbg('plain after sign regularization: "%s"' % plain)
 
                 if self._signOk and self._isNeg and plain.count('-') == 0:
                     # must be in reserved position; add to "plain value"
@@ -4506,9 +4596,9 @@ class wxMaskedEditMixin:
                     plain = ' ' * lpad + plain.replace(',','')
                 else:
                     plain = plain.replace(',','')
-                dbg('plain after pad and group:"%s"' % plain)
+##                dbg('plain after pad and group:"%s"' % plain)
 
-            dbg('returned "%s"' % plain.rstrip(), indent=0)
+##            dbg('returned "%s"' % plain.rstrip(), indent=0)
             return plain.rstrip()
 
 
@@ -4519,19 +4609,19 @@ class wxMaskedEditMixin:
         """
         if value is None: value = self._GetValue()
         if value == self._template and not self._defaultValue:
-##            dbg("IsEmpty? 1 (value == self._template and not self._defaultValue)")
+####            dbg("IsEmpty? 1 (value == self._template and not self._defaultValue)")
             return True     # (all mask chars == fillChar by defn)
         elif value == self._template:
             empty = True
             for pos in range(len(self._template)):
-##                dbg('isMaskChar(%(pos)d)?' % locals(), self._isMaskChar(pos))
-##                dbg('value[%(pos)d] != self._fillChar?' %locals(), value[pos] != self._fillChar[pos])
+####                dbg('isMaskChar(%(pos)d)?' % locals(), self._isMaskChar(pos))
+####                dbg('value[%(pos)d] != self._fillChar?' %locals(), value[pos] != self._fillChar[pos])
                 if self._isMaskChar(pos) and value[pos] not in (' ', self._fillChar[pos]):
                     empty = False
-##            dbg("IsEmpty? %(empty)d (do all mask chars == fillChar?)" % locals())
+####            dbg("IsEmpty? %(empty)d (do all mask chars == fillChar?)" % locals())
             return empty
         else:
-##            dbg("IsEmpty? 0 (value doesn't match template)")
+####            dbg("IsEmpty? 0 (value doesn't match template)")
             return False
 
 
@@ -4547,26 +4637,26 @@ class wxMaskedEditMixin:
     def IsValid(self, value=None):
         """ Indicates whether the value specified (or the current value of the control
         if not specified) is considered valid."""
-##        dbg('wxMaskedEditMixin::IsValid("%s")' % value, indent=1)
+####        dbg('MaskedEditMixin::IsValid("%s")' % value, indent=1)
         if value is None: value = self._GetValue()
         ret = self._CheckValid(value)
-##        dbg(indent=0)
+####        dbg(indent=0)
         return ret
 
 
     def _eraseSelection(self, value=None, sel_start=None, sel_to=None):
         """ Used to blank the selection when inserting a new character. """
-        dbg("wxMaskedEditMixin::_eraseSelection", indent=1)
+##        dbg("MaskedEditMixin::_eraseSelection", indent=1)
         if value is None: value = self._GetValue()
         if sel_start is None or sel_to is None:
             sel_start, sel_to = self._GetSelection()                   ## check for a range of selected text
-        dbg('value: "%s"' % value)
-        dbg("current sel_start, sel_to:", sel_start, sel_to)
+##        dbg('value: "%s"' % value)
+##        dbg("current sel_start, sel_to:", sel_start, sel_to)
 
         newvalue = list(value)
         for i in range(sel_start, sel_to):
             if self._signOk and newvalue[i] in ('-', '(', ')'):
-                dbg('found sign (%s) at' % newvalue[i], i)
+##                dbg('found sign (%s) at' % newvalue[i], i)
 
                 # balance parentheses:
                 if newvalue[i] == '(':
@@ -4589,14 +4679,14 @@ class wxMaskedEditMixin:
                     newvalue[i] = self._template[i]
 
         value = string.join(newvalue,"")
-        dbg('new value: "%s"' % value)
-        dbg(indent=0)
+##        dbg('new value: "%s"' % value)
+##        dbg(indent=0)
         return value
 
 
     def _insertKey(self, char, pos, sel_start, sel_to, value, allowAutoSelect=False):
         """ Handles replacement of the character at the current insertion point."""
-        dbg('wxMaskedEditMixin::_insertKey', "\'" + char + "\'", pos, sel_start, sel_to, '"%s"' % value, indent=1)
+##        dbg('MaskedEditMixin::_insertKey', "\'" + char + "\'", pos, sel_start, sel_to, '"%s"' % value, indent=1)
 
         text = self._eraseSelection(value)
         field = self._FindField(pos)
@@ -4608,7 +4698,7 @@ class wxMaskedEditMixin:
             # adjustpos must have moved the position; make selection match:
             sel_start = sel_to = pos
 
-        dbg('field._insertRight?', field._insertRight)
+##        dbg('field._insertRight?', field._insertRight)
         if( field._insertRight                                  # field allows right insert
             and ((sel_start, sel_to) == field._extent           # and whole field selected
                  or (sel_start == sel_to                        # or nothing selected
@@ -4616,7 +4706,7 @@ class wxMaskedEditMixin:
                           or (field._allowInsert                # or field allows right-insert
                               and sel_start < end               # next to other char in field:
                               and text[sel_start] != field._fillChar) ) ) ) ):
-            dbg('insertRight')
+##            dbg('insertRight')
             fstr = text[start:end]
             erasable_chars = [field._fillChar, ' ']
 
@@ -4624,42 +4714,42 @@ class wxMaskedEditMixin:
                 erasable_chars.append('0')
 
             erased = ''
-##            dbg("fstr[0]:'%s'" % fstr[0])
-##            dbg('field_index:', field._index)
-##            dbg("fstr[0] in erasable_chars?", fstr[0] in erasable_chars)
-##            dbg("self._signOk and field._index == 0 and fstr[0] in ('-','(')?",
+####            dbg("fstr[0]:'%s'" % fstr[0])
+####            dbg('field_index:', field._index)
+####            dbg("fstr[0] in erasable_chars?", fstr[0] in erasable_chars)
+####            dbg("self._signOk and field._index == 0 and fstr[0] in ('-','(')?",
 ##                 self._signOk and field._index == 0 and fstr[0] in ('-','('))
             if fstr[0] in erasable_chars or (self._signOk and field._index == 0 and fstr[0] in ('-','(')):
                 erased = fstr[0]
-##                dbg('value:      "%s"' % text)
-##                dbg('fstr:       "%s"' % fstr)
-##                dbg("erased:     '%s'" % erased)
+####                dbg('value:      "%s"' % text)
+####                dbg('fstr:       "%s"' % fstr)
+####                dbg("erased:     '%s'" % erased)
                 field_sel_start = sel_start - start
                 field_sel_to = sel_to - start
-                dbg('left fstr:  "%s"' % fstr[1:field_sel_start])
-                dbg('right fstr: "%s"' % fstr[field_sel_to:end])
+##                dbg('left fstr:  "%s"' % fstr[1:field_sel_start])
+##                dbg('right fstr: "%s"' % fstr[field_sel_to:end])
                 fstr = fstr[1:field_sel_start] + char + fstr[field_sel_to:end]
             if field._alignRight and sel_start != sel_to:
                 field_len = end - start
 ##                pos += (field_len - len(fstr))    # move cursor right by deleted amount
                 pos = sel_to
-                dbg('setting pos to:', pos)
+##                dbg('setting pos to:', pos)
                 if field._padZero:
                     fstr = '0' * (field_len - len(fstr)) + fstr
                 else:
                     fstr = fstr.rjust(field_len)   # adjust the field accordingly
-            dbg('field str: "%s"' % fstr)
+##            dbg('field str: "%s"' % fstr)
 
             newtext = text[:start] + fstr + text[end:]
             if erased in ('-', '(') and self._signOk:
                 newtext = erased + newtext[1:]
-            dbg('newtext: "%s"' % newtext)
+##            dbg('newtext: "%s"' % newtext)
 
             if self._signOk and field._index == 0:
                 start -= 1             # account for sign position
 
-##            dbg('field._moveOnFieldFull?', field._moveOnFieldFull)
-##            dbg('len(fstr.lstrip()) == end-start?', len(fstr.lstrip()) == end-start)
+####            dbg('field._moveOnFieldFull?', field._moveOnFieldFull)
+####            dbg('len(fstr.lstrip()) == end-start?', len(fstr.lstrip()) == end-start)
             if( field._moveOnFieldFull and pos == end
                 and len(fstr.lstrip()) == end-start):   # if field now full
                 newpos = self._findNextEntry(end)       #   go to next field
@@ -4667,9 +4757,10 @@ class wxMaskedEditMixin:
                 newpos = pos                            # else keep cursor at current position
 
         if not newtext:
-            dbg('not newtext')
+##            dbg('not newtext')
             if newpos != pos:
-                dbg('newpos:', newpos)
+##                dbg('newpos:', newpos)
+                pass
             if self._signOk and self._useParens:
                 old_right_signpos = text.find(')')
 
@@ -4678,10 +4769,10 @@ class wxMaskedEditMixin:
                 field_len = end - start
                 before = text[start:sel_start]
                 after = text[sel_to:end].strip()
-##                dbg("current field:'%s'" % text[start:end])
-##                dbg("before:'%s'" % before, "after:'%s'" % after)
+####                dbg("current field:'%s'" % text[start:end])
+####                dbg("before:'%s'" % before, "after:'%s'" % after)
                 new_len = len(before) + len(after) + 1 # (for inserted char)
-##                dbg('new_len:', new_len)
+####                dbg('new_len:', new_len)
 
                 if new_len < field_len:
                     retained = after + self._template[end-(field_len-new_len):end]
@@ -4691,7 +4782,7 @@ class wxMaskedEditMixin:
                     retained = after
 
                 left = text[0:start] + before
-##                dbg("left:'%s'" % left, "retained:'%s'" % retained)
+####                dbg("left:'%s'" % left, "retained:'%s'" % retained)
                 right   = retained + text[end:]
             else:
                 left  = text[0:pos]
@@ -4720,16 +4811,16 @@ class wxMaskedEditMixin:
                             else:
                                 rstripped_text = newtext.rstrip()
                                 right_signpos = len(rstripped_text)
-                                dbg('old_right_signpos:', old_right_signpos, 'right signpos now:', right_signpos)
+##                                dbg('old_right_signpos:', old_right_signpos, 'right signpos now:', right_signpos)
                                 newtext = newtext[:right_signpos] + ')' + newtext[right_signpos+1:]
 
             if( field._insertRight                                  # if insert-right field (but we didn't start at right edge)
                 and field._moveOnFieldFull                          # and should move cursor when full
                 and len(newtext[start:end].strip()) == end-start):  # and field now full
                 newpos = self._findNextEntry(end)                   #   go to next field
-                dbg('newpos = nextentry =', newpos)
+##                dbg('newpos = nextentry =', newpos)
             else:
-                dbg('pos:', pos, 'newpos:', pos+1)
+##                dbg('pos:', pos, 'newpos:', pos+1)
                 newpos = pos+1
 
 
@@ -4769,12 +4860,12 @@ class wxMaskedEditMixin:
                         # adjust position to just after partial match in control:
                         newpos = self._masklength - (len(self._ctrl_constraints._choices[match_index].strip()) - len(matched_str.strip()))
 
-            dbg('newtext: "%s"' % newtext, 'newpos:', newpos, 'new_select_to:', new_select_to)
-            dbg(indent=0)
+##            dbg('newtext: "%s"' % newtext, 'newpos:', newpos, 'new_select_to:', new_select_to)
+##            dbg(indent=0)
             return newtext, newpos, new_select_to, match_field, match_index
         else:
-            dbg('newtext: "%s"' % newtext, 'newpos:', newpos)
-            dbg(indent=0)
+##            dbg('newtext: "%s"' % newtext, 'newpos:', newpos)
+##            dbg(indent=0)
             return newtext, newpos
 
 
@@ -4788,8 +4879,8 @@ class wxMaskedEditMixin:
         preserve the correct selection when the focus event is not due to tab,
         we need to pull the following trick:
         """
-        dbg('wxMaskedEditMixin::_OnFocus')
-        wxCallAfter(self._fixSelection)
+##        dbg('MaskedEditMixin::_OnFocus')
+        wx.CallAfter(self._fixSelection)
         event.Skip()
         self.Refresh()
 
@@ -4800,41 +4891,42 @@ class wxMaskedEditMixin:
         current value of the control is a "valid value," and has the side
         effect of coloring the control appropriately.
         """
-        dbg(suspend=1)
-        dbg('wxMaskedEditMixin::_CheckValid: candidate="%s"' % candidate, indent=1)
+##        dbg(suspend=1)
+##        dbg('MaskedEditMixin::_CheckValid: candidate="%s"' % candidate, indent=1)
         oldValid = self._valid
         if candidate is None: value = self._GetValue()
         else: value = candidate
-        dbg('value: "%s"' % value)
+##        dbg('value: "%s"' % value)
         oldvalue = value
         valid = True    # assume True
 
         if not self.IsDefault(value) and self._isDate:                    ## Date type validation
             valid = self._validateDate(value)
-            dbg("valid date?", valid)
+##            dbg("valid date?", valid)
 
         elif not self.IsDefault(value) and self._isTime:
             valid = self._validateTime(value)
-            dbg("valid time?", valid)
+##            dbg("valid time?", valid)
 
         elif not self.IsDefault(value) and (self._isInt or self._isFloat):  ## Numeric type
             valid = self._validateNumeric(value)
-            dbg("valid Number?", valid)
+##            dbg("valid Number?", valid)
 
         if valid:   # and not self.IsDefault(value):    ## generic validation accounts for IsDefault()
             ## valid so far; ensure also allowed by any list or regex provided:
             valid = self._validateGeneric(value)
-            dbg("valid value?", valid)
+##            dbg("valid value?", valid)
 
-        dbg('valid?', valid)
+##        dbg('valid?', valid)
 
         if not candidate:
             self._valid = valid
             self._applyFormatting()
             if self._valid != oldValid:
-                dbg('validity changed: oldValid =',oldValid,'newvalid =', self._valid)
-                dbg('oldvalue: "%s"' % oldvalue, 'newvalue: "%s"' % self._GetValue())
-        dbg(indent=0, suspend=0)
+##                dbg('validity changed: oldValid =',oldValid,'newvalid =', self._valid)
+##                dbg('oldvalue: "%s"' % oldvalue, 'newvalue: "%s"' % self._GetValue())
+                pass
+##        dbg(indent=0, suspend=0)
         return valid
 
 
@@ -4846,7 +4938,7 @@ class wxMaskedEditMixin:
         else:
             text = candidate
 
-        valid = True    # assume true
+        valid = True    # assume True
         for i in [-1] + self._field_indices:   # process global constraints first:
             field = self._fields[i]
             start, end = field._extent
@@ -4873,47 +4965,47 @@ class wxMaskedEditMixin:
                         require_digit_at = self._fields[0]._extent[1]-1
                     else:
                         require_digit_at = self._fields[0]._extent[0]
-                    dbg('require_digit_at:', require_digit_at)
-                    dbg("value[rda]: '%s'" % value[require_digit_at])
+##                    dbg('require_digit_at:', require_digit_at)
+##                    dbg("value[rda]: '%s'" % value[require_digit_at])
                     if value[require_digit_at] not in list(string.digits):
                         valid = False
                         return valid
                 # else...
-            dbg('number:', number)
+##            dbg('number:', number)
             if self._ctrl_constraints._hasRange:
                 valid = self._ctrl_constraints._rangeLow <= number <= self._ctrl_constraints._rangeHigh
             else:
                 valid = True
             groupcharpos = value.rfind(groupchar)
             if groupcharpos != -1:  # group char present
-                dbg('groupchar found at', groupcharpos)
+##                dbg('groupchar found at', groupcharpos)
                 if self._isFloat and groupcharpos > self._decimalpos:
                     # 1st one found on right-hand side is past decimal point
-                    dbg('groupchar in fraction; illegal')
+##                    dbg('groupchar in fraction; illegal')
                     valid = False
                 elif self._isFloat:
                     integer = value[:self._decimalpos].strip()
                 else:
                     integer = value.strip()
-                dbg("integer:'%s'" % integer)
+##                dbg("integer:'%s'" % integer)
                 if integer[0] in ('-', '('):
                     integer = integer[1:]
                 if integer[-1] == ')':
                     integer = integer[:-1]
 
                 parts = integer.split(groupchar)
-                dbg('parts:', parts)
+##                dbg('parts:', parts)
                 for i in range(len(parts)):
                     if i == 0 and abs(int(parts[0])) > 999:
-                        dbg('group 0 too long; illegal')
+##                        dbg('group 0 too long; illegal')
                         valid = False
                         break
                     elif i > 0 and (len(parts[i]) != 3 or ' ' in parts[i]):
-                        dbg('group %i (%s) not right size; illegal' % (i, parts[i]))
+##                        dbg('group %i (%s) not right size; illegal' % (i, parts[i]))
                         valid = False
                         break
         except ValueError:
-            dbg('value not a valid number')
+##            dbg('value not a valid number')
             valid = False
         return valid
 
@@ -4922,12 +5014,12 @@ class wxMaskedEditMixin:
         """ Validate the current date value using the provided Regex filter.
             Generally used for character types.BufferType
         """
-        dbg('wxMaskedEditMixin::_validateDate', indent=1)
+##        dbg('MaskedEditMixin::_validateDate', indent=1)
         if candidate is None: value = self._GetValue()
         else: value = candidate
-        dbg('value = "%s"' % value)
+##        dbg('value = "%s"' % value)
         text = self._adjustDate(value, force4digit_year=True)     ## Fix the date up before validating it
-        dbg('text =', text)
+##        dbg('text =', text)
         valid = True   # assume True until proven otherwise
 
         try:
@@ -4942,19 +5034,19 @@ class wxMaskedEditMixin:
 
             year, month, day = getDateParts( datestr, self._datestyle)
             year = int(year)
-            dbg('self._dateExtent:', self._dateExtent)
+##            dbg('self._dateExtent:', self._dateExtent)
             if self._dateExtent == 11:
                 month = charmonths_dict[month.lower()]
             else:
                 month = int(month)
             day = int(day)
-            dbg('year, month, day:', year, month, day)
+##            dbg('year, month, day:', year, month, day)
 
         except ValueError:
-            dbg('cannot convert string to integer parts')
+##            dbg('cannot convert string to integer parts')
             valid = False
         except KeyError:
-            dbg('cannot convert string to integer month')
+##            dbg('cannot convert string to integer month')
             valid = False
 
         if valid:
@@ -4966,12 +5058,12 @@ class wxMaskedEditMixin:
             else:
                 month -= 1
                 try:
-                    dbg("trying to create date from values day=%d, month=%d, year=%d" % (day,month,year))
-                    dateHandler = wxDateTimeFromDMY(day,month,year)
-                    dbg("succeeded")
+##                    dbg("trying to create date from values day=%d, month=%d, year=%d" % (day,month,year))
+                    dateHandler = wx.DateTimeFromDMY(day,month,year)
+##                    dbg("succeeded")
                     dateOk = True
                 except:
-                    dbg('cannot convert string to valid date')
+##                    dbg('cannot convert string to valid date')
                     dateOk = False
                 if not dateOk:
                     valid = False
@@ -4981,16 +5073,17 @@ class wxMaskedEditMixin:
                 # so we eliminate them here:
                 timeStr     = text[self._dateExtent+1:].strip()         ## time portion of the string
                 if timeStr:
-                    dbg('timeStr: "%s"' % timeStr)
+##                    dbg('timeStr: "%s"' % timeStr)
                     try:
                         checkTime    = dateHandler.ParseTime(timeStr)
                         valid = checkTime == len(timeStr)
                     except:
                         valid = False
                     if not valid:
-                        dbg('cannot convert string to valid time')
+##                        dbg('cannot convert string to valid time')
+                        pass                        
         if valid: dbg('valid date')
-        dbg(indent=0)
+##        dbg(indent=0)
         return valid
 
 
@@ -4998,40 +5091,41 @@ class wxMaskedEditMixin:
         """ Validate the current time value using the provided Regex filter.
             Generally used for character types.BufferType
         """
-        dbg('wxMaskedEditMixin::_validateTime', indent=1)
+##        dbg('MaskedEditMixin::_validateTime', indent=1)
         # wxDateTime doesn't take kindly to leading/trailing spaces when parsing,
         # so we eliminate them here:
         if candidate is None: value = self._GetValue().strip()
         else: value = candidate.strip()
-        dbg('value = "%s"' % value)
+##        dbg('value = "%s"' % value)
         valid = True   # assume True until proven otherwise
 
-        dateHandler = wxDateTime_Today()
+        dateHandler = wx.DateTime_Today()
         try:
             checkTime    = dateHandler.ParseTime(value)
-            dbg('checkTime:', checkTime, 'len(value)', len(value))
+##            dbg('checkTime:', checkTime, 'len(value)', len(value))
             valid = checkTime == len(value)
         except:
             valid = False
 
         if not valid:
-            dbg('cannot convert string to valid time')
+##            dbg('cannot convert string to valid time')
+            pass
         if valid: dbg('valid time')
-        dbg(indent=0)
+##        dbg(indent=0)
         return valid
 
 
     def _OnKillFocus(self,event):
         """ Handler for EVT_KILL_FOCUS event.
         """
-        dbg('wxMaskedEditMixin::_OnKillFocus', 'isDate=',self._isDate, indent=1)
+##        dbg('MaskedEditMixin::_OnKillFocus', 'isDate=',self._isDate, indent=1)
         if self._mask and self._IsEditable():
             self._AdjustField(self._GetInsertionPoint())
             self._CheckValid()   ## Call valid handler
 
         self._LostFocus()    ## Provided for subclass use
         event.Skip()
-        dbg(indent=0)
+##        dbg(indent=0)
 
 
     def _fixSelection(self):
@@ -5048,20 +5142,20 @@ class wxMaskedEditMixin:
         we can assume the cause, change the insertion point to the start of
         the control, and deselect.
         """
-        dbg('wxMaskedEditMixin::_fixSelection', indent=1)
+##        dbg('MaskedEditMixin::_fixSelection', indent=1)
         if not self._mask or not self._IsEditable():
-            dbg(indent=0)
+##            dbg(indent=0)
             return
 
         sel_start, sel_to = self._GetSelection()
-        dbg('sel_start, sel_to:', sel_start, sel_to, 'self.IsEmpty()?', self.IsEmpty())
+##        dbg('sel_start, sel_to:', sel_start, sel_to, 'self.IsEmpty()?', self.IsEmpty())
 
         if( sel_start == 0 and sel_to >= len( self._mask )   #(can be greater in numeric controls because of reserved space)
             and (not self._ctrl_constraints._autoSelect or self.IsEmpty() or self.IsDefault() ) ):
             # This isn't normally allowed, and so assume we got here by the new
             # "tab traversal" behavior, so we need to reset the selection
             # and insertion point:
-            dbg('entire text selected; resetting selection to start of control')
+##            dbg('entire text selected; resetting selection to start of control')
             self._goHome()
             field = self._FindField(self._GetInsertionPoint())
             edit_start, edit_end = field._extent
@@ -5081,25 +5175,26 @@ class wxMaskedEditMixin:
                 edit_start, edit_end = integer._extent
 
                 if integer._selectOnFieldEntry:
-                    dbg('select on field entry:')
+##                    dbg('select on field entry:')
                     self._SetInsertionPoint(edit_start)
                     self._SetSelection(edit_start, edit_end)
 
                 elif integer._insertRight:
-                    dbg('moving insertion point to end')
+##                    dbg('moving insertion point to end')
                     self._SetInsertionPoint(edit_end)
                     self._SetSelection(edit_end, edit_end)
                 else:
-                    dbg('numeric ctrl is empty; start at beginning after sign')
+##                    dbg('numeric ctrl is empty; start at beginning after sign')
                     self._SetInsertionPoint(signpos+1)   ## Move past minus sign space if signed
                     self._SetSelection(signpos+1, signpos+1)
 
         elif sel_start > self._goEnd(getPosOnly=True):
-            dbg('cursor beyond the end of the user input; go to end of it')
+##            dbg('cursor beyond the end of the user input; go to end of it')
             self._goEnd()
         else:
-            dbg('sel_start, sel_to:', sel_start, sel_to, 'self._masklength:', self._masklength)
-        dbg(indent=0)
+##            dbg('sel_start, sel_to:', sel_start, sel_to, 'self._masklength:', self._masklength)
+            pass
+##        dbg(indent=0)
 
 
     def _Keypress(self,key):
@@ -5141,11 +5236,11 @@ class wxMaskedEditMixin:
         derived control because the mixin functions can't override a method of
         a sibling class.
         """
-        dbg("wxMaskedEditMixin::_Cut", indent=1)
+##        dbg("MaskedEditMixin::_Cut", indent=1)
         value = self._GetValue()
-        dbg('current value: "%s"' % value)
+##        dbg('current value: "%s"' % value)
         sel_start, sel_to = self._GetSelection()                   ## check for a range of selected text
-        dbg('selected text: "%s"' % value[sel_start:sel_to].strip())
+##        dbg('selected text: "%s"' % value[sel_start:sel_to].strip())
         do = wxTextDataObject()
         do.SetText(value[sel_start:sel_to].strip())
         wxTheClipboard.Open()
@@ -5154,7 +5249,7 @@ class wxMaskedEditMixin:
 
         if sel_to - sel_start != 0:
             self._OnErase()
-        dbg(indent=0)
+##        dbg(indent=0)
 
 
 # WS Note: overriding Copy is no longer necessary given that you
@@ -5198,32 +5293,32 @@ class wxMaskedEditMixin:
         returns validity, replacement text, and extent of paste in
         template.
         """
-        dbg(suspend=1)
-        dbg('wxMaskedEditMixin::_validatePaste("%(paste_text)s", %(sel_start)d, %(sel_to)d), raise_on_invalid? %(raise_on_invalid)d' % locals(), indent=1)
+##        dbg(suspend=1)
+##        dbg('MaskedEditMixin::_validatePaste("%(paste_text)s", %(sel_start)d, %(sel_to)d), raise_on_invalid? %(raise_on_invalid)d' % locals(), indent=1)
         select_length = sel_to - sel_start
         maxlength = select_length
-        dbg('sel_to - sel_start:', maxlength)
+##        dbg('sel_to - sel_start:', maxlength)
         if maxlength == 0:
             maxlength = self._masklength - sel_start
             item = 'control'
         else:
             item = 'selection'
-        dbg('maxlength:', maxlength)
+##        dbg('maxlength:', maxlength)
         length_considered = len(paste_text)
         if length_considered > maxlength:
-            dbg('paste text will not fit into the %s:' % item, indent=0)
+##            dbg('paste text will not fit into the %s:' % item, indent=0)
             if raise_on_invalid:
-                dbg(indent=0, suspend=0)
+##                dbg(indent=0, suspend=0)
                 if item == 'control':
                     raise ValueError('"%s" will not fit into the control "%s"' % (paste_text, self.name))
                 else:
                     raise ValueError('"%s" will not fit into the selection' % paste_text)
             else:
-                dbg(indent=0, suspend=0)
+##                dbg(indent=0, suspend=0)
                 return False, None, None
 
         text = self._template
-        dbg('length_considered:', length_considered)
+##        dbg('length_considered:', length_considered)
 
         valid_paste = True
         replacement_text = ""
@@ -5232,7 +5327,7 @@ class wxMaskedEditMixin:
         while valid_paste and i < length_considered and replace_to < self._masklength:
             if paste_text[i:] == self._template[replace_to:length_considered]:
                 # remainder of paste matches template; skip char-by-char analysis
-                dbg('remainder paste_text[%d:] (%s) matches template[%d:%d]' % (i, paste_text[i:], replace_to, length_considered))
+##                dbg('remainder paste_text[%d:] (%s) matches template[%d:%d]' % (i, paste_text[i:], replace_to, length_considered))
                 replacement_text += paste_text[i:]
                 replace_to = i = length_considered
                 continue
@@ -5243,12 +5338,12 @@ class wxMaskedEditMixin:
                 if field._forceupper:   char = char.upper()
                 elif field._forcelower: char = char.lower()
 
-            dbg('char:', "'"+char+"'", 'i =', i, 'replace_to =', replace_to)
-            dbg('self._isTemplateChar(%d)?' % replace_to, self._isTemplateChar(replace_to))
+##            dbg('char:', "'"+char+"'", 'i =', i, 'replace_to =', replace_to)
+##            dbg('self._isTemplateChar(%d)?' % replace_to, self._isTemplateChar(replace_to))
             if not self._isTemplateChar(replace_to) and self._isCharAllowed( char, replace_to, allowAutoSelect=False, ignoreInsertRight=True):
                 replacement_text += char
-                dbg("not template(%(replace_to)d) and charAllowed('%(char)s',%(replace_to)d)" % locals())
-                dbg("replacement_text:", '"'+replacement_text+'"')
+##                dbg("not template(%(replace_to)d) and charAllowed('%(char)s',%(replace_to)d)" % locals())
+##                dbg("replacement_text:", '"'+replacement_text+'"')
                 i += 1
                 replace_to += 1
             elif( char == self._template[replace_to]
@@ -5256,8 +5351,8 @@ class wxMaskedEditMixin:
                           ( (i == 0 and (char == '-' or (self._useParens and char == '(')))
                             or (i == self._masklength - 1 and self._useParens and char == ')') ) ) ):
                 replacement_text += char
-                dbg("'%(char)s' == template(%(replace_to)d)" % locals())
-                dbg("replacement_text:", '"'+replacement_text+'"')
+##                dbg("'%(char)s' == template(%(replace_to)d)" % locals())
+##                dbg("replacement_text:", '"'+replacement_text+'"')
                 i += 1
                 replace_to += 1
             else:
@@ -5266,24 +5361,25 @@ class wxMaskedEditMixin:
                     valid_paste = False
                 else:
                     replacement_text += self._template[replace_to:next_entry]
-                    dbg("skipping template; next_entry =", next_entry)
-                    dbg("replacement_text:", '"'+replacement_text+'"')
+##                    dbg("skipping template; next_entry =", next_entry)
+##                    dbg("replacement_text:", '"'+replacement_text+'"')
                     replace_to = next_entry  # so next_entry will be considered on next loop
 
         if not valid_paste and raise_on_invalid:
-            dbg('raising exception', indent=0, suspend=0)
+##            dbg('raising exception', indent=0, suspend=0)
             raise ValueError('"%s" cannot be inserted into the control "%s"' % (paste_text, self.name))
 
         elif i < len(paste_text):
             valid_paste = False
             if raise_on_invalid:
-                dbg('raising exception', indent=0, suspend=0)
+##                dbg('raising exception', indent=0, suspend=0)
                 raise ValueError('"%s" will not fit into the control "%s"' % (paste_text, self.name))
 
-        dbg('valid_paste?', valid_paste)
+##        dbg('valid_paste?', valid_paste)
         if valid_paste:
-            dbg('replacement_text: "%s"' % replacement_text, 'replace to:', replace_to)
-        dbg(indent=0, suspend=0)
+##            dbg('replacement_text: "%s"' % replacement_text, 'replace to:', replace_to)
+            pass
+##        dbg(indent=0, suspend=0)
         return valid_paste, replacement_text, replace_to
 
 
@@ -5295,17 +5391,17 @@ class wxMaskedEditMixin:
         derived control because the mixin functions can't override a
         method of a sibling class.
         """
-        dbg('wxMaskedEditMixin::_Paste (value = "%s")' % value, indent=1)
+##        dbg('MaskedEditMixin::_Paste (value = "%s")' % value, indent=1)
         if value is None:
             paste_text = self._getClipboardContents()
         else:
             paste_text = value
 
         if paste_text is not None:
-            dbg('paste text: "%s"' % paste_text)
+##            dbg('paste text: "%s"' % paste_text)
             # (conversion will raise ValueError if paste isn't legal)
             sel_start, sel_to = self._GetSelection()
-            dbg('selection:', (sel_start, sel_to))
+##            dbg('selection:', (sel_start, sel_to))
 
             # special case: handle allowInsert fields properly
             field = self._FindField(sel_start)
@@ -5314,7 +5410,7 @@ class wxMaskedEditMixin:
             if field._allowInsert and sel_to <= edit_end and sel_start + len(paste_text) < edit_end:
                 new_pos = sel_start + len(paste_text)   # store for subsequent positioning
                 paste_text = paste_text + self._GetValue()[sel_to:edit_end].rstrip()
-                dbg('paste within insertable field; adjusted paste_text: "%s"' % paste_text, 'end:', edit_end)
+##                dbg('paste within insertable field; adjusted paste_text: "%s"' % paste_text, 'end:', edit_end)
                 sel_to = sel_start + len(paste_text)
 
             # Another special case: paste won't fit, but it's a right-insert field where entire
@@ -5330,7 +5426,7 @@ class wxMaskedEditMixin:
                 amount_needed = len(paste_text) - (sel_to - sel_start)
                 if amount_needed <= empty_space:
                     sel_start -= amount_needed
-                    dbg('expanded selection to:', (sel_start, sel_to))
+##                    dbg('expanded selection to:', (sel_start, sel_to))
 
 
             # another special case: deal with signed values properly:
@@ -5341,10 +5437,10 @@ class wxMaskedEditMixin:
                     paste_signpos = paste_text.find('(')
 
                 # if paste text will result in signed value:
-##                dbg('paste_signpos != -1?', paste_signpos != -1)
-##                dbg('sel_start:', sel_start, 'signpos:', signpos)
-##                dbg('field._insertRight?', field._insertRight)
-##                dbg('sel_start - len(paste_text) >= signpos?', sel_start - len(paste_text) <= signpos)
+####                dbg('paste_signpos != -1?', paste_signpos != -1)
+####                dbg('sel_start:', sel_start, 'signpos:', signpos)
+####                dbg('field._insertRight?', field._insertRight)
+####                dbg('sel_start - len(paste_text) >= signpos?', sel_start - len(paste_text) <= signpos)
                 if paste_signpos != -1 and (sel_start <= signpos
                                             or (field._insertRight and sel_start - len(paste_text) <= signpos)):
                     signed = True
@@ -5352,32 +5448,32 @@ class wxMaskedEditMixin:
                     signed = False
                 # remove "sign" from paste text, so we can auto-adjust for sign type after paste:
                 paste_text = paste_text.replace('-', ' ').replace('(',' ').replace(')','')
-                dbg('unsigned paste text: "%s"' % paste_text)
+##                dbg('unsigned paste text: "%s"' % paste_text)
             else:
                 signed = False
 
             # another special case: deal with insert-right fields when selection is empty and
             # cursor is at end of field:
-##            dbg('field._insertRight?', field._insertRight)
-##            dbg('sel_start == edit_end?', sel_start == edit_end)
-##            dbg('sel_start', sel_start, 'sel_to', sel_to)
+####            dbg('field._insertRight?', field._insertRight)
+####            dbg('sel_start == edit_end?', sel_start == edit_end)
+####            dbg('sel_start', sel_start, 'sel_to', sel_to)
             if field._insertRight and sel_start == edit_end and sel_start == sel_to:
                 sel_start -= len(paste_text)
                 if sel_start < 0:
                     sel_start = 0
-                dbg('adjusted selection:', (sel_start, sel_to))
+##                dbg('adjusted selection:', (sel_start, sel_to))
 
             try:
                 valid_paste, replacement_text, replace_to = self._validatePaste(paste_text, sel_start, sel_to, raise_on_invalid)
             except:
-                dbg('exception thrown', indent=0)
+##                dbg('exception thrown', indent=0)
                 raise
 
             if not valid_paste:
-                dbg('paste text not legal for the selection or portion of the control following the cursor;')
-                if not wxValidator_IsSilent():
-                    wxBell()
-                dbg(indent=0)
+##                dbg('paste text not legal for the selection or portion of the control following the cursor;')
+                if not wx.Validator_IsSilent():
+                    wx.Bell()
+##                dbg(indent=0)
                 return False
             # else...
             text = self._eraseSelection()
@@ -5395,33 +5491,35 @@ class wxMaskedEditMixin:
                     if not self._isNeg:
                         self._isNeg = 1
 
-            dbg("new_text:", '"'+new_text+'"')
+##            dbg("new_text:", '"'+new_text+'"')
 
             if not just_return_value:
+                if new_text != self._GetValue():
+                    self.modified = True
                 if new_text == '':
                     self.ClearValue()
                 else:
-                    wxCallAfter(self._SetValue, new_text)
+                    wx.CallAfter(self._SetValue, new_text)
                     if new_pos is None:
                         new_pos = sel_start + len(replacement_text)
-                    wxCallAfter(self._SetInsertionPoint, new_pos)
+                    wx.CallAfter(self._SetInsertionPoint, new_pos)
             else:
-                dbg(indent=0)
+##                dbg(indent=0)
                 return new_text
         elif just_return_value:
-            dbg(indent=0)
+##            dbg(indent=0)
             return self._GetValue()
-        dbg(indent=0)
+##        dbg(indent=0)
 
     def _Undo(self):
         """ Provides an Undo() method in base controls. """
-        dbg("wxMaskedEditMixin::_Undo", indent=1)
+##        dbg("MaskedEditMixin::_Undo", indent=1)
         value = self._GetValue()
         prev = self._prevValue
-        dbg('current value:  "%s"' % value)
-        dbg('previous value: "%s"' % prev)
+##        dbg('current value:  "%s"' % value)
+##        dbg('previous value: "%s"' % prev)
         if prev is None:
-            dbg('no previous value', indent=0)
+##            dbg('no previous value', indent=0)
             return
 
         elif value != prev:
@@ -5458,24 +5556,24 @@ class wxMaskedEditMixin:
             # Determine where they stop differing in "undo" result:
             sm = difflib.SequenceMatcher(None, a=value, b=prev)
             i, j, k = sm.find_longest_match(sel_start, length, sel_start, length)
-            dbg('i,j,k = ', (i,j,k), 'value[i:i+k] = "%s"' % value[i:i+k], 'prev[j:j+k] = "%s"' % prev[j:j+k] )
+##            dbg('i,j,k = ', (i,j,k), 'value[i:i+k] = "%s"' % value[i:i+k], 'prev[j:j+k] = "%s"' % prev[j:j+k] )
 
             if k == 0:                              # no match found; select to end
                 sel_to = length
             else:
                 code_5tuples = sm.get_opcodes()
                 for op, i1, i2, j1, j2 in code_5tuples:
-                    dbg("%7s value[%d:%d] (%s) prev[%d:%d] (%s)" %
-                            (op, i1, i2, value[i1:i2], j1, j2, prev[j1:j2]))
+##                    dbg("%7s value[%d:%d] (%s) prev[%d:%d] (%s)" % (op, i1, i2, value[i1:i2], j1, j2, prev[j1:j2]))
+                    pass
 
                 diff_found = False
                 # look backward through operations needed to produce "previous" value;
                 # first change wins:
                 for next_op in range(len(code_5tuples)-1, -1, -1):
                     op, i1, i2, j1, j2 = code_5tuples[next_op]
-                    dbg('value[i1:i2]: "%s"' % value[i1:i2], 'template[i1:i2] "%s"' % self._template[i1:i2])
+##                    dbg('value[i1:i2]: "%s"' % value[i1:i2], 'template[i1:i2] "%s"' % self._template[i1:i2])
                     if op == 'insert' and prev[j1:j2] != self._template[j1:j2]:
-                        dbg('insert found: selection =>', (j1, j2))
+##                        dbg('insert found: selection =>', (j1, j2))
                         sel_start = j1
                         sel_to = j2
                         diff_found = True
@@ -5489,11 +5587,11 @@ class wxMaskedEditMixin:
                         else:
                             sel_start = i1
                             sel_to = j1
-                        dbg('delete found: selection =>', (sel_start, sel_to))
+##                        dbg('delete found: selection =>', (sel_start, sel_to))
                         diff_found = True
                         break
                     elif op == 'replace':
-                        dbg('replace found: selection =>', (j1, j2))
+##                        dbg('replace found: selection =>', (j1, j2))
                         sel_start = j1
                         sel_to = j2
                         diff_found = True
@@ -5508,17 +5606,17 @@ class wxMaskedEditMixin:
                         if op == 'equal':
                             continue
                         elif op == 'replace':
-                            dbg('setting sel_start to', i1)
+##                            dbg('setting sel_start to', i1)
                             sel_start = i1
                             break
                         elif op == 'insert' and not value[i1:i2]:
-                            dbg('forward %s found' % op)
+##                            dbg('forward %s found' % op)
                             if prev[j1:j2].strip():
-                                dbg('item to insert non-empty; setting sel_start to', j1)
+##                                dbg('item to insert non-empty; setting sel_start to', j1)
                                 sel_start = j1
                                 break
                             elif not field._insertRight:
-                                dbg('setting sel_start to inserted space:', j1)
+##                                dbg('setting sel_start to inserted space:', j1)
                                 sel_start = j1
                                 break
                         elif op == 'delete' and field._insertRight and not value[i1:i2].lstrip():
@@ -5529,7 +5627,7 @@ class wxMaskedEditMixin:
 
 
                 if not diff_found:
-                    dbg('no insert,delete or replace found (!)')
+##                    dbg('no insert,delete or replace found (!)')
                     # do "left-insert"-centric processing of difference based on l.c.s.:
                     if i == j and j != sel_start:         # match starts after start of selection
                         sel_to = sel_start + (j-sel_start)  # select to start of match
@@ -5573,7 +5671,7 @@ class wxMaskedEditMixin:
             # To get all this right, we use the previous selection recorded to help us...
 
             if (sel_start, sel_to) != self._prevSelection:
-                dbg('calculated selection', (sel_start, sel_to), "doesn't match previous", self._prevSelection)
+##                dbg('calculated selection', (sel_start, sel_to), "doesn't match previous", self._prevSelection)
 
                 prev_sel_start, prev_sel_to = self._prevSelection
                 field = self._FindField(sel_start)
@@ -5592,8 +5690,8 @@ class wxMaskedEditMixin:
                     calc_select_len = sel_to - sel_start
                     prev_select_len = prev_sel_to - prev_sel_start
 
-                    dbg('sel_start == prev_sel_start', sel_start == prev_sel_start)
-                    dbg('sel_to > prev_sel_to', sel_to > prev_sel_to)
+##                    dbg('sel_start == prev_sel_start', sel_start == prev_sel_start)
+##                    dbg('sel_to > prev_sel_to', sel_to > prev_sel_to)
 
                     if prev_select_len >= calc_select_len:
                         # old selection was bigger; trust it:
@@ -5604,7 +5702,7 @@ class wxMaskedEditMixin:
                           and sel_to == len(self._template) ):  # and calculated selection goes to end of control
 
                         i, j, k = sm.find_longest_match(prev_sel_to, length, prev_sel_to, length)
-                        dbg('i,j,k = ', (i,j,k), 'value[i:i+k] = "%s"' % value[i:i+k], 'prev[j:j+k] = "%s"' % prev[j:j+k] )
+##                        dbg('i,j,k = ', (i,j,k), 'value[i:i+k] = "%s"' % value[i:i+k], 'prev[j:j+k] = "%s"' % prev[j:j+k] )
                         if k > 0:
                             # difflib must not have optimized opcodes properly;
                             sel_to = j
@@ -5627,9 +5725,9 @@ class wxMaskedEditMixin:
                         else:
                             test_sel_start, test_sel_to = prev_sel_start, prev_sel_to
 
-                        dbg('test selection:', (test_sel_start, test_sel_to))
-                        dbg('calc change: "%s"' % self._prevValue[sel_start:sel_to])
-                        dbg('test change: "%s"' % self._prevValue[test_sel_start:test_sel_to])
+##                        dbg('test selection:', (test_sel_start, test_sel_to))
+##                        dbg('calc change: "%s"' % self._prevValue[sel_start:sel_to])
+##                        dbg('test change: "%s"' % self._prevValue[test_sel_start:test_sel_to])
 
                         # if calculated selection spans characters, and same characters
                         # "before" the previous insertion point are present there as well,
@@ -5640,14 +5738,15 @@ class wxMaskedEditMixin:
 
                             sel_start, sel_to = test_sel_start, test_sel_to
 
-            dbg('sel_start, sel_to:', sel_start, sel_to)
-            dbg('previous value: "%s"' % self._prevValue)
+##            dbg('sel_start, sel_to:', sel_start, sel_to)
+##            dbg('previous value: "%s"' % self._prevValue)
             self._SetValue(self._prevValue)
             self._SetInsertionPoint(sel_start)
             self._SetSelection(sel_start, sel_to)
         else:
-            dbg('no difference between previous value')
-        dbg(indent=0)
+##            dbg('no difference between previous value')
+            pass
+##        dbg(indent=0)
 
 
     def _OnClear(self, event):
@@ -5656,7 +5755,7 @@ class wxMaskedEditMixin:
 
 
     def _OnContextMenu(self, event):
-        dbg('wxMaskedEditMixin::OnContextMenu()', indent=1)
+##        dbg('MaskedEditMixin::OnContextMenu()', indent=1)
         menu = wxMenu()
         menu.Append(wxID_UNDO, "Undo", "")
         menu.AppendSeparator()
@@ -5687,7 +5786,7 @@ class wxMaskedEditMixin:
         self.PopupMenu(menu, event.GetPosition())
         menu.Destroy()
         self._contextMenu = None
-        dbg(indent=0)
+##        dbg(indent=0)
 
     def _UndoUpdateUI(self, event):
         if self._prevValue is None or self._prevValue == self._curValue:
@@ -5696,105 +5795,166 @@ class wxMaskedEditMixin:
             self._contextMenu.Enable(wxID_UNDO, True)
 
 
-## ---------- ---------- ---------- ---------- ---------- ---------- ----------
+    def _OnCtrlParametersChanged(self):
+        """
+        Overridable function to allow derived classes to take action as a
+        result of parameter changes prior to possibly changing the value
+        of the control.
+        """
+        pass
+
+ ## ---------- ---------- ---------- ---------- ---------- ---------- ----------
+# ## 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 MaskedEditAccessorsMixin:
+
+    # Define the default set of attributes exposed by the most generic masked controls:
+    exposed_basectrl_params = MaskedEditMixin.valid_ctrl_params.keys() + Field.valid_params.keys()
+    exposed_basectrl_params.remove('index')
+    exposed_basectrl_params.remove('extent')
+    exposed_basectrl_params.remove('foregroundColour')   # (base class already has this)
+
+    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 wxMaskedTextCtrl( wxTextCtrl, wxMaskedEditMixin ):
+
+
+class BaseMaskedTextCtrl( wx.TextCtrl, MaskedEditMixin ):
     """
-    This is the primary derivation from wxMaskedEditMixin.  It provides
+    This is the primary derivation from MaskedEditMixin.  It provides
     a general masked text control that can be configured with different
-    masks.
+    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 = wxDefaultPosition,
-                  size = wxDefaultSize,
-                  style = wxTE_PROCESS_TAB,
-                  validator=wxDefaultValidator,     ## placeholder provided for data-transfer logic
+                  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):
 
-        wxTextCtrl.__init__(self, parent, id, value='',
+        wx.TextCtrl.__init__(self, parent, id, value='',
                             pos=pos, size = size,
                             style=style, validator=validator,
                             name=name)
 
         self.controlInitialized = True
-        wxMaskedEditMixin.__init__( self, name, **kwargs )
+        MaskedEditMixin.__init__( self, name, **kwargs )
+
         self._SetInitialValue(value)
 
         if setupEventHandling:
             ## Setup event handlers
-            EVT_SET_FOCUS( self, self._OnFocus )        ## defeat automatic full selection
-            EVT_KILL_FOCUS( self, self._OnKillFocus )   ## run internal validator
-            EVT_LEFT_DCLICK(self, self._OnDoubleClick)  ## select field under cursor on dclick
-            EVT_RIGHT_UP(self, self._OnContextMenu )    ## bring up an appropriate context menu
-            EVT_KEY_DOWN( self, self._OnKeyDown )       ## capture control events not normally seen, eg ctrl-tab.
-            EVT_CHAR( self, self._OnChar )              ## handle each keypress
-            EVT_TEXT( self, self.GetId(), self._OnTextChange )  ## color control appropriately & keep
+            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 "<wxMaskedTextCtrl: %s>" % self.GetValue()
+        return "<BaseMaskedTextCtrl: %s>" % self.GetValue()
 
 
     def _GetSelection(self):
         """
         Allow mixin to get the text selection of this control.
-        REQUIRED by any class derived from wxMaskedEditMixin.
+        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 wxMaskedEditMixin.
+        REQUIRED by any class derived from MaskedEditMixin.
         """
-##        dbg("wxMaskedTextCtrl::_SetSelection(%(sel_start)d, %(sel_to)d)" % locals())
+####        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("wxMaskedTextCtrl::SetSelection(%(sel_start)d, %(sel_to)d)" % locals())
-        wxTextCtrl.SetSelection(self, sel_start, sel_to)
+##        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("wxMaskedTextCtrl::_SetInsertionPoint(%(pos)d)" % locals())
+####        dbg("MaskedTextCtrl::_SetInsertionPoint(%(pos)d)" % locals())
         self.SetInsertionPoint(pos)
 
     def SetInsertionPoint(self, pos):
         """
         This is just for debugging...
         """
-        dbg("wxMaskedTextCtrl::SetInsertionPoint(%(pos)d)" % locals())
-        wxTextCtrl.SetInsertionPoint(self, pos)
+##        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 wxMaskedEditMixin.
+        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 wxMaskedEditMixin.
+        REQUIRED by any class derived from MaskedEditMixin.
         """
-        dbg('wxMaskedTextCtrl::_SetValue("%(value)s")' % locals(), indent=1)
+##        dbg('MaskedTextCtrl::_SetValue("%(value)s")' % locals(), indent=1)
         # Record current selection and insertion point, for undo
         self._prevSelection = self._GetSelection()
         self._prevInsertionPoint = self._GetInsertionPoint()
-        wxTextCtrl.SetValue(self, value)
-        dbg(indent=0)
+        wx.TextCtrl.SetValue(self, value)
+##        dbg(indent=0)
 
     def SetValue(self, value):
         """
@@ -5803,10 +5963,10 @@ class wxMaskedTextCtrl( wxTextCtrl, wxMaskedEditMixin ):
         masked control.  NOTE: this must be done in the class derived
         from the base wx control.
         """
-        dbg('wxMaskedTextCtrl::SetValue = "%s"' % value, indent=1)
+##        dbg('MaskedTextCtrl::SetValue = "%s"' % value, indent=1)
 
         if not self._mask:
-            wxTextCtrl.SetValue(self, value)    # revert to base control behavior
+            wx.TextCtrl.SetValue(self, value)    # revert to base control behavior
             return
 
         # empty previous contents, replacing entire value:
@@ -5823,12 +5983,12 @@ class wxMaskedTextCtrl( wxTextCtrl, wxMaskedEditMixin ):
             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)
+##            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)
+##            dbg('padded value = "%s"' % value)
 
         # make SetValue behave the same as if you had typed the value in:
         try:
@@ -5840,43 +6000,44 @@ class wxMaskedTextCtrl( wxTextCtrl, wxMaskedEditMixin ):
                 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)
+                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)
+                dateparts[0] = self._adjustDate(dateparts[0], fixcentury=True)
                 value = string.join(dateparts, ' ')
-                dbg('adjusted value: "%s"' % value)
+##                dbg('adjusted value: "%s"' % value)
                 value = self._Paste(value, raise_on_invalid=True, just_return_value=True)
             else:
-                dbg('exception thrown', indent=0)
+##                dbg('exception thrown', indent=0)
                 raise
 
-        self._SetValue(value)
-##        dbg('queuing insertion after .SetValue', self._masklength)
-        wxCallAfter(self._SetInsertionPoint, self._masklength)
-        wxCallAfter(self._SetSelection, self._masklength, self._masklength)
-        dbg(indent=0)
+        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("wxMaskedTextCtrl::Clear - value reset to default value (template)")
+##        dbg("MaskedTextCtrl::Clear - value reset to default value (template)")
         if self._mask:
             self.ClearValue()
         else:
-            wxTextCtrl.Clear(self)    # else revert to base control behavior
+            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 wxMaskedEditMixin.
+        REQUIRED by any class derived from MaskedEditMixin.
         """
-        dbg('wxMaskedTextCtrl::_Refresh', indent=1)
-        wxTextCtrl.Refresh(self)
-        dbg(indent=0)
+##        dbg('MaskedTextCtrl::_Refresh', indent=1)
+        wx.TextCtrl.Refresh(self)
+##        dbg(indent=0)
 
 
     def Refresh(self):
@@ -5885,18 +6046,18 @@ class wxMaskedTextCtrl( wxTextCtrl, wxMaskedEditMixin ):
         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('wxMaskedTextCtrl::Refresh', indent=1)
+##        dbg('MaskedTextCtrl::Refresh', indent=1)
         self._CheckValid()
         self._Refresh()
-        dbg(indent=0)
+##        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 wxMaskedEditMixin.
+        REQUIRED by any class derived from MaskedEditMixin.
         """
-        return wxTextCtrl.IsEditable(self)
+        return wx.TextCtrl.IsEditable(self)
 
 
     def Cut(self):
@@ -5909,7 +6070,7 @@ class wxMaskedTextCtrl( wxTextCtrl, wxMaskedEditMixin ):
         if self._mask:
             self._Cut()             # call the mixin's Cut method
         else:
-            wxTextCtrl.Cut(self)    # else revert to base control behavior
+            wx.TextCtrl.Cut(self)    # else revert to base control behavior
 
 
     def Paste(self):
@@ -5922,7 +6083,7 @@ class wxMaskedTextCtrl( wxTextCtrl, wxMaskedEditMixin ):
         if self._mask:
             self._Paste()                   # call the mixin's Paste method
         else:
-            wxTextCtrl.Paste(self, value)   # else revert to base control behavior
+            wx.TextCtrl.Paste(self, value)   # else revert to base control behavior
 
 
     def Undo(self):
@@ -5933,7 +6094,7 @@ class wxMaskedTextCtrl( wxTextCtrl, wxMaskedEditMixin ):
         if self._mask:
             self._Undo()
         else:
-            wxTextCtrl.Undo(self)   # else revert to base control behavior
+            wx.TextCtrl.Undo(self)   # else revert to base control behavior
 
 
     def IsModified(self):
@@ -5944,7 +6105,7 @@ class wxMaskedTextCtrl( wxTextCtrl, wxMaskedEditMixin ):
         keystroke to see if the value changes, and if so, it's been
         modified.
         """
-        return wxTextCtrl.IsModified(self) or self.modified
+        return wx.TextCtrl.IsModified(self) or self.modified
 
 
     def _CalcSize(self, size=None):
@@ -5954,12 +6115,22 @@ class wxMaskedTextCtrl( wxTextCtrl, wxMaskedEditMixin ):
         return self._calcSize(size)
 
 
+class MaskedTextCtrl( 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
+
+
 ## ---------- ---------- ---------- ---------- ---------- ---------- ----------
 ## Because calling SetSelection programmatically does not fire EVT_COMBOBOX
 ## events, we have to do it ourselves when we auto-complete.
-class wxMaskedComboBoxSelectEvent(wxPyCommandEvent):
+class MaskedComboBoxSelectEvent(wx.PyCommandEvent):
     def __init__(self, id, selection = 0, object=None):
-        wxPyCommandEvent.__init__(self, wxEVT_COMMAND_COMBOBOX_SELECTED, id)
+        wx.PyCommandEvent.__init__(self, wx.wxEVT_COMMAND_COMBOBOX_SELECTED, id)
 
         self.__selection = selection
         self.SetEventObject(object)
@@ -5970,17 +6141,17 @@ class wxMaskedComboBoxSelectEvent(wxPyCommandEvent):
         return self.__selection
 
 
-class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
+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 = wxDefaultPosition,
-                  size = wxDefaultSize,
+                  pos = wx.DefaultPosition,
+                  size = wx.DefaultSize,
                   choices = [],
-                  style = wxCB_DROPDOWN,
-                  validator = wxDefaultValidator,
+                  style = wx.CB_DROPDOWN,
+                  validator = wx.DefaultValidator,
                   name = "maskedComboBox",
                   setupEventHandling = True,        ## setup event handling by default):
                   **kwargs):
@@ -5989,7 +6160,7 @@ class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
         # 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 & wxCB_READONLY == wxCB_READONLY
+        self.__readonly = style & wx.CB_READONLY == wx.CB_READONLY
 
         kwargs['choices'] = choices                 ## set up maskededit to work with choice list too
 
@@ -5997,18 +6168,19 @@ class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
         if not kwargs.has_key('compareNoCase'):
             kwargs['compareNoCase'] = True
 
-        wxMaskedEditMixin.__init__( self, name, **kwargs )
+        MaskedEditMixin.__init__( self, name, **kwargs )
+
         self._choices = self._ctrl_constraints._choices
-        dbg('self._choices:', self._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]
 
-        wxComboBox.__init__(self, parent, id, value='',
+        wx.ComboBox.__init__(self, parent, id, value='',
                             pos=pos, size = size,
-                            choices=choices, style=style|wxWANTS_CHARS,
+                            choices=choices, style=style|wx.WANTS_CHARS,
                             validator=validator,
                             name=name)
 
@@ -6033,26 +6205,26 @@ class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
             self._SetInitialValue(value)
 
 
-        self._SetKeycodeHandler(WXK_UP, self.OnSelectChoice)
-        self._SetKeycodeHandler(WXK_DOWN, self.OnSelectChoice)
+        self._SetKeycodeHandler(wx.WXK_UP, self.OnSelectChoice)
+        self._SetKeycodeHandler(wx.WXK_DOWN, self.OnSelectChoice)
 
         if setupEventHandling:
             ## Setup event handlers
-            EVT_SET_FOCUS( self, self._OnFocus )        ## defeat automatic full selection
-            EVT_KILL_FOCUS( self, self._OnKillFocus )   ## run internal validator
-            EVT_LEFT_DCLICK(self, self._OnDoubleClick)  ## select field under cursor on dclick
-            EVT_RIGHT_UP(self, self._OnContextMenu )    ## bring up an appropriate context menu
-            EVT_CHAR( self, self._OnChar )              ## handle each keypress
-            EVT_KEY_DOWN( self, self.OnKeyDown )        ## for special processing of up/down keys
-            EVT_KEY_DOWN( self, self._OnKeyDown )       ## for processing the rest of the control keys
-                                                        ## (next in evt chain)
-            EVT_TEXT( self, self.GetId(), self._OnTextChange )  ## color control appropriately & keep
+            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 "<wxMaskedComboBox: %s>" % self.GetValue()
+        return "<MaskedComboBox: %s>" % self.GetValue()
 
 
     def _CalcSize(self, size=None):
@@ -6067,14 +6239,14 @@ class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
     def _GetSelection(self):
         """
         Allow mixin to get the text selection of this control.
-        REQUIRED by any class derived from wxMaskedEditMixin.
+        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 wxMaskedEditMixin.
+        REQUIRED by any class derived from MaskedEditMixin.
         """
         return self.SetMark( sel_start, sel_to )
 
@@ -6089,14 +6261,14 @@ class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
     def _GetValue(self):
         """
         Allow mixin to get the raw value of the control with this function.
-        REQUIRED by any class derived from wxMaskedEditMixin.
+        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 wxMaskedEditMixin.
+        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
@@ -6110,7 +6282,7 @@ class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
         # Record current selection and insertion point, for undo
         self._prevSelection = self._GetSelection()
         self._prevInsertionPoint = self._GetInsertionPoint()
-        wxComboBox.SetValue(self, value)
+        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()
@@ -6123,7 +6295,7 @@ class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
         from the base wx control.
         """
         if not self._mask:
-            wxComboBox.SetValue(value)   # revert to base control behavior
+            wx.ComboBox.SetValue(value)   # revert to base control behavior
             return
         # else...
         # empty previous contents, replacing entire value:
@@ -6135,7 +6307,7 @@ class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
             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)
+##            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
@@ -6157,30 +6329,30 @@ class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
                 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)
+                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)
+                dateparts[0] = self._adjustDate(dateparts[0], fixcentury=True)
                 value = string.join(dateparts, ' ')
-                dbg('adjusted value: "%s"' % value)
+##                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)
-        wxCallAfter(self._SetInsertionPoint, self._masklength)
-        wxCallAfter(self._SetSelection, self._masklength, self._masklength)
+####        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 wxMaskedEditMixin.
+        REQUIRED by any class derived from MaskedEditMixin.
         """
-        wxComboBox.Refresh(self)
+        wx.ComboBox.Refresh(self)
 
     def Refresh(self):
         """
@@ -6195,7 +6367,7 @@ class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
     def _IsEditable(self):
         """
         Allow mixin to determine if the base control is editable with this function.
-        REQUIRED by any class derived from wxMaskedEditMixin.
+        REQUIRED by any class derived from MaskedEditMixin.
         """
         return not self.__readonly
 
@@ -6210,7 +6382,7 @@ class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
         if self._mask:
             self._Cut()             # call the mixin's Cut method
         else:
-            wxComboBox.Cut(self)    # else revert to base control behavior
+            wx.ComboBox.Cut(self)    # else revert to base control behavior
 
 
     def Paste(self):
@@ -6223,7 +6395,7 @@ class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
         if self._mask:
             self._Paste()           # call the mixin's Paste method
         else:
-            wxComboBox.Paste(self)  # else revert to base control behavior
+            wx.ComboBox.Paste(self)  # else revert to base control behavior
 
 
     def Undo(self):
@@ -6234,7 +6406,7 @@ class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
         if self._mask:
             self._Undo()
         else:
-            wxComboBox.Undo()       # else revert to base control behavior
+            wx.ComboBox.Undo()       # else revert to base control behavior
 
 
     def Append( self, choice, clientData=None ):
@@ -6267,7 +6439,7 @@ class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
                 choice = choice.ljust(self._masklength)
             if self._ctrl_constraints._fillChar != ' ':
                 choice = choice.replace(' ', self._fillChar)
-            dbg('updated choice:', choice)
+##            dbg('updated choice:', choice)
 
 
             self._ctrl_constraints._compareChoices.append(compareChoice)
@@ -6279,7 +6451,7 @@ class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
                 (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))
 
-        wxComboBox.Append(self, choice, clientData)
+        wx.ComboBox.Append(self, choice, clientData)
 
 
 
@@ -6293,21 +6465,19 @@ class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
             self._ctrl_constraints._autoCompleteIndex = -1
             if self._ctrl_constraints._choices:
                 self.SetCtrlParameters(choices=[])
-        wxComboBox.Clear(self)
+        wx.ComboBox.Clear(self)
 
 
-    def SetCtrlParameters( self, **kwargs ):
+    def _OnCtrlParametersChanged(self):
         """
-        Override mixin's default SetCtrlParameters to detect changes in choice list, so
+        Override mixin's default OnCtrlParametersChanged to detect changes in choice list, so
         we can update the base control:
         """
-        wxMaskedEditMixin.SetCtrlParameters(self, **kwargs )
-        if( self.controlInitialized
-            and (kwargs.has_key('choices') or self._choices != self._ctrl_constraints._choices) ):
-            wxComboBox.Clear(self)
+        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:
-                wxComboBox.Append( self, choice )
+                wx.ComboBox.Append( self, choice )
 
 
     def GetMark(self):
@@ -6317,33 +6487,33 @@ class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
         works, but has the nasty side effect of generating lots of intermediate
         events.
         """
-        dbg(suspend=1)  # turn off debugging around this function
-        dbg('wxMaskedComboBox::GetMark', indent=1)
+##        dbg(suspend=1)  # turn off debugging around this function
+##        dbg('MaskedComboBox::GetMark', indent=1)
         if self.__readonly:
-            dbg(indent=0)
+##            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)
+##        dbg("current sel_start:", sel_start)
         value = self.GetValue()
-        dbg('value: "%s"' % value)
+##        dbg('value: "%s"' % value)
 
         self._ignoreChange = True               # tell _OnTextChange() to ignore next event (if any)
 
-        wxComboBox.Cut(self)
+        wx.ComboBox.Cut(self)
         newvalue = self.GetValue()
-        dbg("value after Cut operation:", newvalue)
+##        dbg("value after Cut operation:", newvalue)
 
         if newvalue != value:                   # something was selected; calculate extent
-            dbg("something selected")
+##            dbg("something selected")
             sel_to = sel_start + len(value) - len(newvalue)
-            wxComboBox.SetValue(self, value)    # restore original value and selection (still ignoring change)
-            wxComboBox.SetInsertionPoint(self, sel_start)
-            wxComboBox.SetMark(self, sel_start, sel_to)
+            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)
+##        dbg('computed selection:', sel_start, sel_to, indent=0, suspend=0)
         return sel_start, sel_to
 
 
@@ -6352,12 +6522,12 @@ class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
         Necessary for bookkeeping on choice selection, to keep current value
         current.
         """
-        dbg('wxMaskedComboBox::SetSelection(%d)' % index)
+##        dbg('MaskedComboBox::SetSelection(%d)' % index)
         if self._mask:
             self._prevValue = self._curValue
             self._curValue = self._choices[index]
             self._ctrl_constraints._autoCompleteIndex = index
-        wxComboBox.SetSelection(self, index)
+        wx.ComboBox.SetSelection(self, index)
 
 
     def OnKeyDown(self, event):
@@ -6380,7 +6550,7 @@ class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
         on the text of the control somehow interferes with the combobox's
         selection mechanism for the arrow keys.
         """
-        dbg('wxMaskedComboBox::OnSelectChoice', indent=1)
+##        dbg('MaskedComboBox::OnSelectChoice', indent=1)
 
         if not self._mask:
             event.Skip()
@@ -6391,7 +6561,7 @@ class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
         if self._ctrl_constraints._compareNoCase:
             value = value.lower()
 
-        if event.GetKeyCode() == WXK_UP:
+        if event.GetKeyCode() == wx.WXK_UP:
             direction = -1
         else:
             direction = 1
@@ -6402,7 +6572,7 @@ class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
                                                 self._ctrl_constraints._compareNoCase,
                                                 current_index = self._ctrl_constraints._autoCompleteIndex)
         if match_index is not None:
-            dbg('setting selection to', match_index)
+##            dbg('setting selection to', match_index)
             # issue appropriate event to outside:
             self._OnAutoSelect(self._ctrl_constraints, match_index=match_index)
             self._CheckValid()
@@ -6411,15 +6581,15 @@ class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
             pos = self._adjustPos(self._GetInsertionPoint(), event.GetKeyCode())
             field = self._FindField(pos)
             if self.IsEmpty() or not field._hasList:
-                dbg('selecting 1st value in list')
+##                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)
+##                dbg(indent=0)
                 keep_processing = self._OnAutoCompleteField(event)
-        dbg('keep processing?', keep_processing, indent=0)
+##        dbg('keep processing?', keep_processing, indent=0)
         return keep_processing
 
 
@@ -6428,17 +6598,17 @@ class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
         Override mixin (empty) autocomplete handler, so that autocompletion causes
         combobox to update appropriately.
         """
-        dbg('wxMaskedComboBox::OnAutoSelect', field._index, indent=1)
+##        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')
+##            dbg('issuing combo selection event')
             self.GetEventHandler().ProcessEvent(
-                wxMaskedComboBoxSelectEvent( self.GetId(), match_index, self ) )
+                MaskedComboBoxSelectEvent( self.GetId(), match_index, self ) )
         self._CheckValid()
-        dbg('field._autoCompleteIndex:', match_index)
-        dbg('self.GetSelection():', self.GetSelection())
-        dbg(indent=0)
+##        dbg('field._autoCompleteIndex:', match_index)
+##        dbg('self.GetSelection():', self.GetSelection())
+##        dbg(indent=0)
 
 
     def _OnReturn(self, event):
@@ -6451,31 +6621,81 @@ class wxMaskedComboBox( wxComboBox, wxMaskedEditMixin ):
         programmatic wxComboBox.SetSelection() call to pick the appropriate
         item in the list. (and then do the usual OnReturn bit.)
         """
-        dbg('wxMaskedComboBox::OnReturn', indent=1)
-        dbg('current value: "%s"' % self.GetValue(), 'current index:', self.GetSelection())
+##        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:
-            wxCallAfter(self.SetSelection, self._ctrl_constraints._autoCompleteIndex)
+            wx.CallAfter(self.SetSelection, self._ctrl_constraints._autoCompleteIndex)
 
-        event.m_keyCode = WXK_TAB
+        event.m_keyCode = wx.WXK_TAB
         event.Skip()
-        dbg(indent=0)
+##        dbg(indent=0)
+
+
+class MaskedComboBox( 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
 
 
 ## ---------- ---------- ---------- ---------- ---------- ---------- ----------
 
-class wxIpAddrCtrl( wxMaskedTextCtrl ):
+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 wxMaskedTextCtrl that accepts
+    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 = wxDefaultPosition,
-                  size = wxDefaultSize,
-                  style = wxTE_PROCESS_TAB,
-                  validator = wxDefaultValidator,
-                  name = 'wxIpAddrCtrl',
+                  pos = wx.DefaultPosition,
+                  size = wx.DefaultSize,
+                  style = wx.TE_PROCESS_TAB,
+                  validator = wx.DefaultValidator,
+                  name = 'IpAddrCtrl',
                   setupEventHandling = True,        ## setup event handling by default
                   **kwargs):
 
@@ -6487,7 +6707,7 @@ class wxIpAddrCtrl( wxMaskedTextCtrl ):
             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}"
 
 
-        wxMaskedTextCtrl.__init__(
+        BaseMaskedTextCtrl.__init__(
                 self, parent, id=id, value = value,
                 pos=pos, size=size,
                 style = style,
@@ -6496,6 +6716,7 @@ class wxIpAddrCtrl( wxMaskedTextCtrl ):
                 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]))"
@@ -6514,7 +6735,7 @@ class wxIpAddrCtrl( wxMaskedTextCtrl ):
 
 
     def OnDot(self, event):
-        dbg('wxIpAddrCtrl::OnDot', indent=1)
+##        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)
@@ -6525,29 +6746,29 @@ class wxIpAddrCtrl( wxMaskedTextCtrl ):
                 newvalue = oldvalue[:pos] + ' ' * (edit_end - pos) + oldvalue[edit_end:]
                 self._SetValue(newvalue)
                 self._SetInsertionPoint(pos)
-        dbg(indent=0)
+##        dbg(indent=0)
         return self._OnChangeField(event)
 
 
 
     def GetAddress(self):
-        value = wxMaskedTextCtrl.GetValue(self)
+        value = BaseMaskedTextCtrl.GetValue(self)
         return value.replace(' ','')    # remove spaces from the value
 
 
     def _OnCtrl_S(self, event):
-        dbg("wxIpAddrCtrl::_OnCtrl_S")
+##        dbg("IpAddrCtrl::_OnCtrl_S")
         if self._demo:
             print "value:", self.GetAddress()
         return False
 
     def SetValue(self, value):
-        dbg('wxIpAddrCtrl::SetValue(%s)' % str(value), indent=1)
+##        dbg('IpAddrCtrl::SetValue(%s)' % str(value), indent=1)
         if type(value) not in (types.StringType, types.UnicodeType):
-            dbg(indent=0)
+##            dbg(indent=0)
             raise ValueError('%s must be a string', str(value))
 
-        bValid = True   # assume true
+        bValid = True   # assume True
         parts = value.split('.')
         if len(parts) != 4:
             bValid = False
@@ -6574,13 +6795,13 @@ class wxIpAddrCtrl( wxMaskedTextCtrl ):
                     parts[i] = '   '    # convert empty field to 3-char length
 
         if not bValid:
-            dbg(indent=0)
+##            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)
+##            dbg('parts:', parts)
             value = string.join(parts, '.')
-            wxMaskedTextCtrl.SetValue(self, value)
-        dbg(indent=0)
+            BaseMaskedTextCtrl.SetValue(self, value)
+##        dbg(indent=0)
 
 
 ## ---------- ---------- ---------- ---------- ---------- ---------- ----------
@@ -6695,31 +6916,31 @@ def getDay(dateStr,dateFmt):
     return parts[2]
 
 ## ---------- ---------- ---------- ---------- ---------- ---------- ----------
-class test(wxPySimpleApp):
+class test(wx.PySimpleApp):
         def OnInit(self):
-            from wxPython.lib.rcsizer import RowColSizer
-            self.frame = wxFrame( NULL, -1, "wxMaskedEditMixin 0.0.7 Demo Page #1", size = (700,600))
-            self.panel = wxPanel( self.frame, -1)
+            from wx.lib.rcsizer import RowColSizer
+            self.frame = wx.Frame( None, -1, "MaskedEditMixin 0.0.7 Demo Page #1", size = (700,600))
+            self.panel = wx.Panel( self.frame, -1)
             self.sizer = RowColSizer()
             self.labels = []
             self.editList  = []
             rowcount    = 4
 
-            id, id1 = wxNewId(), wxNewId()
-            self.command1  = wxButton( self.panel, id, "&Close" )
-            self.command2  = wxButton( self.panel, id1, "&AutoFormats" )
-            self.sizer.Add(self.command1, row=0, col=0, flag=wxALL, border = 5)
-            self.sizer.Add(self.command2, row=0, col=1, colspan=2, flag=wxALL, border = 5)
-            EVT_BUTTON( self.panel, id, self.onClick )
+            id, id1 = wx.NewId(), wx.NewId()
+            self.command1  = wx.Button( self.panel, id, "&Close" )
+            self.command2  = wx.Button( self.panel, id1, "&AutoFormats" )
+            self.sizer.Add(self.command1, row=0, col=0, flag=wx.ALL, border = 5)
+            self.sizer.Add(self.command2, row=0, col=1, colspan=2, flag=wx.ALL, border = 5)
+            self.panel.Bind(wx.EVT_BUTTON, self.onClick, self.command1 )
 ##            self.panel.SetDefaultItem(self.command1 )
-            EVT_BUTTON( self.panel, id1, self.onClickPage )
+            self.panel.Bind(wx.EVT_BUTTON, self.onClickPage, self.command2)
 
-            self.check1 = wxCheckBox( self.panel, -1, "Disallow Empty" )
-            self.check2 = wxCheckBox( self.panel, -1, "Highlight Empty" )
-            self.sizer.Add( self.check1, row=0,col=3, flag=wxALL,border=5 )
-            self.sizer.Add( self.check2, row=0,col=4, flag=wxALL,border=5 )
-            EVT_CHECKBOX( self.panel, self.check1.GetId(), self._onCheck1 )
-            EVT_CHECKBOX( self.panel, self.check2.GetId(), self._onCheck2 )
+            self.check1 = wx.CheckBox( self.panel, -1, "Disallow Empty" )
+            self.check2 = wx.CheckBox( self.panel, -1, "Highlight Empty" )
+            self.sizer.Add( self.check1, row=0,col=3, flag=wx.ALL,border=5 )
+            self.sizer.Add( self.check2, row=0,col=4, flag=wx.ALL,border=5 )
+            self.panel.Bind(wx.EVT_CHECKBOX, self._onCheck1, self.check1 )
+            self.panel.Bind(wx.EVT_CHECKBOX, self._onCheck2, self.check2 )
 
 
             label = """Press ctrl-s in any field to output the value and plain value. Press ctrl-x to clear and re-set any field.
@@ -6727,28 +6948,28 @@ Note that all controls have been auto-sized by including F in the format code.
 Try entering nonsensical or partial values in validated fields to see what happens (use ctrl-s to test the valid status)."""
             label2 = "\nNote that the State and Last Name fields are list-limited (Name:Smith,Jones,Williams)."
 
-            self.label1 = wxStaticText( self.panel, -1, label)
-            self.label2 = wxStaticText( self.panel, -1, "Description")
-            self.label3 = wxStaticText( self.panel, -1, "Mask Value")
-            self.label4 = wxStaticText( self.panel, -1, "Format")
-            self.label5 = wxStaticText( self.panel, -1, "Reg Expr Val. (opt)")
-            self.label6 = wxStaticText( self.panel, -1, "wxMaskedEdit Ctrl")
-            self.label7 = wxStaticText( self.panel, -1, label2)
+            self.label1 = wx.StaticText( self.panel, -1, label)
+            self.label2 = wx.StaticText( self.panel, -1, "Description")
+            self.label3 = wx.StaticText( self.panel, -1, "Mask Value")
+            self.label4 = wx.StaticText( self.panel, -1, "Format")
+            self.label5 = wx.StaticText( self.panel, -1, "Reg Expr Val. (opt)")
+            self.label6 = wx.StaticText( self.panel, -1, "wxMaskedEdit Ctrl")
+            self.label7 = wx.StaticText( self.panel, -1, label2)
             self.label7.SetForegroundColour("Blue")
             self.label1.SetForegroundColour("Blue")
-            self.label2.SetFont(wxFont(9,wxSWISS,wxNORMAL,wxBOLD))
-            self.label3.SetFont(wxFont(9,wxSWISS,wxNORMAL,wxBOLD))
-            self.label4.SetFont(wxFont(9,wxSWISS,wxNORMAL,wxBOLD))
-            self.label5.SetFont(wxFont(9,wxSWISS,wxNORMAL,wxBOLD))
-            self.label6.SetFont(wxFont(9,wxSWISS,wxNORMAL,wxBOLD))
-
-            self.sizer.Add( self.label1, row=1,col=0,colspan=7, flag=wxALL,border=5)
-            self.sizer.Add( self.label7, row=2,col=0,colspan=7, flag=wxALL,border=5)
-            self.sizer.Add( self.label2, row=3,col=0, flag=wxALL,border=5)
-            self.sizer.Add( self.label3, row=3,col=1, flag=wxALL,border=5)
-            self.sizer.Add( self.label4, row=3,col=2, flag=wxALL,border=5)
-            self.sizer.Add( self.label5, row=3,col=3, flag=wxALL,border=5)
-            self.sizer.Add( self.label6, row=3,col=4, flag=wxALL,border=5)
+            self.label2.SetFont(wx.Font(9,wx.SWISS,wx.NORMAL,wx.BOLD))
+            self.label3.SetFont(wx.Font(9,wx.SWISS,wx.NORMAL,wx.BOLD))
+            self.label4.SetFont(wx.Font(9,wx.SWISS,wx.NORMAL,wx.BOLD))
+            self.label5.SetFont(wx.Font(9,wx.SWISS,wx.NORMAL,wx.BOLD))
+            self.label6.SetFont(wx.Font(9,wx.SWISS,wx.NORMAL,wx.BOLD))
+
+            self.sizer.Add( self.label1, row=1,col=0,colspan=7, flag=wx.ALL,border=5)
+            self.sizer.Add( self.label7, row=2,col=0,colspan=7, flag=wx.ALL,border=5)
+            self.sizer.Add( self.label2, row=3,col=0, flag=wx.ALL,border=5)
+            self.sizer.Add( self.label3, row=3,col=1, flag=wx.ALL,border=5)
+            self.sizer.Add( self.label4, row=3,col=2, flag=wx.ALL,border=5)
+            self.sizer.Add( self.label5, row=3,col=3, flag=wx.ALL,border=5)
+            self.sizer.Add( self.label6, row=3,col=4, flag=wx.ALL,border=5)
 
             # The following list is of the controls for the demo. Feel free to play around with
             # the options!
@@ -6772,13 +6993,13 @@ Try entering nonsensical or partial values in validated fields to see what happe
            ]
 
             for control in controls:
-                self.sizer.Add( wxStaticText( self.panel, -1, control[0]),row=rowcount, col=0,border=5,flag=wxALL)
-                self.sizer.Add( wxStaticText( self.panel, -1, control[1]),row=rowcount, col=1,border=5, flag=wxALL)
-                self.sizer.Add( wxStaticText( self.panel, -1, control[3]),row=rowcount, col=2,border=5, flag=wxALL)
-                self.sizer.Add( wxStaticText( self.panel, -1, control[4][:20]),row=rowcount, col=3,border=5, flag=wxALL)
+                self.sizer.Add( wx.StaticText( self.panel, -1, control[0]),row=rowcount, col=0,border=5,flag=wx.ALL)
+                self.sizer.Add( wx.StaticText( self.panel, -1, control[1]),row=rowcount, col=1,border=5, flag=wx.ALL)
+                self.sizer.Add( wx.StaticText( self.panel, -1, control[3]),row=rowcount, col=2,border=5, flag=wx.ALL)
+                self.sizer.Add( wx.StaticText( self.panel, -1, control[4][:20]),row=rowcount, col=3,border=5, flag=wx.ALL)
 
                 if control in controls[:]:#-2]:
-                    newControl  = wxMaskedTextCtrl( self.panel, -1, "",
+                    newControl  = MaskedTextCtrl( self.panel, -1, "",
                                                     mask         = control[1],
                                                     excludeChars = control[2],
                                                     formatcodes  = control[3],
@@ -6790,7 +7011,7 @@ Try entering nonsensical or partial values in validated fields to see what happe
                                                     demo         = True)
                     if control[6]: newControl.SetCtrlParameters(choiceRequired = True)
                 else:
-                    newControl = wxMaskedComboBox(  self.panel, -1, "",
+                    newControl = MaskedComboBox(  self.panel, -1, "",
                                                     choices = control[7],
                                                     choiceRequired  = True,
                                                     mask         = control[1],
@@ -6802,7 +7023,7 @@ Try entering nonsensical or partial values in validated fields to see what happe
                                                     demo         = True)
                 self.editList.append( newControl )
 
-                self.sizer.Add( newControl, row=rowcount,col=4,flag=wxALL,border=5)
+                self.sizer.Add( newControl, row=rowcount,col=4,flag=wx.ALL,border=5)
                 rowcount += 1
 
             self.sizer.AddGrowableCol(4)
@@ -6824,7 +7045,7 @@ Try entering nonsensical or partial values in validated fields to see what happe
 
         def _onCheck1(self,event):
             """ Set required value on/off """
-            value = event.Checked()
+            value = event.IsChecked()
             if value:
                 for control in self.editList:
                     control.SetCtrlParameters(emptyInvalid=True)
@@ -6837,7 +7058,7 @@ Try entering nonsensical or partial values in validated fields to see what happe
 
         def _onCheck2(self,event):
             """ Highlight empty values"""
-            value = event.Checked()
+            value = event.IsChecked()
             if value:
                 for control in self.editList:
                     control.SetCtrlParameters( emptyBackgroundColour = 'Aquamarine')
@@ -6851,11 +7072,11 @@ Try entering nonsensical or partial values in validated fields to see what happe
 
 ## ---------- ---------- ---------- ---------- ---------- ---------- ----------
 
-class test2(wxFrame):
+class test2(wx.Frame):
         def __init__(self, parent, id, caption):
-            wxFrame.__init__( self, parent, id, "wxMaskedEdit control 0.0.7 Demo Page #2 -- AutoFormats", size = (550,600))
-            from wxPython.lib.rcsizer import RowColSizer
-            self.panel = wxPanel( self, -1)
+            wx.Frame.__init__( self, parent, id, "wxMaskedEdit control 0.0.7 Demo Page #2 -- AutoFormats", size = (550,600))
+            from wx.lib.rcsizer import RowColSizer
+            self.panel = wx.Panel( self, -1)
             self.sizer = RowColSizer()
             self.labels = []
             self.texts  = []
@@ -6866,26 +7087,26 @@ All these controls have been created by passing a single parameter, the AutoForm
 The class contains an internal dictionary of types and formats (autoformats).
 To see a great example of validations in action, try entering a bad email address, then tab out."""
 
-            self.label1 = wxStaticText( self.panel, -1, label)
-            self.label2 = wxStaticText( self.panel, -1, "Description")
-            self.label3 = wxStaticText( self.panel, -1, "AutoFormat Code")
-            self.label4 = wxStaticText( self.panel, -1, "wxMaskedEdit Control")
+            self.label1 = wx.StaticText( self.panel, -1, label)
+            self.label2 = wx.StaticText( self.panel, -1, "Description")
+            self.label3 = wx.StaticText( self.panel, -1, "AutoFormat Code")
+            self.label4 = wx.StaticText( self.panel, -1, "wxMaskedEdit Control")
             self.label1.SetForegroundColour("Blue")
-            self.label2.SetFont(wxFont(9,wxSWISS,wxNORMAL,wxBOLD))
-            self.label3.SetFont(wxFont(9,wxSWISS,wxNORMAL,wxBOLD))
-            self.label4.SetFont(wxFont(9,wxSWISS,wxNORMAL,wxBOLD))
-
-            self.sizer.Add( self.label1, row=1,col=0,colspan=3, flag=wxALL,border=5)
-            self.sizer.Add( self.label2, row=3,col=0, flag=wxALL,border=5)
-            self.sizer.Add( self.label3, row=3,col=1, flag=wxALL,border=5)
-            self.sizer.Add( self.label4, row=3,col=2, flag=wxALL,border=5)
-
-            id, id1 = wxNewId(), wxNewId()
-            self.command1  = wxButton( self.panel, id, "&Close")
-            self.command2  = wxButton( self.panel, id1, "&Print Formats")
-            EVT_BUTTON( self.panel, id, self.onClick)
+            self.label2.SetFont(wx.Font(9,wx.SWISS,wx.NORMAL,wx.BOLD))
+            self.label3.SetFont(wx.Font(9,wx.SWISS,wx.NORMAL,wx.BOLD))
+            self.label4.SetFont(wx.Font(9,wx.SWISS,wx.NORMAL,wx.BOLD))
+
+            self.sizer.Add( self.label1, row=1,col=0,colspan=3, flag=wx.ALL,border=5)
+            self.sizer.Add( self.label2, row=3,col=0, flag=wx.ALL,border=5)
+            self.sizer.Add( self.label3, row=3,col=1, flag=wx.ALL,border=5)
+            self.sizer.Add( self.label4, row=3,col=2, flag=wx.ALL,border=5)
+
+            id, id1 = wx.NewId(), wx.NewId()
+            self.command1  = wx.Button( self.panel, id, "&Close")
+            self.command2  = wx.Button( self.panel, id1, "&Print Formats")
+            self.panel.Bind(wx.EVT_BUTTON, self.onClick, self.command1)
             self.panel.SetDefaultItem(self.command1)
-            EVT_BUTTON( self.panel, id1, self.onClickPrint)
+            self.panel.Bind(wx.EVT_BUTTON, self.onClickPrint, self.command2)
 
             # The following list is of the controls for the demo. Feel free to play around with
             # the options!
@@ -6894,7 +7115,7 @@ To see a great example of validations in action, try entering a bad email addres
            ("US Date + Time","USDATETIMEMMDDYYYY/HHMM"),
            ("US Date MMDDYYYY","USDATEMMDDYYYY/"),
            ("Time (with seconds)","TIMEHHMMSS"),
-           ("Military Time\n(without seconds)","MILTIMEHHMM"),
+           ("Military Time\n(without seconds)","24HRTIMEHHMM"),
            ("Social Sec#","USSOCIALSEC"),
            ("Credit Card","CREDITCARD"),
            ("Expiration MM/YY","EXPDATEMMYY"),
@@ -6903,24 +7124,24 @@ To see a great example of validations in action, try entering a bad email addres
            ("US Zip Code","USZIP"),
            ("US Zip+4","USZIPPLUS4"),
            ("Email Address","EMAIL"),
-           ("IP Address", "(derived control wxIpAddrCtrl)")
+           ("IP Address", "(derived control IpAddrCtrl)")
            ]
 
             for control in controls:
-                self.sizer.Add( wxStaticText( self.panel, -1, control[0]),row=rowcount, col=0,border=5,flag=wxALL)
-                self.sizer.Add( wxStaticText( self.panel, -1, control[1]),row=rowcount, col=1,border=5, flag=wxALL)
+                self.sizer.Add( wx.StaticText( self.panel, -1, control[0]),row=rowcount, col=0,border=5,flag=wx.ALL)
+                self.sizer.Add( wx.StaticText( self.panel, -1, control[1]),row=rowcount, col=1,border=5, flag=wx.ALL)
                 if control in controls[:-1]:
-                    self.sizer.Add( wxMaskedTextCtrl( self.panel, -1, "",
+                    self.sizer.Add( MaskedTextCtrl( self.panel, -1, "",
                                                       autoformat  = control[1],
                                                       demo        = True),
-                                row=rowcount,col=2,flag=wxALL,border=5)
+                                row=rowcount,col=2,flag=wx.ALL,border=5)
                 else:
-                    self.sizer.Add( wxIpAddrCtrl( self.panel, -1, "", demo=True ),
-                                    row=rowcount,col=2,flag=wxALL,border=5)
+                    self.sizer.Add( IpAddrCtrl( self.panel, -1, "", demo=True ),
+                                    row=rowcount,col=2,flag=wx.ALL,border=5)
                 rowcount += 1
 
-            self.sizer.Add(self.command1, row=0, col=0, flag=wxALL, border = 5)
-            self.sizer.Add(self.command2, row=0, col=1, flag=wxALL, border = 5)
+            self.sizer.Add(self.command1, row=0, col=0, flag=wx.ALL, border = 5)
+            self.sizer.Add(self.command2, row=0, col=1, flag=wx.ALL, border = 5)
             self.sizer.AddGrowableCol(3)
 
             self.panel.SetSizer(self.sizer)
@@ -6937,7 +7158,7 @@ To see a great example of validations in action, try entering a bad email addres
 ## ---------- ---------- ---------- ---------- ---------- ---------- ----------
 
 if __name__ == "__main__":
-    app = test()
+    app = test(False)
 
 i=1
 ##
@@ -6951,14 +7172,14 @@ i=1
 ##      control in the EVT_TEXT handler, and if *different*, call event.Skip()
 ##      to propagate it down the event chain, and let the application see it.
 ##
-## 2. WS: wxMaskedComboBox is deficient in several areas, all having to do with the
+## 2. WS: MaskedComboBox is deficient in several areas, all having to do with the
 ##      behavior of the underlying control that I can't fix.  The problems are:
 ##      a) The background coloring doesn't work in the text field of the control;
 ##         instead, there's a only border around it that assumes the correct color.
 ##      b) The control will not pass WXK_TAB to the event handler, no matter what
 ##         I do, and there's no style wxCB_PROCESS_TAB like wxTE_PROCESS_TAB to
-##         indicate that we want these events.  As a result, wxMaskedComboBox
-##         doesn't do the nice field-tabbing that wxMaskedTextCtrl does.
+##         indicate that we want these events.  As a result, MaskedComboBox
+##         doesn't do the nice field-tabbing that MaskedTextCtrl does.
 ##      c) Auto-complete had to be reimplemented for the control because programmatic
 ##         setting of the value of the text field does not set up the auto complete
 ##         the way that the control processing keystrokes does.  (But I think I've
@@ -6969,7 +7190,7 @@ i=1
 ##         implemented has its flaws, not the least of which is that due to the
 ##         strategy that I'm using, the paste buffer is always replaced by the
 ##         contents of the control's selection when in focus, on each keystroke;
-##         this makes it impossible to paste anything into a wxMaskedComboBox
+##         this makes it impossible to paste anything into a MaskedComboBox
 ##         at the moment... :-(
 ##      e) The other deficient behavior, likely induced by the workaround for (d),
 ##         is that you can can't shift-left to select more than one character
@@ -6978,8 +7199,8 @@ i=1
 ##
 ## 3. WS: Controls on wxPanels don't seem to pass Shift-WXK_TAB to their
 ##      EVT_KEY_DOWN or EVT_CHAR event handlers.  Until this is fixed in
-##      wxWindows, shift-tab won't take you backwards through the fields of
-##      a wxMaskedTextCtrl like it should.  Until then Shifted arrow keys will
+##      wxWidgets, shift-tab won't take you backwards through the fields of
+##      a MaskedTextCtrl like it should.  Until then Shifted arrow keys will
 ##      work like shift-tab and tab ought to.
 ##
 
@@ -6989,7 +7210,7 @@ i=1
 ##     fields.  Example: City validates against list of cities, or zip vs zip code list.
 ##  2. Allow optional monetary symbols (eg. $, pounds, etc.) at front of a "decimal"
 ##     control.
-##  3. Fix shift-left selection for wxMaskedComboBox.
+##  3. Fix shift-left selection for MaskedComboBox.
 ##  5. Transform notion of "decimal control" to be less "entire control"-centric,
 ##     so that monetary symbols can be included and still have the appropriate
 ##     semantics.  (Big job, as currently written, but would make control even
@@ -6998,19 +7219,41 @@ i=1
 
 ## CHANGELOG:
 ## ====================
+##  Version 1.5
+##  (Reported) bugs fixed:
+##   1. Crash ensues if you attempt to change the mask of a read-only
+##      MaskedComboBox after initial construction.
+##   2. Changed strategy of defining Get/Set property functions so that
+##      these are now generated dynamically at runtime, rather than as
+##      part of the class definition.  (This makes it possible to have
+##      more general base classes that have many more options for configuration
+##      without requiring that derivations support the same options.)
+##   3. Fixed IsModified for _Paste() and _OnErase().
+##
+##   Enhancements:
+##   1. Fixed "attribute function inheritance," since base control is more
+##      generic than subsequent derivations, not all property functions of a
+##      generic control should be exposed in those derivations.  New strategy
+##      uses base control classes (eg. BaseMaskedTextCtrl) that should be
+##      used to derive new class types, and mixed with their own mixins to
+##      only expose those attributes from the generic masked controls that
+##      make sense for the derivation.  (This makes Boa happier.)
+##   2. Renamed (with b-c) MILTIME autoformats to 24HRTIME, so as to be less
+##      "parochial."
+##
 ##  Version 1.4
 ##  (Reported) bugs fixed:
 ##   1. Right-click menu allowed "cut" operation that destroyed mask
 ##      (was implemented by base control)
-##   2. wxMaskedComboBox didn't allow .Append() of mixed-case values; all
+##   2. MaskedComboBox didn't allow .Append() of mixed-case values; all
 ##      got converted to lower case.
-##   3. wxMaskedComboBox selection didn't deal with spaces in values
+##   3. MaskedComboBox selection didn't deal with spaces in values
 ##      properly when autocompleting, and didn't have a concept of "next"
 ##      match for handling choice list duplicates.
-##   4. Size of wxMaskedComboBox was always default.
+##   4. Size of MaskedComboBox was always default.
 ##   5. Email address regexp allowed some "non-standard" things, and wasn't
 ##      general enough.
-##   6. Couldn't easily reset wxMaskedComboBox contents programmatically.
+##   6. Couldn't easily reset MaskedComboBox contents programmatically.
 ##   7. Couldn't set emptyInvalid during construction.
 ##   8. Under some versions of wxPython, readonly comboboxes can apparently
 ##      return a GetInsertionPoint() result (655535), causing masked control
@@ -7085,7 +7328,7 @@ i=1
 ##  13. Fixed a couple of coding bugs being flagged by Python2.1.
 ##  14. Fixed several issues with sign positioning, erasure and validity
 ##      checking for "numeric" masked controls.
-##  15. Added validation to wxIpAddrCtrl.SetValue().
+##  15. Added validation to IpAddrCtrl.SetValue().
 ##
 ##  Version 1.1
 ##   1. Changed calling interface to use boolean "useFixedWidthFont" (True by default)
@@ -7109,7 +7352,7 @@ i=1
 ##      fixed failure to obey case conversion codes when pasting.
 ##  11. Implemented '0' (zero-pad) formatting code, as it wasn't being done anywhere...
 ##  12. Removed condition from OnDecimalPoint, so that it always truncates right on '.'
-##  13. Enhanced wxIpAddrCtrl to use right-insert fields, selection on field traversal,
+##  13. Enhanced IpAddrCtrl to use right-insert fields, selection on field traversal,
 ##      individual field validation to prevent field values > 255, and require explicit
 ##      tab/. to change fields.
 ##  14. Added handler for left double-click to select field under cursor.
@@ -7118,7 +7361,7 @@ i=1
 ##      attribute, for more consistent and controllable coloring.
 ##  17. Added retainFieldValidation parameter, allowing top-level constraints
 ##      such as "validRequired" to be set independently of field-level equivalent.
-##      (needed in wxTimeCtrl for bounds constraints.)
+##      (needed in TimeCtrl for bounds constraints.)
 ##  18. Refactored code a bit, cleaned up and commented code more heavily, fixed
 ##      some of the logic for setting/resetting parameters, eg. fillChar, defaultValue,
 ##      etc.
@@ -7155,9 +7398,9 @@ i=1
 ##      than making assumptions about character width.
 ##   7. Fixed GetMaskParameter(), which was non-functional in previous version.
 ##   8. Fixed exceptions raised to provide info on which control had the error.
-##   9. Fixed bug in choice management of wxMaskedComboBox.
-##  10. Fixed bug in wxIpAddrCtrl causing traceback if field value was of
-##     the form '# #'.  Modified control code for wxIpAddrCtrl so that '.'
+##   9. Fixed bug in choice management of MaskedComboBox.
+##  10. Fixed bug in IpAddrCtrl causing traceback if field value was of
+##     the form '# #'.  Modified control code for IpAddrCtrl so that '.'
 ##     in the middle of a field clips the rest of that field, similar to
 ##     decimal and integer controls.
 ##
@@ -7185,14 +7428,14 @@ i=1
 ##      is not desired in every position.  Added IsDefault() function to mean "does the value
 ##      equal the template?" and modified .IsEmpty() to mean "do all of the editable
 ##      positions in the template == the fillChar?"
-##  10. Extracted mask logic into mixin, so we can have both wxMaskedTextCtrl and wxMaskedComboBox,
+##  10. Extracted mask logic into mixin, so we can have both MaskedTextCtrl and MaskedComboBox,
 ##      now included.
-##  11. wxMaskedComboBox now adds the capability to validate from list of valid values.
+##  11. MaskedComboBox now adds the capability to validate from list of valid values.
 ##      Example: City validates against list of cities, or zip vs zip code list.
 ##  12. Fixed oversight in EVT_TEXT handler that prevented the events from being
 ##      passed to the next handler in the event chain, causing updates to the
 ##      control to be invisible to the parent code.
-##  13. Added IPADDR autoformat code, and subclass wxIpAddrCtrl for controlling tabbing within
+##  13. Added IPADDR autoformat code, and subclass IpAddrCtrl for controlling tabbing within
 ##      the control, that auto-reformats as you move between cells.
 ##  14. Mask characters [A,a,X,#] can now appear in the format string as literals, by using '\'.
 ##  15. It is now possible to specify repeating masks, e.g. #{3}-#{3}-#{14}
@@ -7213,7 +7456,7 @@ i=1
 ##  19. Enhanced tabbing logic so that tab takes you to the next field if the
 ##      control is a multi-field control.
 ##  20. Added stub method called whenever the control "changes fields", that
-##      can be overridden by subclasses (eg. wxIpAddrCtrl.)
+##      can be overridden by subclasses (eg. IpAddrCtrl.)
 ##  21. Changed a lot of code to be more functionally-oriented so side-effects
 ##      aren't as problematic when maintaining code and/or adding features.
 ##      Eg: IsValid() now does not have side-effects; it merely reflects the
@@ -7277,7 +7520,7 @@ i=1
 ##      (i.e. disallow empty values if True).
 ##
 ##  Version 0.0.5
-##   1. get_plainValue method renamed to GetPlainValue following the wxWindows
+##   1. get_plainValue method renamed to GetPlainValue following the wxWidgets
 ##      StudlyCaps(tm) standard (thanks Paul Moore).  ;)
 ##   2. New format code 'F' causes the control to auto-fit (auto-size) itself
 ##      based on the length of the mask template.
@@ -7342,7 +7585,7 @@ i=1
 ##   4. Home and End keys now supported to move cursor to beginning or end of field.
 ##   5. Un-signed integers and decimals now supported.
 ##   6. Cosmetic improvements to the demo.
-##   7. Class renamed to wxMaskedTextCtrl.
+##   7. Class renamed to MaskedTextCtrl.
 ##   8. Can now specify include characters that will override the basic
 ##      controls: for example, includeChars = "@." for email addresses
 ##   9. Added mask character 'C' -> allow any upper or lowercase character