]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/wx/lib/maskednumctrl.py
Fixed OOR typo
[wxWidgets.git] / wxPython / wx / lib / maskednumctrl.py
index 138a88adbec166a4afae1d2c52a2d03c49b45970..9a3d234793026dbb8dc4ce3021da0656fee3f626 100644 (file)
@@ -4,7 +4,7 @@
 # Created:      09/06/2003
 # Copyright:   (c) 2003 by Will Sadkin
 # RCS-ID:      $Id$
 # Created:      09/06/2003
 # Copyright:   (c) 2003 by Will Sadkin
 # RCS-ID:      $Id$
-# License:     wxWindows license
+# License:     wxWidgets license
 #----------------------------------------------------------------------------
 # NOTE:
 #   This was written to provide a numeric edit control for wxPython that
 #----------------------------------------------------------------------------
 # NOTE:
 #   This was written to provide a numeric edit control for wxPython that
@@ -29,7 +29,7 @@
 #   are exceeded.
 #
 #   MaskedNumCtrl is intended to support fixed-point numeric entry, and
 #   are exceeded.
 #
 #   MaskedNumCtrl is intended to support fixed-point numeric entry, and
-#   is derived from  MaskedTextCtrl.  As such, it supports a limited range
+#   is derived from BaseMaskedTextCtrl.  As such, it supports a limited range
 #   of values to comply with a fixed-width entry mask.
 #----------------------------------------------------------------------------
 # 12/09/2003 - Jeff Grimmett (grimmtooth@softhome.net)
 #   of values to comply with a fixed-width entry mask.
 #----------------------------------------------------------------------------
 # 12/09/2003 - Jeff Grimmett (grimmtooth@softhome.net)
@@ -65,10 +65,10 @@ Here's the API:
     <B>MaskedNumCtrl</B>(
          parent, id = -1,
          <B>value</B> = 0,
     <B>MaskedNumCtrl</B>(
          parent, id = -1,
          <B>value</B> = 0,
-         pos = wxDefaultPosition,
-         size = wxDefaultSize,
+         pos = wx.DefaultPosition,
+         size = wx.DefaultSize,
          style = 0,
          style = 0,
-         validator = wxDefaultValidator,
+         validator = wx.DefaultValidator,
          name = "maskednumber",
          <B>integerWidth</B> = 10,
          <B>fractionWidth</B> = 0,
          name = "maskednumber",
          <B>integerWidth</B> = 10,
          <B>fractionWidth</B> = 0,
@@ -87,6 +87,7 @@ Here's the API:
          <B>emptyBackgroundColour</B> = "White",
          <B>validBackgroundColour</B> = "White",
          <B>invalidBackgroundColour</B> = "Yellow",
          <B>emptyBackgroundColour</B> = "White",
          <B>validBackgroundColour</B> = "White",
          <B>invalidBackgroundColour</B> = "Yellow",
+         <B>autoSize</B> = True         
          )
 </PRE>
 <UL>
          )
 </PRE>
 <UL>
@@ -177,11 +178,20 @@ Here's the API:
     <DT><B>invalidBackgroundColour</B>
     <DD>Color value used for illegal values or values out-of-bounds of the
         control when the bounds are set but the control is not limited.
     <DT><B>invalidBackgroundColour</B>
     <DD>Color value used for illegal values or values out-of-bounds of the
         control when the bounds are set but the control is not limited.
+    <BR>
+    <DT><B>autoSize</B>
+    <DD>Boolean indicating whether or not the control should set its own
+        width based on the integer and fraction widths.  True by default.
+        <B><I>Note:</I></B> Setting this to False will produce seemingly odd
+        behavior unless the control is large enough to hold the maximum
+        specified value given the widths and the sign positions; if not,
+        the control will appear to "jump around" as the contents scroll.
+        (ie. autoSize is highly recommended.)
 </UL>
 <BR>
 <BR>
 <DT><B>EVT_MASKEDNUM(win, id, func)</B>
 </UL>
 <BR>
 <BR>
 <DT><B>EVT_MASKEDNUM(win, id, func)</B>
