]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/wx/lib/masked/textctrl.py
wxSscanf() and friends are now Unicode+ANSI friendly wrappers instead of defines...
[wxWidgets.git] / wxPython / wx / lib / masked / textctrl.py
index d73fbe4a4e3412fe00b992b55866c442e7143ac3..a2953913fc11f9c9a0f97909266394bc6cf15f59 100644 (file)
 # masked.TimeCtrl, and masked.IpAddrCtrl.
 #
 #----------------------------------------------------------------------------
+"""
+Provides a generic, fully configurable masked edit text control, as well as
+a base class from which you can derive masked controls tailored to a specific
+function.  See maskededit module overview for how to configure the control.
+"""
+
 import  wx
 from wx.lib.masked import *
 
 # jmg 12/9/03 - when we cut ties with Py 2.2 and earlier, this would
 # be a good place to implement the 2.3 logger class
 from wx.tools.dbg import Logger
-dbg = Logger()
-##dbg(enable=0)
-
-# ## TRICKY BIT: to avoid a ton of boiler-plate, and to
-# ## automate the getter/setter generation for each valid
-# ## control parameter so we never forget to add the
-# ## functions when adding parameters, this loop
-# ## programmatically adds them to the class:
-# ## (This makes it easier for Designers like Boa to
-# ## deal with masked controls.)
-#
-# ## To further complicate matters, this is done with an
-# ## extra level of inheritance, so that "general" classes like
-# ## MaskedTextCtrl can have all possible attributes,
-# ## while derived classes, like TimeCtrl and MaskedNumCtrl
-# ## can prevent exposure of those optional attributes of their base
-# ## class that do not make sense for their derivation.  Therefore,
-# ## we define
-# ##    BaseMaskedTextCtrl(TextCtrl, MaskedEditMixin)
-# ## and
-# ##    MaskedTextCtrl(BaseMaskedTextCtrl, MaskedEditAccessorsMixin).
-# ##
-# ## This allows us to then derive:
-# ##    MaskedNumCtrl( BaseMaskedTextCtrl )
-# ##
-# ## and not have to expose all the same accessor functions for the
-# ## derived control when they don't all make sense for it.
-# ##
+##dbg = Logger()
+##dbg(enable=1)
+
 
 class BaseMaskedTextCtrl( wx.TextCtrl, MaskedEditMixin ):
     """
     This is the primary derivation from MaskedEditMixin.  It provides
     a general masked text control that can be configured with different
-    masks.  It's actually a "base masked textCtrl", so that the
-    MaskedTextCtrl class can be derived from it, and add those
-    accessor functions to it that are appropriate to the general class,
-    whilst other classes can derive from BaseMaskedTextCtrl, and
-    only define those accessor functions that are appropriate for
-    those derivations.
+    masks.
+
+    However, this is done with an extra level of inheritance, so that
+    "general" classes like masked.TextCtrl can have all possible attributes,
+    while derived classes, like masked.TimeCtrl and masked.NumCtrl
+    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::
+    
+        masked.TextCtrl(BaseMaskedTextCtrl, MaskedEditAccessorsMixin).
+
+    This allows us to then derive::
+    
+        masked.NumCtrl( BaseMaskedTextCtrl )
+
+    and not have to expose all the same accessor functions for the
+    derived control when they don't all make sense for it.
+
+    In practice, BaseMaskedTextCtrl should never be instantiated directly,
+    but should only be used in derived classes.
     """
 
     def __init__( self, parent, id=-1, value = '',
@@ -76,6 +75,13 @@ class BaseMaskedTextCtrl( wx.TextCtrl, MaskedEditMixin ):
                             style=style, validator=validator,
                             name=name)
 
+        self._PostInit(setupEventHandling = setupEventHandling,
+                      name=name, value=value,**kwargs )
+
+
+    def _PostInit(self,setupEventHandling=True,
+                 name='maskedTextCtrl' , value='', **kwargs):
+
         self.controlInitialized = True
         MaskedEditMixin.__init__( self, name, **kwargs )
 
@@ -112,12 +118,12 @@ class BaseMaskedTextCtrl( wx.TextCtrl, MaskedEditMixin ):
 ####        dbg("MaskedTextCtrl::_SetSelection(%(sel_start)d, %(sel_to)d)" % locals())
         return self.SetSelection( sel_start, sel_to )
 
-    def SetSelection(self, sel_start, sel_to):
-        """
-        This is just for debugging...
-        """
+##    def SetSelection(self, sel_start, sel_to):
+##        """
+##        This is just for debugging...
+##        """
 ##        dbg("MaskedTextCtrl::SetSelection(%(sel_start)d, %(sel_to)d)" % locals())
