Rework target profile editor input boxes for better editing experience

This commit is contained in:
DarkPhoenix
2019-07-30 17:11:53 +03:00
parent 0320a16ba4
commit 4c1c15e69e
4 changed files with 107 additions and 80 deletions

View File

@@ -27,7 +27,7 @@ from gui.bitmap_loader import BitmapLoader
from gui.contextMenu import ContextMenu
from service.const import GraphCacheCleanupReason
from service.fit import Fit
from .input import ConstantBox, RangeBox
from gui.utils.inputs import FloatBox, FloatRangeBox
from .lists import FitList, TargetList
from .vector import VectorPicker
@@ -213,9 +213,9 @@ class GraphControlPanel(wx.Panel):
handledHandles.add(inputDef.handle)
fieldSizer = wx.BoxSizer(wx.HORIZONTAL)
if mainInput:
fieldTextBox = RangeBox(self, self._storedRanges.get((inputDef.handle, inputDef.unit), inputDef.defaultRange))
fieldTextBox = FloatRangeBox(self, self._storedRanges.get((inputDef.handle, inputDef.unit), inputDef.defaultRange))
else:
fieldTextBox = ConstantBox(self, self._storedConsts.get((inputDef.handle, inputDef.unit), inputDef.defaultValue))
fieldTextBox = FloatBox(self, self._storedConsts.get((inputDef.handle, inputDef.unit), inputDef.defaultValue))
fieldTextBox.Bind(wx.EVT_TEXT, self.OnFieldChanged)
fieldSizer.Add(fieldTextBox, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, 5)
fieldIcon = None

View File

@@ -57,7 +57,7 @@ from gui.marketBrowser import MarketBrowser
from gui.multiSwitch import MultiSwitch
from gui.patternEditor import DmgPatternEditorDlg
from gui.preferenceDialog import PreferenceDialog
from gui.targetProfileEditor import ResistsEditorDlg
from gui.targetProfileEditor import TargetProfileEditorDlg
from gui.setEditor import ImplantSetEditorDlg
from gui.shipBrowser import ShipBrowser
from gui.statsPane import StatsPane
@@ -398,7 +398,7 @@ class MainFrame(wx.Frame):
dlg.Show()
def showTargetProfileEditor(self, event):
ResistsEditorDlg(self)
TargetProfileEditorDlg(self)
def showDamagePatternEditor(self, event):
dlg = DmgPatternEditorDlg(self)

View File

