class_docstr: **Bases:** QtWidgets.QAbstractSpinBox
  
  Extension of QSpinBox widget for selection of a numerical value.     
  Adds many extra features:
  
    * SI prefix notation (eg, automatically display "300 mV" instead of "0.003 V")
    * Float values with linear and decimal stepping (1-9, 10-90, 100-900, etc.)
    * Option for unbounded values
    * Delayed signals (allows multiple rapid changes with only one change signal)
    * Customizable text formatting
  
  =============================  ==============================================
  **Signals:**
  valueChanged(value)            Same as QSpinBox; emitted every time the value 
                                 has changed.
  sigValueChanged(self)          Emitted when value has changed, but also combines
                                 multiple rapid changes into one signal (eg, 
                                 when rolling the mouse wheel).
  sigValueChanging(self, value)  Emitted immediately for all value changes.
  =============================  ==============================================
class_docstr_tok: ["*","*","Bases",":","*","*","QtWidgets.QAbstractSpinBox","Extension","of","QSpinBox","widget","for","selection","of","a","numerical","value",".","Adds","many","extra","features",":","*","SI","prefix","notation","(","eg",",","automatically","display","``","300","mV","''","instead","of","``","0.003","V","''",")","*","Float","values","with","linear","and","decimal","stepping","(","1-9",",","10-90",",","100-900",",","etc",".",")","*","Option","for","unbounded","values","*","Delayed","signals","(","allows","multiple","rapid","changes","with","only","one","change","signal",")","*","Customizable","text","formatting","=============================","==============================================","*","*","Signals",":","*","*","valueChanged","(","value",")","Same","as","QSpinBox",";","emitted","every","time","the","value","has","changed",".","sigValueChanged","(","self",")","Emitted","when","value","has","changed",",","but","also","combines","multiple","rapid","changes","into","one","signal","(","eg",",","when","rolling","the","mouse","wheel",")",".","sigValueChanging","(","self",",","value",")","Emitted","immediately","for","all","value","changes",".","=============================","=============================================="]
docstr: ============== ========================================================================
  **Arguments:**
  parent         Sets the parent widget for this SpinBox (optional). Default is None.
  value          (float/int) initial value. Default is 0.0.
  ============== ========================================================================
  
  All keyword arguments are passed to :func:`setOpts`.
docstr_tok: ["==============","========================================================================","*","*","Arguments",":","*","*","parent","Sets","the","parent","widget","for","this","SpinBox","(","optional",")",".","Default","is","None",".","value","(","float\/int",")","initial","value",".","Default","is","0.0",".","==============","========================================================================","All","keyword","arguments","are","passed","to",":","func",":","`","setOpts","`","."]
code: def __init__(self, parent=None, value=0.0, **kwargs):
      """
      ============== ========================================================================
      **Arguments:**
      parent         Sets the parent widget for this SpinBox (optional). Default is None.
      value          (float/int) initial value. Default is 0.0.
      ============== ========================================================================
  
      All keyword arguments are passed to :func:`setOpts`.
      """
      QtWidgets.QAbstractSpinBox.__init__(self, parent)
      self.lastValEmitted = None
      self.lastText = ""
      self.textValid = True  ## If false, we draw a red border
      self.setMinimumWidth(0)
      self._lastFontHeight = None
  
      self.setSizePolicy(
          QtWidgets.QSizePolicy.Policy.Expanding,
          QtWidgets.QSizePolicy.Policy.Preferred,
      )
      self.errorBox = ErrorBox(self.lineEdit())
  
      self.opts = {
          "bounds": [None, None],
          "wrapping": False,
          ## normal arithmetic step
          "step": decimal.Decimal(
              "0.01"
          ),  ## if 'dec' is false, the spinBox steps by 'step' every time
          ## if 'dec' is True, the step size is relative to the value
          ## 'step' needs to be an integral divisor of ten, ie 'step'*n=10 for some integer value of n (but only if dec is True)
          "dec": False,  ## if true, does decimal stepping. ie from 1-10 it steps by 'step', from 10 to 100 it steps by 10*'step', etc.
          ## if true, minStep must be set in order to cross zero.
          "int": False,  ## Set True to force value to be integer. If True, 'step' is rounded to the nearest integer or defaults to 1.
          "finite": True,
          "prefix": "",  ## string to be prepended to spin box value
          "suffix": "",
          "siPrefix": False,  ## Set to True to display numbers with SI prefix (ie, 100pA instead of 1e-10A)
          "delay": 0.3,  ## delay sending wheel update signals for 300ms
          "delayUntilEditFinished": True,  ## do not send signals until text editing has finished
          "decimals": 6,
          "format": "{prefix}{prefixGap}{scaledValue:.{decimals}g}{suffixGap}{siPrefix}{suffix}",
          "regex": fn.FLOAT_REGEX,
          "evalFunc": decimal.Decimal,
          "compactHeight": True,  # manually remove extra margin outside of text
      }
      if kwargs.get("int", False):
          self.opts["step"] = 1
  
      self.decOpts = ["step", "minStep"]
  
      self.val = decimal.Decimal(
          str(value)
      )  ## Value is precise decimal. Ordinary math not allowed.
      self.updateText()
      self.skipValidate = False
      self.setCorrectionMode(self.CorrectionMode.CorrectToPreviousValue)
      self.setKeyboardTracking(False)
      self.proxy = SignalProxy(
          self.sigValueChanging,
          delay=self.opts["delay"],
          slot=self.delayedChange,
          threadSafe=False,
      )
      self.setOpts(**kwargs)
      self._updateHeight()
  
      self.editingFinished.connect(self.editingFinishedEvent)
  
imports: import decimal
  import re
  from math import isinf, isnan
  from ..None import functions
  from ..Qt import QtCore, QtGui, QtWidgets
  from ..SignalProxy import SignalProxy
label_desc: Use image node_id 1 to create a new SpinBox object from inherited base classes: QtWidgets with example: obj = SpinBox(parent, value)