-        wx.TextCtrl.SetSelection(self, sel_start, sel_to)
+##        wx.TextCtrl.SetSelection(self, sel_start, sel_to)
 
 
     def _GetInsertionPoint(self):
@@ -127,13 +133,16 @@ class BaseMaskedTextCtrl( wx.TextCtrl, MaskedEditMixin ):
 ####        dbg("MaskedTextCtrl::_SetInsertionPoint(%(pos)d)" % locals())
         self.SetInsertionPoint(pos)
 
-    def SetInsertionPoint(self, pos):
-        """
-        This is just for debugging...
-        """
+##    def SetInsertionPoint(self, pos):
+##        """
+##        This is just for debugging...
+##        """
 ##        dbg("MaskedTextCtrl::SetInsertionPoint(%(pos)d)" % locals())
-        wx.TextCtrl.SetInsertionPoint(self, pos)
+##        wx.TextCtrl.SetInsertionPoint(self, pos)
+
 
+    def IsEmpty(*args, **kw):
+        return MaskedEditMixin.IsEmpty(*args, **kw)
 
     def _GetValue(self):
         """
@@ -142,29 +151,59 @@ class BaseMaskedTextCtrl( wx.TextCtrl, MaskedEditMixin ):
         """
         return self.GetValue()
 
+
     def _SetValue(self, value):
         """
         Allow mixin to set the raw value of the control with this function.
         REQUIRED by any class derived from MaskedEditMixin.
         """
-##        dbg('MaskedTextCtrl::_SetValue("%(value)s")' % locals(), indent=1)
+##        dbg('MaskedTextCtrl::_SetValue("%(value)s", use_change_value=%(use_change_value)d)' % locals(), indent=1)
         # Record current selection and insertion point, for undo
         self._prevSelection = self._GetSelection()
         self._prevInsertionPoint = self._GetInsertionPoint()
         wx.TextCtrl.SetValue(self, value)
 ##        dbg(indent=0)
 
+    def _ChangeValue(self, value):
+        """
+        Allow mixin to set the raw value of the control with this function without
+        generating an event as a result. (New for masked.TextCtrl as of 2.8.4)
+        """
+##        dbg('MaskedTextCtrl::_ChangeValue("%(value)s", use_change_value=%(use_change_value)d)' % locals(), indent=1)
+        # Record current selection and insertion point, for undo
+        self._prevSelection = self._GetSelection()
+        self._prevInsertionPoint = self._GetInsertionPoint()
+        wx.TextCtrl.ChangeValue(self, value)
+##        dbg(indent=0)
+
     def SetValue(self, value):
         """
-        This function redefines the externally accessible .SetValue to be
+        This function redefines the externally accessible .SetValue() to be
         a smart "paste" of the text in question, so as not to corrupt the
         masked control.  NOTE: this must be done in the class derived
         from the base wx control.
         """
-##        dbg('MaskedTextCtrl::SetValue = "%s"' % value, indent=1)
+        self.ModifyValue(value, use_change_value=False)
+
+    def ChangeValue(self, value):
+        """
+        Provided to accomodate similar functionality added to base control in wxPython 2.7.1.1.
+        """
+        self.ModifyValue(value, use_change_value=True)
+
+
+    def ModifyValue(self, value, use_change_value=False):
+        """
+        This factored function of common code does the bulk of the work for SetValue 
+        and ChangeValue.
+        """
+##        dbg('MaskedTextCtrl::ModifyValue("%(value)s", use_change_value=%(use_change_value)d)' % locals(), indent=1)
 
         if not self._mask:
-            wx.TextCtrl.SetValue(self, value)    # revert to base control behavior
+            if use_change_value:
+                wx.TextCtrl.ChangeValue(self, value)    # revert to base control behavior
+            else:
+                wx.TextCtrl.SetValue(self, value)    # revert to base control behavior
             return
 
         # empty previous contents, replacing entire value:
@@ -188,9 +227,9 @@ class BaseMaskedTextCtrl( wx.TextCtrl, MaskedEditMixin ):
                 value = value[1:]
 ##            dbg('padded value = "%s"' % value)
 
-        # make SetValue behave the same as if you had typed the value in:
+        # make Set/ChangeValue behave the same as if you had typed the value in:
         try:
-            value = self._Paste(value, raise_on_invalid=True, just_return_value=True)
+            value, replace_to = self._Paste(value, raise_on_invalid=True, just_return_value=True)
             if self._isFloat:
                 self._isNeg = False     # (clear current assumptions)
                 value = self._adjustFloat(value)