@@ -30,6 +30,7 @@ import gui.globalEvents as GE
from gui.bitmap_loader import BitmapLoader
from gui.builtinViews.entityEditor import EntityEditor, BaseValidator
from gui.utils.clipboard import toClipboard, fromClipboard
from gui.utils.inputs import FloatBox, InputValidator, strToFloat
from service.fit import Fit
from service.targetProfile import TargetProfile
@@ -37,13 +38,26 @@ from service.targetProfile import TargetProfile
pyfalog = Logger(__name__)
class TargetProfileTextValidator(BaseValidator):
class ResistValidator(InputValidator):
def _validateWithReason(self, value):
if not value:
return True, ''
value = strToFloat(value)
if value is None:
return False, 'Incorrect formatting (decimals only)'
if value < 0 or value > 100:
return False, 'Incorrect range (must be 0-100)'
return True, ''
class TargetProfileNameValidator(BaseValidator):
def __init__(self):
BaseValidator.__init__(self)
def Clone(self):
return TargetProfileTextValidator()
return TargetProfileNameValidator()
def Validate(self, win):
entityEditor = win.parent
@@ -68,7 +82,7 @@ class TargetProfileEntityEditor(EntityEditor):
def __init__(self, parent):
EntityEditor.__init__(self, parent, "Target Profile")
self.SetEditorValidator(TargetProfileTextValidator)
self.SetEditorValidator(TargetProfileNameValidator)
def getEntitiesFromContext(self):
sTR = TargetProfile.getInstance()
@@ -94,7 +108,7 @@ class TargetProfileEntityEditor(EntityEditor):
sTR.deletePattern(entity)
class ResistsEditorDlg(wx.Dialog):
class TargetProfileEditorDlg(wx.Dialog):
DAMAGE_TYPES = OrderedDict([
("em", "EM resistance"),
("thermal", "Thermal resistance"),
@@ -146,11 +160,11 @@ class ResistsEditorDlg(wx.Dialog):
bmp.SetToolTip(wx.ToolTip(ttText))
resistEditSizer.Add(bmp, 0, style, border)
# set text edit
setattr(self, "%sEdit" % type_, wx.TextCtrl(self, wx.ID_ANY, "", wx.DefaultPosition, defSize))
editObj = getattr(self, "%sEdit" % type_)
editObj.SetToolTip(wx.ToolTip(ttText))
editObj.Bind(wx.EVT_TEXT, self.ValuesUpdated)
resistEditSizer.Add(editObj, 0, wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_VERTICAL, 5)
setattr(self, "%sEdit" % type_, FloatBox(parent=self, id=wx.ID_ANY, value=None, pos=wx.DefaultPosition, size=defSize, validator=ResistValidator()))
editBox = getattr(self, "%sEdit" % type_)
editBox.SetToolTip(wx.ToolTip(ttText))
self.Bind(event=wx.EVT_TEXT, handler=self.OnFieldChanged, source=editBox)
resistEditSizer.Add(editBox, 0, wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_VERTICAL, 5)
unit = wx.StaticText(self, wx.ID_ANY, "%", wx.DefaultPosition, wx.DefaultSize, 0)
unit.SetToolTip(wx.ToolTip(ttText))
resistEditSizer.Add(unit, 0, wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_VERTICAL, 5)
@@ -171,20 +185,17 @@ class ResistsEditorDlg(wx.Dialog):
bmp.SetToolTip(wx.ToolTip(ttText))
miscAttrSizer.Add(bmp, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT, 5)
# set text edit
setattr(self, "%sEdit" % attr, wx.TextCtrl(self, wx.ID_ANY, "", wx.DefaultPosition, defSize))
editObj = getattr(self, "%sEdit" % attr)
editObj.SetToolTip(wx.ToolTip(ttText))
editObj.Bind(wx.EVT_TEXT, self.ValuesUpdated)
miscAttrSizer.Add(editObj, 0, wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_VERTICAL, 5)
setattr(self, "%sEdit" % attr, FloatBox(parent=self, id=wx.ID_ANY, value=None, pos=wx.DefaultPosition, size=defSize))
editBox = getattr(self, "%sEdit" % attr)
editBox.SetToolTip(wx.ToolTip(ttText))
self.Bind(event=wx.EVT_TEXT, handler=self.OnFieldChanged, source=editBox)
miscAttrSizer.Add(editBox, 0, wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_VERTICAL, 5)
unit = wx.StaticText(self, wx.ID_ANY, unitText, wx.DefaultPosition, wx.DefaultSize, 0)
unit.SetToolTip(wx.ToolTip(ttText))
miscAttrSizer.Add(unit, 0, wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_VERTICAL, 5)
contentSizer.Add(miscAttrSizer, 1, wx.EXPAND | wx.ALL, 5)
# Color we use to reset invalid value color
self.colorReset = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)
self.slfooter = wx.StaticLine(self)
contentSizer.Add(self.slfooter, 0, wx.EXPAND | wx.TOP, 5)
@@ -235,58 +246,47 @@ class ResistsEditorDlg(wx.Dialog):
self.Bind(wx.EVT_CLOSE, self.onClose)
self.Bind(wx.EVT_CHAR_HOOK, self.kbEvent)
self.inputTimer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.OnInputTimer, self.inputTimer)
self.patternChanged()
self.ShowModal()
def ValuesUpdated(self, event=None):
"""
Event that is fired when resists values change. Iterates through all
resist edit fields. If blank, sets it to 0.0. If it is not a proper
decimal value, sets text color to red and refuses to save changes until
issue is resolved
"""
def OnFieldChanged(self, event=None):
if event is not None:
event.Skip()
self.inputTimer.Stop()
self.inputTimer.Start(Fit.getInstance().serviceFittingOptions['marketSearchDelay'], True)
def OnInputTimer(self, event):
event.Skip()
if self.block:
return
editObj = None
try:
p = self.entityEditor.getActiveEntity()
for type_ in self.DAMAGE_TYPES:
editObj = getattr(self, "%sEdit" % type_)
editBox = getattr(self, "%sEdit" % type_)
# Raise exception if value is not valid
if not editBox.isValid():
reason = editBox.getInvalidationReason()
raise ValueError(reason)
if editObj.GetValue() == "":
# if we are blank, overwrite with 0
editObj.ChangeValue("0.0")
editObj.SetInsertionPointEnd()
value = float(editObj.GetValue())
# assertion, because they're easy
assert 0 <= value <= 100
# if everything checks out, set resist attribute
value = editBox.GetValueFloat() or 0
setattr(p, "%sAmount" % type_, value / 100)
editObj.SetForegroundColour(self.colorReset)
for attr in self.ATTRIBUTES:
editObj = getattr(self, "%sEdit" % attr)
editBox = getattr(self, "%sEdit" % attr)
# Raise exception if value is not valid
if not editBox.isValid():
reason = editBox.getInvalidationReason()
raise ValueError(reason)
if editObj.GetValue() == "" and attr != "signatureRadius":
# if we are blank, overwrite with 0 except for signatureRadius
editObj.ChangeValue("0.0")
editObj.SetInsertionPointEnd()
# if everything checks out, set attribute
value = editObj.GetValue()
if value == '':
value = None
else:
value = float(value)
value = editBox.GetValueFloat()
setattr(p, attr, value)
editObj.SetForegroundColour(self.colorReset)
self.stNotice.SetLabel("")
self.totSizer.Layout()
@@ -297,16 +297,8 @@ class ResistsEditorDlg(wx.Dialog):
TargetProfile.getInstance().saveChanges(p)
wx.PostEvent(self.mainFrame, GE.TargetProfileChanged(profileID=p.ID))
except ValueError:
editObj.SetForegroundColour(wx.RED)
msg = "Incorrect Formatting (decimals only)"
pyfalog.warning(msg)
self.stNotice.SetLabel(msg)
except AssertionError:
editObj.SetForegroundColour(wx.RED)
msg = "Incorrect Range (must be 0-100)"
pyfalog.warning(msg)
self.stNotice.SetLabel(msg)
except ValueError as e:
self.stNotice.SetLabel(e.args[0])
finally: # Refresh for color changes to take effect immediately
self.Refresh()
@@ -326,18 +318,18 @@ class ResistsEditorDlg(wx.Dialog):
for field in self.DAMAGE_TYPES:
edit = getattr(self, "%sEdit" % field)
amount = getattr(p, "%sAmount" % field) * 100
edit.ChangeValue(str(amount))
edit.ChangeValueFloat(amount)
for attr in self.ATTRIBUTES:
edit = getattr(self, "%sEdit" % attr)
amount = getattr(p, attr)
if amount == math.inf:
edit.ChangeValue('')
edit.ChangeValueFloat(None)
else:
edit.ChangeValue(str(amount))
edit.ChangeValueFloat(amount)
self.block = False
self.ValuesUpdated()
self.OnFieldChanged()
def __del__(self):
pass