-<DD>Respond to a wxEVT_COMMAND_MASKED_NUMBER_UPDATED event, generated when
+<DD>Respond to a EVT_COMMAND_MASKED_NUMBER_UPDATED event, generated when
 the value changes. Notice that this event will always be sent when the
 control's contents changes - whether this is due to user input or
 comes from the program itself (for example, if SetValue() is called.)
 the value changes. Notice that this event will always be sent when the
 control's contents changes - whether this is due to user input or
 comes from the program itself (for example, if SetValue() is called.)
@@ -353,6 +363,12 @@ within the control.  (The default is True.)
 the field values on entry.
 <BR>
 <BR>
 the field values on entry.
 <BR>
 <BR>
+<DT><B>SetAutoSize(bool)</B>
+<DD>Resets the autoSize attribute of the control.
+<DT><B>GetAutoSize()</B>
+<DD>Returns the current state of the autoSize attribute for the control.
+<BR>
+<BR>
 </DL>
 </body></html>
 """
 </DL>
 </body></html>
 """
@@ -368,8 +384,7 @@ MAXINT = maxint     # (constants should be in upper case)
 MININT = -maxint-1
 
 from wx.tools.dbg import Logger
 MININT = -maxint-1
 
 from wx.tools.dbg import Logger
-from wx.lib.maskededit import MaskedEditMixin, MaskedTextCtrl, Field
-
+from wx.lib.maskededit import MaskedEditMixin, BaseMaskedTextCtrl, Field
 dbg = Logger()
 dbg(enable=0)
 
 dbg = Logger()
 dbg(enable=0)
 
@@ -394,16 +409,55 @@ class MaskedNumNumberUpdatedEvent(wx.PyCommandEvent):
 
 
 #----------------------------------------------------------------------------
 
 
 #----------------------------------------------------------------------------