@@ -206,19 +245,34 @@ class BaseMaskedTextCtrl( wx.TextCtrl, MaskedEditMixin ):
                 dateparts[0] = self._adjustDate(dateparts[0], fixcentury=True)
                 value = string.join(dateparts, ' ')
 ##                dbg('adjusted value: "%s"' % value)
-                value = self._Paste(value, raise_on_invalid=True, just_return_value=True)
+                value, replace_to = self._Paste(value, raise_on_invalid=True, just_return_value=True)
             else:
 ##                dbg('exception thrown', indent=0)
                 raise
-
-        self._SetValue(value)   # note: to preserve similar capability, .SetValue()
-                                # does not change IsModified()
-####        dbg('queuing insertion after .SetValue', self._masklength)
-        wx.CallAfter(self._SetInsertionPoint, self._masklength)
-        wx.CallAfter(self._SetSelection, self._masklength, self._masklength)
+        if use_change_value:
+            self._ChangeValue(value)
+        else:
+            self._SetValue(value)       # note: to preserve similar capability, .SetValue()
+                                        # does not change IsModified()
+####        dbg('queuing insertion after ._Set/ChangeValue', replace_to)
+        # set selection to last char replaced by paste
+        wx.CallAfter(self._SetInsertionPoint, replace_to)
+        wx.CallAfter(self._SetSelection, replace_to, replace_to)
 ##        dbg(indent=0)
 
 
+    def SetFont(self, *args, **kwargs):
+        """ Set the font, then recalculate control size, if appropriate. """
+        wx.TextCtrl.SetFont(self, *args, **kwargs)
+        if self._autofit:
+##            dbg('calculated size:', self._CalcSize())            
+            self.SetClientSize(self._CalcSize())
+            width = self.GetSize().width
+            height = self.GetBestSize().height
+##            dbg('setting client size to:', (width, height))
+            self.SetInitialSize((width, height))
+
+
     def Clear(self):
         """ Blanks the current control value by replacing it with the default value."""
 ##        dbg("MaskedTextCtrl::Clear - value reset to default value (template)")
@@ -297,10 +351,10 @@ class BaseMaskedTextCtrl( wx.TextCtrl, MaskedEditMixin ):
 
     def IsModified(self):
         """
-        This function overrides the raw wxTextCtrl method, because the
+        This function overrides the raw wx.TextCtrl method, because the
         masked edit mixin uses SetValue to change the value, which doesn't
-        modify the state of this attribute.  So, we keep track on each
-        keystroke to see if the value changes, and if so, it's been
+        modify the state of this attribute.  So, the derived control keeps track
+        on each keystroke to see if the value changes, and if so, it's been
         modified.
         """
         return wx.TextCtrl.IsModified(self) or self.modified
@@ -315,11 +369,48 @@ class BaseMaskedTextCtrl( wx.TextCtrl, MaskedEditMixin ):
 
 class TextCtrl( BaseMaskedTextCtrl, MaskedEditAccessorsMixin ):
     """
-    This extra level of inheritance allows us to add the generic set of
-    masked edit parameters only to this class while allowing other
-    classes to derive from the "base" masked text control, and provide
-    a smaller set of valid accessor functions.
+    The "user-visible" masked text control; it is identical to the
+    BaseMaskedTextCtrl class it's derived from.
+    (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.)
+    See BaseMaskedTextCtrl for available methods.
     """
     pass
 
 
+class PreMaskedTextCtrl( BaseMaskedTextCtrl, MaskedEditAccessorsMixin ):
+    """
+    This class exists to support the use of XRC subclassing.
+    """
+    # This should really be wx.EVT_WINDOW_CREATE but it is not
+    # currently delivered for native controls on all platforms, so
+    # we'll use EVT_SIZE instead.  It should happen shortly after the
+    # control is created as the control is set to its "best" size.
+    _firstEventType = wx.EVT_SIZE
+
+    def __init__(self):
+        pre = wx.PreTextCtrl()
+        self.PostCreate(pre)
+        self.Bind(self._firstEventType, self.OnCreate)
+
+
+    def OnCreate(self, evt):
+        self.Unbind(self._firstEventType)
+        self._PostInit()
+
+__i=0
+## CHANGELOG:
+## ====================
+##  Version 1.3
+##  - Added support for ChangeValue() function, similar to that of the base
+##    control, added in wxPython 2.7.1.1.
+##
+##  Version 1.2
+##  - Converted docstrings to reST format, added doc for ePyDoc.
+##    removed debugging override functions.
+##
+##  Version 1.1
+##  1. Added .SetFont() method that properly resizes control
+##  2. Modified control to support construction via XRC mechanism.