View File

@@ -19,6 +19,7 @@
import re
from abc import ABCMeta, abstractmethod
import wx
@@ -38,18 +39,51 @@ def strToFloat(val):
return None
class ConstantBox(wx.TextCtrl):
class InputValidator(metaclass=ABCMeta):
def __init__(self, parent, initial):
super().__init__(parent, wx.ID_ANY, style=0)
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.ChangeValue(valToStr(initial))
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()
@@ -58,6 +92,7 @@ class ConstantBox(wx.TextCtrl):
return
if currentValue == '' or re.match('^\d*\.?\d*$', currentValue):
self._storedValue = currentValue
self.updateColor()
event.Skip()
else:
self.ChangeValue(self._storedValue)
@@ -66,13 +101,13 @@ class ConstantBox(wx.TextCtrl):
return strToFloat(self.GetValue())
class RangeBox(wx.TextCtrl):
class FloatRangeBox(wx.TextCtrl):
def __init__(self, parent, initRange):
super().__init__(parent, wx.ID_ANY, style=0)
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 = ''
self.ChangeValue('{}-{}'.format(valToStr(min(initRange)), valToStr(max(initRange))))
self.ChangeValue('{}-{}'.format(valToStr(min(value)), valToStr(max(value))))
def ChangeValue(self, value):
self._storedValue = value