+class MaskedNumCtrlAccessorsMixin:
+    # Define wxMaskedNumCtrl's list of attributes having their own
+    # Get/Set functions, ignoring those that make no sense for
+    # an numeric control.
+    exposed_basectrl_params = (
+         'decimalChar',
+         'shiftDecimalChar',
+         'groupChar',
+         'useParensForNegatives',
+         'defaultValue',
+         'description',
+
+         'useFixedWidthFont',
+         'autoSize',
+         '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 MaskedNumCtrl(BaseMaskedTextCtrl, MaskedNumCtrlAccessorsMixin):
 
 
-class MaskedNumCtrl(MaskedTextCtrl):
 
     valid_ctrl_params = {
         'integerWidth': 10,                 # by default allow all 32-bit integers
 
     valid_ctrl_params = {
         'integerWidth': 10,                 # by default allow all 32-bit integers
-        'fractionWidth': 0,                  # by default, use integers
+        'fractionWidth': 0,                 # by default, use integers
         'decimalChar': '.',                 # by default, use '.' for decimal point
         'allowNegative': True,              # by default, allow negative numbers
         'useParensForNegatives': False,     # by default, use '-' to indicate negatives
         'decimalChar': '.',                 # by default, use '.' for decimal point
         'allowNegative': True,              # by default, allow negative numbers
         'useParensForNegatives': False,     # by default, use '-' to indicate negatives
-        'groupDigits': True,             # by default, don't insert grouping
+        'groupDigits': True,                # by default, don't insert grouping
         'groupChar': ',',                   # by default, use ',' for grouping
         'min': None,                        # by default, no bounds set
         'max': None,
         'groupChar': ',',                   # by default, use ',' for grouping
         'min': None,                        # by default, no bounds set
         'max': None,
@@ -415,7 +469,8 @@ class MaskedNumCtrl(MaskedTextCtrl):
         'emptyBackgroundColour': "White",
         'validBackgroundColour': "White",
         'invalidBackgroundColour': "Yellow",
         'emptyBackgroundColour': "White",
         'validBackgroundColour': "White",
         'invalidBackgroundColour': "Yellow",
-        'useFixedWidthFont': True,  # by default, use a fixed-width font
+        'useFixedWidthFont': True,          # by default, use a fixed-width font
+        'autoSize': True,                   # by default, set the width of the control based on the mask        
         }
 
 
         }
 
 
@@ -488,6 +543,12 @@ class MaskedNumCtrl(MaskedTextCtrl):
         del init_args['integerWidth']
         del init_args['fractionWidth']
 
         del init_args['integerWidth']
         del init_args['fractionWidth']
 
+        self._autoSize = init_args['autoSize']
+        if self._autoSize:
+            formatcodes = 'FR<'
+        else:
+            formatcodes = 'R<'
+
 
         mask = intmask+fracmask
 
 
         mask = intmask+fracmask
 
@@ -497,11 +558,11 @@ class MaskedNumCtrl(MaskedTextCtrl):
         self._typedSign = False
 
         # Construct the base control:
         self._typedSign = False
 
         # Construct the base control:
-        MaskedTextCtrl.__init__(
+        BaseMaskedTextCtrl.__init__(
                 self, parent, id, '',
                 pos, size, style, validator, name,
                 mask = mask,
                 self, parent, id, '',
                 pos, size, style, validator, name,
                 mask = mask,
-                formatcodes = 'FR<',
+                formatcodes = formatcodes,
                 fields = fields,
                 validFunc=self.IsInBounds,
                 setupEventHandling = False)
                 fields = fields,
                 validFunc=self.IsInBounds,
                 setupEventHandling = False)
@@ -538,7 +599,8 @@ class MaskedNumCtrl(MaskedTextCtrl):
 
         if( (kwargs.has_key('integerWidth') and kwargs['integerWidth'] != self._integerWidth)
             or (kwargs.has_key('fractionWidth') and kwargs['fractionWidth'] != self._fractionWidth)
 
         if( (kwargs.has_key('integerWidth') and kwargs['integerWidth'] != self._integerWidth)
             or (kwargs.has_key('fractionWidth') and kwargs['fractionWidth'] != self._fractionWidth)
-            or (kwargs.has_key('groupDigits') and kwargs['groupDigits'] != self._groupDigits) ):
+            or (kwargs.has_key('groupDigits') and kwargs['groupDigits'] != self._groupDigits)
+            or (kwargs.has_key('autoSize') and kwargs['autoSize'] != self._autoSize) ):
 
             fields = {}
 
 
             fields = {}
 
@@ -614,7 +676,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
         dbg('kwargs:', kwargs)
 
         # reprocess existing format codes to ensure proper resulting format:
         dbg('kwargs:', kwargs)
 
         # reprocess existing format codes to ensure proper resulting format:
-        formatcodes = self.GetFormatcodes()
+        formatcodes = self.GetCtrlParameter('formatcodes')        
         if kwargs.has_key('allowNegative'):
             if kwargs['allowNegative'] and '-' not in formatcodes:
                 formatcodes += '-'
         if kwargs.has_key('allowNegative'):
             if kwargs['allowNegative'] and '-' not in formatcodes:
                 formatcodes += '-'
@@ -641,6 +703,16 @@ class MaskedNumCtrl(MaskedTextCtrl):
                 formatcodes = formatcodes.replace('S','')
                 maskededit_kwargs['formatcodes'] = formatcodes
 
                 formatcodes = formatcodes.replace('S','')
                 maskededit_kwargs['formatcodes'] = formatcodes
 
+        if kwargs.has_key('autoSize'):
+            self._autoSize = kwargs['autoSize']
+            if kwargs['autoSize'] and 'F' not in formatcodes:
+                formatcodes += 'F'
+                maskededit_kwargs['formatcodes'] = formatcodes
+            elif not kwargs['autoSize'] and 'F' in formatcodes:
+                formatcodes = formatcodes.replace('F', '')
+                maskededit_kwargs['formatcodes'] = formatcodes
+
+
         if 'r' in formatcodes and self._fractionWidth:
             # top-level mask should only be right insert if no fractional
             # part will be shown; ie. if reconfiguring control, remove
         if 'r' in formatcodes and self._fractionWidth:
             # top-level mask should only be right insert if no fractional
             # part will be shown; ie. if reconfiguring control, remove
@@ -648,6 +720,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
             formatcodes = formatcodes.replace('r', '')
             maskededit_kwargs['formatcodes'] = formatcodes
 
             formatcodes = formatcodes.replace('r', '')
             maskededit_kwargs['formatcodes'] = formatcodes
 
+
         if kwargs.has_key('limited'):
             if kwargs['limited'] and not self._limited:
                 maskededit_kwargs['validRequired'] = True
         if kwargs.has_key('limited'):
             if kwargs['limited'] and not self._limited:
                 maskededit_kwargs['validRequired'] = True
@@ -661,6 +734,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
 
         # Record end of integer and place cursor there:
         integerEnd = self._fields[0]._extent[1]
 
         # Record end of integer and place cursor there:
         integerEnd = self._fields[0]._extent[1]
+        self.SetInsertionPoint(0)
         self.SetInsertionPoint(integerEnd)
         self.SetSelection(integerEnd, integerEnd)
 
         self.SetInsertionPoint(integerEnd)
         self.SetSelection(integerEnd, integerEnd)
 
@@ -733,7 +807,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
             dbg('abs(value):', value)
             self._isNeg = False
 
             dbg('abs(value):', value)
             self._isNeg = False
 
-        elif not self._allowNone and MaskedTextCtrl.GetValue(self) == '':
+        elif not self._allowNone and BaseMaskedTextCtrl.GetValue(self) == '':
             if self._min > 0:
                 value = self._min
             else:
             if self._min > 0:
                 value = self._min
             else:
@@ -775,7 +849,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
         else:
             fracstart, fracend = self._fields[1]._extent
             if candidate is None:
         else:
             fracstart, fracend = self._fields[1]._extent
             if candidate is None:
-                value = self._toGUI(MaskedTextCtrl.GetValue(self))
+                value = self._toGUI(BaseMaskedTextCtrl.GetValue(self))
             else:
                 value = self._toGUI(candidate)
             fracstring = value[fracstart:fracend].strip()
             else:
                 value = self._toGUI(candidate)
             fracstring = value[fracstart:fracend].strip()
@@ -824,8 +898,8 @@ class MaskedNumCtrl(MaskedTextCtrl):
 
         if numvalue == "":
             if self._allowNone:
 
         if numvalue == "":
             if self._allowNone:
-                dbg('calling base MaskedTextCtrl._SetValue(self, "%s")' % value)
-                MaskedTextCtrl._SetValue(self, value)
+                dbg('calling base BaseMaskedTextCtrl._SetValue(self, "%s")' % value)
+                BaseMaskedTextCtrl._SetValue(self, value)
                 self.Refresh()
                 return
             elif self._min > 0 and self.IsLimited():
                 self.Refresh()
                 return
             elif self._min > 0 and self.IsLimited():
@@ -925,7 +999,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
             # reasonable instead:
             dbg('setting replacement value:', replacement)
             self._SetValue(self._toGUI(replacement))
             # reasonable instead:
             dbg('setting replacement value:', replacement)
             self._SetValue(self._toGUI(replacement))
-            sel_start = MaskedTextCtrl.GetValue(self).find(str(abs(replacement)))   # find where it put the 1, so we can select it
+            sel_start = BaseMaskedTextCtrl.GetValue(self).find(str(abs(replacement)))   # find where it put the 1, so we can select it            
             sel_to = sel_start + len(str(abs(replacement)))
             dbg('queuing selection of (%d, %d)' %(sel_start, sel_to))
             wx.CallAfter(self.SetInsertionPoint, sel_start)
             sel_to = sel_start + len(str(abs(replacement)))
             dbg('queuing selection of (%d, %d)' %(sel_start, sel_to))
             wx.CallAfter(self.SetInsertionPoint, sel_start)
@@ -951,8 +1025,8 @@ class MaskedNumCtrl(MaskedTextCtrl):
 
 
         sel_start, sel_to = self._GetSelection()     # record current insertion point
 
 
         sel_start, sel_to = self._GetSelection()     # record current insertion point
-        dbg('calling base MaskedTextCtrl._SetValue(self, "%s")' % adjvalue)
-        MaskedTextCtrl._SetValue(self, adjvalue)
+        dbg('calling BaseMaskedTextCtrl._SetValue(self, "%s")' % adjvalue)
+        BaseMaskedTextCtrl._SetValue(self, adjvalue)
         # After all actions so far scheduled, check that resulting cursor
         # position is appropriate, and move if not:
         wx.CallAfter(self._CheckInsertionPoint)
         # After all actions so far scheduled, check that resulting cursor
         # position is appropriate, and move if not:
         wx.CallAfter(self._CheckInsertionPoint)
@@ -985,7 +1059,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
         # delete next digit to appropriate side:
         if self._groupDigits:
             key = event.GetKeyCode()
         # delete next digit to appropriate side:
         if self._groupDigits:
             key = event.GetKeyCode()
-            value = MaskedTextCtrl.GetValue(self)
+            value = BaseMaskedTextCtrl.GetValue(self)
             sel_start, sel_to = self._GetSelection()
 
             if key == wx.WXK_BACK:
             sel_start, sel_to = self._GetSelection()
 
             if key == wx.WXK_BACK:
@@ -1011,7 +1085,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
                     self.SetInsertionPoint(sel_start)
                     self.SetSelection(sel_start, sel_to+1)
 
                     self.SetInsertionPoint(sel_start)
                     self.SetSelection(sel_start, sel_to+1)
 
-        MaskedTextCtrl._OnErase(self, event)
+        BaseMaskedTextCtrl._OnErase(self, event)
         dbg(indent=0)
 
 
         dbg(indent=0)
 
 
@@ -1025,7 +1099,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
         before passing the events on.
         """
         dbg('MaskedNumCtrl::OnTextChange', indent=1)
         before passing the events on.
         """
         dbg('MaskedNumCtrl::OnTextChange', indent=1)
-        if not MaskedTextCtrl._OnTextChange(self, event):
+        if not BaseMaskedTextCtrl._OnTextChange(self, event):
             dbg(indent=0)
             return
 
             dbg(indent=0)
             return
 
@@ -1046,7 +1120,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
 
     def _GetValue(self):
         """
 
     def _GetValue(self):
         """
-        Override of MaskedTextCtrl to allow amixin to get the raw text value of the
+        Override of BaseMaskedTextCtrl to allow mixin to get the raw text value of the
         control with this function.
         """
         return wx.TextCtrl.GetValue(self)
         control with this function.
         """
         return wx.TextCtrl.GetValue(self)
@@ -1056,7 +1130,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
         """
         Returns the current numeric value of the control.
         """
         """
         Returns the current numeric value of the control.
         """
-        return self._fromGUI( MaskedTextCtrl.GetValue(self) )
+        return self._fromGUI( BaseMaskedTextCtrl.GetValue(self) )
 
     def SetValue(self, value):
         """
 
     def SetValue(self, value):
         """
@@ -1067,16 +1141,16 @@ class MaskedNumCtrl(MaskedTextCtrl):
         A ValueError exception will be raised if an invalid value
         is specified.
         """
         A ValueError exception will be raised if an invalid value
         is specified.
         """
-        MaskedTextCtrl.SetValue( self, self._toGUI(value) )
+        BaseMaskedTextCtrl.SetValue( self, self._toGUI(value) )
 
 
     def SetIntegerWidth(self, value):
 
 
     def SetIntegerWidth(self, value):
-        self.SetCtrlParameters(integerWidth=value)
+        self.SetParameters(integerWidth=value)
     def GetIntegerWidth(self):
         return self._integerWidth
 
     def SetFractionWidth(self, value):
     def GetIntegerWidth(self):
         return self._integerWidth
 
     def SetFractionWidth(self, value):
-        self.SetCtrlParameters(fractionWidth=value)
+        self.SetParameters(fractionWidth=value)
     def GetFractionWidth(self):
         return self._fractionWidth
 
     def GetFractionWidth(self):
         return self._fractionWidth
 
@@ -1221,7 +1295,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
             except ValueError, e:
                 dbg('error getting NumValue(self._toGUI(value)):', e, indent=0)
                 return False
             except ValueError, e:
                 dbg('error getting NumValue(self._toGUI(value)):', e, indent=0)
                 return False
-            if value == '':
+            if value.strip() == '':
                 value = None
             elif self._fractionWidth:
                 value = float(value)
                 value = None
             elif self._fractionWidth:
                 value = float(value)
@@ -1294,6 +1368,12 @@ class MaskedNumCtrl(MaskedTextCtrl):
     def GetSelectOnEntry(self):
         return self._selectOnEntry
 
     def GetSelectOnEntry(self):
         return self._selectOnEntry
 
+    def SetAutoSize(self, value):
+        self.SetParameters(autoSize=value)
+    def GetAutoSize(self):
+        return self._autoSize
+
+
     # (Other parameter accessors are inherited from base class)
 
 
     # (Other parameter accessors are inherited from base class)
 
 
@@ -1311,6 +1391,14 @@ class MaskedNumCtrl(MaskedTextCtrl):
         elif type(value) in (types.StringType, types.UnicodeType):
             value = self._GetNumValue(value)
             dbg('cleansed num value: "%s"' % value)
         elif type(value) in (types.StringType, types.UnicodeType):
             value = self._GetNumValue(value)
             dbg('cleansed num value: "%s"' % value)
+            if value == "":
+                if self.IsNoneAllowed():
+                    dbg(indent=0)
+                    return self._template
+                else:
+                    dbg('exception raised:', e, indent=0)
+                    raise ValueError ('wxMaskedNumCtrl requires numeric value, passed %s'% repr(value) )
+            # else...
             try:
                 if self._fractionWidth or value.find('.') != -1:
                     value = float(value)
             try:
                 if self._fractionWidth or value.find('.') != -1:
                     value = float(value)
@@ -1380,7 +1468,7 @@ class MaskedNumCtrl(MaskedTextCtrl):
         # So, to ensure consistency and to prevent spurious ValueErrors,
         # we make the following test, and react accordingly:
         #
         # So, to ensure consistency and to prevent spurious ValueErrors,
         # we make the following test, and react accordingly:
         #
-        if value == '':
+        if value.strip() == '':
             if not self.IsNoneAllowed():
                 dbg('empty value; not allowed,returning 0', indent = 0)
                 if self._fractionWidth:
             if not self.IsNoneAllowed():
                 dbg('empty value; not allowed,returning 0', indent = 0)
                 if self._fractionWidth:
@@ -1514,3 +1602,12 @@ i=0
 ## =============================##
 ##   1. Add support for printf-style format specification.
 ##   2. Add option for repositioning on 'illegal' insertion point.
 ## =============================##
 ##   1. Add support for printf-style format specification.
 ##   2. Add option for repositioning on 'illegal' insertion point.
+##
+## Version 1.1
+##   1. Fixed .SetIntegerWidth() and .SetFractionWidth() functions.
+##   2. Added autoSize parameter, to allow manual sizing of the control.
+##   3. Changed inheritance to use wxBaseMaskedTextCtrl, to remove exposure of
+##      nonsensical parameter methods from the control, so it will work
+##      properly with Boa.
+##   4. Fixed allowNone bug found by user sameerc1@grandecom.net
+