# ============================================================================= # Copyright (C) 2010 Diego Duclos # # This file is part of pyfa. # # pyfa is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # pyfa is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with pyfa. If not, see . # ============================================================================= import re from abc import ABCMeta, abstractmethod import wx from eos.utils.float import floatUnerr def valToStr(val): if val is None: return '' val = floatUnerr(val) if int(val) == val: val = int(val) return str(val) def strToFloat(val): try: return float(val) except ValueError: return None class InputValidator(metaclass=ABCMeta): def validate(self, value): return self._validateWithReason(value)[0] def getReason(self, value): return self._validateWithReason(value)[1] @abstractmethod def _validateWithReason(self, value): raise NotImplementedError class FloatBox(wx.TextCtrl): def __init__(self, parent, value, id=wx.ID_ANY, style=0, validator=None, **kwargs): super().__init__(parent=parent, id=id, style=style, **kwargs) self.Bind(wx.EVT_TEXT, self.OnText) self._storedValue = '' self._validator = validator self.ChangeValue(valToStr(value)) def ChangeValue(self, value): self._storedValue = value super().ChangeValue(value) self.updateColor() def ChangeValueFloat(self, value): self.ChangeValue(valToStr(value)) def updateColor(self): if self.isValid(): self.SetForegroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)) else: self.SetForegroundColour(wx.RED) def isValid(self): if self._validator is None: return True return self._validator.validate(self.GetValue()) def getInvalidationReason(self): if self._validator is None: return None return self._validator.getReason(self.GetValue()) def OnText(self, event): currentValue = self.GetValue() if currentValue == self._storedValue: event.Skip() return if currentValue == '' or re.match('^\d*\.?\d*$', currentValue): self._storedValue = currentValue self.updateColor() event.Skip() else: self.ChangeValue(self._storedValue) def GetValueFloat(self): return strToFloat(self.GetValue()) class FloatRangeBox(wx.TextCtrl): def __init__(self, parent, value, id=wx.ID_ANY, style=0, **kwargs): super().__init__(parent=parent, id=id, style=style, **kwargs) self.Bind(wx.EVT_TEXT, self.OnText) self._storedValue = '' value = [v for v in value if v is not None] if not value: self.ChangeValue('') else: self.ChangeValue('{}-{}'.format(valToStr(min(value)), valToStr(max(value)))) def ChangeValue(self, value): self._storedValue = value super().ChangeValue(value) def OnText(self, event): currentValue = self.GetValue() if currentValue == self._storedValue: event.Skip() return if currentValue == '' or re.match('^\d*\.?\d*-?\d*\.?\d*$', currentValue): self._storedValue = currentValue event.Skip() else: self.ChangeValue(self._storedValue) def GetValueRange(self): parts = self.GetValue().split('-') if len(parts) == 1: val = strToFloat(parts[0]) return (val, val) else: return (strToFloat(parts[0]), strToFloat(parts[1]))