diff --git a/gui/builtinContextMenus/__init__.py b/gui/builtinContextMenus/__init__.py index fd343cc51b..787ff25dde 100644 --- a/gui/builtinContextMenus/__init__.py +++ b/gui/builtinContextMenus/__init__.py @@ -20,6 +20,7 @@ from gui.builtinContextMenus import itemStats from gui.builtinContextMenus import itemMarketJump from gui.builtinContextMenus import fitSystemSecurity # Not really an item info but want to keep it here +from gui.builtinContextMenus import fitPilotSecurity # Not really an item info but want to keep it here from gui.builtinContextMenus import shipJump # Generic item manipulations from gui.builtinContextMenus import itemRemove diff --git a/gui/builtinContextMenus/fitPilotSecurity.py b/gui/builtinContextMenus/fitPilotSecurity.py new file mode 100644 index 0000000000..87b5d310d0 --- /dev/null +++ b/gui/builtinContextMenus/fitPilotSecurity.py @@ -0,0 +1,157 @@ +import re + +import wx + +import gui.fitCommands as cmd +import gui.mainFrame +from gui.contextMenu import ContextMenuUnconditional +from service.fit import Fit + +_t = wx.GetTranslation + + +class FitPilotSecurityMenu(ContextMenuUnconditional): + + def __init__(self): + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + + def display(self, callingWindow, srcContext): + if srcContext != "fittingShip": + return False + + fitID = self.mainFrame.getActiveFit() + fit = Fit.getInstance().getFit(fitID) + + if fit.ship.name not in ('Pacifier', 'Enforcer', 'Marshal', 'Sidewinder', 'Cobra', 'Python'): + return + + return True + + def getText(self, callingWindow, itmContext): + return _t("Pilot Security Status") + + def addOption(self, menu, optionLabel, optionValue): + id = ContextMenuUnconditional.nextID() + self.optionIds[id] = optionValue + menuItem = wx.MenuItem(menu, id, optionLabel, kind=wx.ITEM_CHECK) + menu.Bind(wx.EVT_MENU, self.handleMode, menuItem) + return menuItem + + def addOptionCustom(self, menu, optionLabel): + id = ContextMenuUnconditional.nextID() + menuItem = wx.MenuItem(menu, id, optionLabel, kind=wx.ITEM_CHECK) + menu.Bind(wx.EVT_MENU, self.handleModeCustom, menuItem) + return menuItem + + def getSubMenu(self, callingWindow, context, rootMenu, i, pitem): + fitID = self.mainFrame.getActiveFit() + fit = Fit.getInstance().getFit(fitID) + msw = True if "wxMSW" in wx.PlatformInfo else False + self.optionIds = {} + sub = wx.Menu() + presets = (-10, -8, -6, -4, -2, 0, 1, 2, 3, 4, 5) + # Inherit + char_sec_status = round(fit.character.secStatus, 2) + menuItem = self.addOption(rootMenu if msw else sub, _t('Character') + f' ({char_sec_status})', None) + sub.Append(menuItem) + menuItem.Check(fit.pilotSecurity is None) + # Custom + label = _t('Custom') + is_checked = False + if fit.pilotSecurity is not None and fit.pilotSecurity not in presets: + sec_status = round(fit.getPilotSecurity(), 2) + label += f' ({sec_status})' + is_checked = True + menuItem = self.addOptionCustom(rootMenu if msw else sub, label) + sub.Append(menuItem) + menuItem.Check(is_checked) + sub.AppendSeparator() + # Predefined options + for sec_status in presets: + menuItem = self.addOption(rootMenu if msw else sub, str(sec_status), sec_status) + sub.Append(menuItem) + menuItem.Check(fit.pilotSecurity == sec_status) + return sub + + def handleMode(self, event): + optionValue = self.optionIds[event.Id] + self.mainFrame.command.Submit(cmd.GuiChangeFitPilotSecurityCommand( + fitID=self.mainFrame.getActiveFit(), + secStatus=optionValue)) + + def handleModeCustom(self, event): + fitID = self.mainFrame.getActiveFit() + fit = Fit.getInstance().getFit(fitID) + sec_status = fit.getPilotSecurity() + + with SecStatusChanger(self.mainFrame, value=sec_status) as dlg: + if dlg.ShowModal() == wx.ID_OK: + cleanInput = re.sub(r'[^0-9.\-+]', '', dlg.input.GetLineText(0).strip()) + if cleanInput: + try: + cleanInputFloat = float(cleanInput) + except ValueError: + return + else: + return + self.mainFrame.command.Submit(cmd.GuiChangeFitPilotSecurityCommand( + fitID=fitID, secStatus=max(-10.0, min(5.0, cleanInputFloat)))) + + +FitPilotSecurityMenu.register() + + +class SecStatusChanger(wx.Dialog): + + def __init__(self, parent, value): + super().__init__(parent, title=_t('Change Security Status'), style=wx.DEFAULT_DIALOG_STYLE) + self.SetMinSize((346, 156)) + + bSizer1 = wx.BoxSizer(wx.VERTICAL) + + bSizer2 = wx.BoxSizer(wx.VERTICAL) + text = wx.StaticText(self, wx.ID_ANY, _t('Security Status (min -10.0, max 5.0):')) + bSizer2.Add(text, 0) + + bSizer1.Add(bSizer2, 0, wx.ALL, 10) + + self.input = wx.TextCtrl(self, wx.ID_ANY, style=wx.TE_PROCESS_ENTER) + if value is None: + value = '0.0' + else: + if value == int(value): + value = int(value) + value = str(value) + self.input.SetValue(value) + + bSizer1.Add(self.input, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, 15) + + bSizer3 = wx.BoxSizer(wx.VERTICAL) + bSizer3.Add(wx.StaticLine(self, wx.ID_ANY), 0, wx.BOTTOM | wx.EXPAND, 15) + + bSizer3.Add(self.CreateStdDialogButtonSizer(wx.OK | wx.CANCEL), 0, wx.EXPAND) + bSizer1.Add(bSizer3, 0, wx.ALL | wx.EXPAND, 10) + + self.input.Bind(wx.EVT_CHAR, self.onChar) + self.input.Bind(wx.EVT_TEXT_ENTER, self.processEnter) + self.SetSizer(bSizer1) + self.Fit() + self.CenterOnParent() + self.input.SetFocus() + self.input.SelectAll() + + def processEnter(self, evt): + self.EndModal(wx.ID_OK) + + # checks to make sure it's valid number + @staticmethod + def onChar(event): + key = event.GetKeyCode() + + acceptable_characters = '1234567890.-+' + acceptable_keycode = [3, 22, 13, 8, 127] # modifiers like delete, copy, paste + if key in acceptable_keycode or key >= 255 or (key < 255 and chr(key) in acceptable_characters): + event.Skip() + return + else: + return False diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index ab56b1ddcd..78536054a0 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -12,6 +12,7 @@ from .gui.commandFit.add import GuiAddCommandFitsCommand from .gui.commandFit.remove import GuiRemoveCommandFitsCommand from .gui.commandFit.toggleStates import GuiToggleCommandFitStatesCommand +from .gui.fitPilotSecurity import GuiChangeFitPilotSecurityCommand from .gui.fitRename import GuiRenameFitCommand from .gui.fitRestrictionToggle import GuiToggleFittingRestrictionsCommand from .gui.fitSystemSecurity import GuiChangeFitSystemSecurityCommand diff --git a/gui/fitCommands/calc/fitPilotSecurity.py b/gui/fitCommands/calc/fitPilotSecurity.py new file mode 100644 index 0000000000..8f09925085 --- /dev/null +++ b/gui/fitCommands/calc/fitPilotSecurity.py @@ -0,0 +1,32 @@ +import wx +from logbook import Logger + +from service.fit import Fit + + +pyfalog = Logger(__name__) + + +class CalcChangeFitPilotSecurityCommand(wx.Command): + + def __init__(self, fitID, secStatus): + wx.Command.__init__(self, True, 'Change Fit Pilot Security') + self.fitID = fitID + self.secStatus = secStatus + self.savedSecStatus = None + + def Do(self): + pyfalog.debug('Doing changing pilot security status of fit {} to {}'.format(self.fitID, self.secStatus)) + fit = Fit.getInstance().getFit(self.fitID, basic=True) + # Fetching status via getter and then saving 'raw' security status + # is intentional, to restore pre-change state properly + if fit.pilotSecurity == self.secStatus: + return False + self.savedSecStatus = fit.pilotSecurity + fit.pilotSecurity = self.secStatus + return True + + def Undo(self): + pyfalog.debug('Undoing changing pilot security status of fit {} to {}'.format(self.fitID, self.secStatus)) + cmd = CalcChangeFitPilotSecurityCommand(fitID=self.fitID, secStatus=self.savedSecStatus) + return cmd.Do() diff --git a/gui/fitCommands/gui/fitPilotSecurity.py b/gui/fitCommands/gui/fitPilotSecurity.py new file mode 100644 index 0000000000..2f6123c4a2 --- /dev/null +++ b/gui/fitCommands/gui/fitPilotSecurity.py @@ -0,0 +1,36 @@ +import wx +from service.fit import Fit + +import eos.db +import gui.mainFrame +from gui import globalEvents as GE +from gui.fitCommands.helpers import InternalCommandHistory +from gui.fitCommands.calc.fitPilotSecurity import CalcChangeFitPilotSecurityCommand + + +class GuiChangeFitPilotSecurityCommand(wx.Command): + + def __init__(self, fitID, secStatus): + wx.Command.__init__(self, True, 'Change Fit Pilot Security') + self.internalHistory = InternalCommandHistory() + self.fitID = fitID + self.secStatus = secStatus + + def Do(self): + cmd = CalcChangeFitPilotSecurityCommand(fitID=self.fitID, secStatus=self.secStatus) + success = self.internalHistory.submit(cmd) + eos.db.flush() + sFit = Fit.getInstance() + sFit.recalc(self.fitID) + eos.db.commit() + wx.PostEvent(gui.mainFrame.MainFrame.getInstance(), GE.FitChanged(fitIDs=(self.fitID,))) + return success + + def Undo(self): + success = self.internalHistory.undoAll() + eos.db.flush() + sFit = Fit.getInstance() + sFit.recalc(self.fitID) + eos.db.commit() + wx.PostEvent(gui.mainFrame.MainFrame.getInstance(), GE.FitChanged(fitIDs=(self.fitID,))) + return success