import wx from eval import arithmetic_eval from utils import typename class MathEntry(wx.TextCtrl): def __init__(self, *args, value="", **kwargs): if "style" in kwargs: kwargs["style"] |= wx.TE_PROCESS_ENTER else: kwargs["style"] = wx.TE_PROCESS_ENTER self.value_type = type(value) value = str(value) wx.TextCtrl.__init__(self, *args, value=value, **kwargs) self._alarm = False self._last_good_value = self.GetValue() self.Bind(wx.EVT_TEXT_ENTER, self.on_enter) self.Bind(wx.EVT_KEY_UP, self.on_escape) def GetValue(self): val = super().GetValue() if val == "": #TODO? return None if val == "None": #TODO? return None try: val = self.value_type(val) except (ValueError, TypeError) as e: print(e) return val def SetValue(self, val): self.value_type = type(val) val = str(val) super().SetValue(val) def on_enter(self, event): val = super().GetValue() self._unset_alarm() try: val = arithmetic_eval(val) self.value_type = type(val) except SyntaxError as e: en = typename(e) msg = e.args[0] msg = f"{en}: {msg}" self._set_alarm(msg) self.SetInsertionPoint(e.offset) except Exception as e: en = typename(e) msg = f"{en}: {e}" self._set_alarm(msg) self.SetInsertionPointEnd() else: self.SetValue(val) self._last_good_value = val event.Skip() def on_escape(self, event): code = event.GetKeyCode() if code != wx.WXK_ESCAPE: event.Skip() return if self._alarm: self.SetValue(self._last_good_value) self._unset_alarm() def _set_alarm(self, msg): self._alarm = True self.SetToolTip(msg) self.SetForegroundColour(wx.RED) def _unset_alarm(self): self._alarm = False self.SetToolTip(None) self.SetForegroundColour(wx.NullColour) def clear(self): super().SetValue("")