diff --git a/gui/builtinAdditionPanes/droneView.py b/gui/builtinAdditionPanes/droneView.py index 8bcf8428e..b3953c886 100644 --- a/gui/builtinAdditionPanes/droneView.py +++ b/gui/builtinAdditionPanes/droneView.py @@ -76,7 +76,7 @@ class DroneView(Display): self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) self.mainFrame.Bind(ITEM_SELECTED, self.addItem) - self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDoubleClick) + self.Bind(wx.EVT_LEFT_DCLICK, self.onLeftDoubleClick) self.Bind(wx.EVT_LEFT_DOWN, self.click) self.Bind(wx.EVT_KEY_UP, self.kbEvent) self.Bind(wx.EVT_MOTION, self.OnMouseMove) @@ -236,7 +236,7 @@ class DroneView(Display): event.Skip() - def OnLeftDoubleClick(self, event): + def onLeftDoubleClick(self, event): row, _ = self.HitTest(event.Position) if row != -1: col = self.getColumn(event.Position) @@ -246,7 +246,7 @@ class DroneView(Display): drone = self.drones[self.GetItemData(row)] except IndexError: return - if mstate.cmdDown or mstate.altDown: + if mstate.altDown: self.removeDroneStacks([drone]) else: self.removeDrone(drone) diff --git a/gui/builtinAdditionPanes/fighterView.py b/gui/builtinAdditionPanes/fighterView.py index eddba47a0..63313694d 100644 --- a/gui/builtinAdditionPanes/fighterView.py +++ b/gui/builtinAdditionPanes/fighterView.py @@ -20,17 +20,18 @@ # noinspection PyPackageRequirements import wx -import gui.globalEvents as GE -from gui.builtinMarketBrowser.events import ItemSelected, ITEM_SELECTED -import gui.mainFrame import gui.display as d -from gui.builtinViewColumns.state import State +import gui.fitCommands as cmd +import gui.globalEvents as GE +import gui.mainFrame from eos.const import FittingSlot +from gui.builtinMarketBrowser.events import ItemSelected, ITEM_SELECTED +from gui.builtinViewColumns.state import State from gui.contextMenu import ContextMenu +from gui.fitCommands.helpers import getSimilarFighters from gui.utils.staticHelpers import DragDropHelper from service.fit import Fit from service.market import Market -import gui.fitCommands as cmd class FighterViewDrop(wx.DropTarget): @@ -138,7 +139,7 @@ class FighterDisplay(d.Display): self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) self.mainFrame.Bind(ITEM_SELECTED, self.addItem) - self.Bind(wx.EVT_LEFT_DCLICK, self.removeItem) + self.Bind(wx.EVT_LEFT_DCLICK, self.onLeftDoubleClick) self.Bind(wx.EVT_LEFT_DOWN, self.click) self.Bind(wx.EVT_KEY_UP, self.kbEvent) self.Bind(wx.EVT_MOTION, self.OnMouseMove) @@ -188,14 +189,8 @@ class FighterDisplay(d.Display): if keycode == 65 and mstate.cmdDown and not mstate.altDown and not mstate.shiftDown: self.selectAll() if keycode == wx.WXK_DELETE or keycode == wx.WXK_NUMPAD_DELETE: - row = self.GetFirstSelected() - if row != -1: - try: - fighter = self.fighters[self.GetItemData(row)] - except IndexError: - return - self.removeFighter(fighter) - + fighters = self.getSelectedFighters() + self.removeFighters(fighters) event.Skip() def startDrag(self, event): @@ -290,22 +285,29 @@ class FighterDisplay(d.Display): event.Skip() - def removeItem(self, event): + def onLeftDoubleClick(self, event): row, _ = self.HitTest(event.Position) if row != -1: col = self.getColumn(event.Position) if col != self.getColIndex(State): + mstate = wx.GetMouseState() try: fighter = self.fighters[self.GetItemData(row)] except IndexError: return - self.removeFighter(fighter) + if mstate.altDown: + fighters = getSimilarFighters(self.original, fighter) + else: + fighters = [fighter] + self.removeFighters(fighters) - def removeFighter(self, fighter): + def removeFighters(self, fighters): fitID = self.mainFrame.getActiveFit() - if fighter in self.original: - position = self.original.index(fighter) - self.mainFrame.command.Submit(cmd.GuiRemoveLocalFighterCommand(fitID=fitID, position=position)) + positions = [] + for fighter in fighters: + if fighter in self.original: + positions.append(self.original.index(fighter)) + self.mainFrame.command.Submit(cmd.GuiRemoveLocalFightersCommand(fitID=fitID, positions=positions)) def click(self, event): event.Skip() @@ -323,14 +325,29 @@ class FighterDisplay(d.Display): self.mainFrame.command.Submit(cmd.GuiToggleLocalFighterStateCommand(fitID=fitID, position=position)) def spawnMenu(self, event): - sel = self.GetFirstSelected() - if sel != -1: + selection = self.getSelectedFighters() + clickedPos = self.getRowByAbs(event.Position) + mainFighter = None + if clickedPos != -1: try: - fighter = self.fighters[sel] + fighter = self.fighters[clickedPos] except IndexError: - return - sMkt = Market.getInstance() - sourceContext = "fighterItem" - itemContext = sMkt.getCategoryByItem(fighter.item).name - menu = ContextMenu.getMenu(fighter, (fighter,), (sourceContext, itemContext)) + pass + else: + if fighter in self.original: + mainFighter = fighter + sourceContext = "fighterItem" + itemContext = None if mainFighter is None else Market.getInstance().getCategoryByItem(mainFighter.item).name + menu = ContextMenu.getMenu(mainFighter, selection, (sourceContext, itemContext)) + if menu: self.PopupMenu(menu) + + def getSelectedFighters(self): + fighters = [] + for row in self.getSelectedRows(): + try: + fighter = self.fighters[self.GetItemData(row)] + except IndexError: + continue + fighters.append(fighter) + return fighters diff --git a/gui/builtinContextMenus/itemRemove.py b/gui/builtinContextMenus/itemRemove.py index 3023fe7b4..7ee5a66c2 100644 --- a/gui/builtinContextMenus/itemRemove.py +++ b/gui/builtinContextMenus/itemRemove.py @@ -5,7 +5,7 @@ import wx import gui.fitCommands as cmd import gui.mainFrame from gui.contextMenu import ContextMenuCombined -from gui.fitCommands.helpers import getSimilarModPositions +from gui.fitCommands.helpers import getSimilarModPositions, getSimilarFighters from service.fit import Fit from service.settings import ContextMenuSettings @@ -61,10 +61,16 @@ class RemoveItem(ContextMenuCombined): self.mainFrame.command.Submit(cmd.GuiRemoveLocalDronesCommand( fitID=fitID, positions=positions, amount=math.inf)) elif srcContext == "fighterItem": - if mainItem in fit.fighters: - position = fit.fighters.index(mainItem) - self.mainFrame.command.Submit(cmd.GuiRemoveLocalFighterCommand( - fitID=fitID, position=position)) + if wx.GetMouseState().altDown: + fighters = getSimilarFighters(fit.fighters, mainItem) + else: + fighters = selection + positions = [] + for fighter in fighters: + if fighter in fit.fighters: + positions.append(fit.fighters.index(fighter)) + self.mainFrame.command.Submit(cmd.GuiRemoveLocalFightersCommand( + fitID=fitID, positions=positions)) elif srcContext == "implantItem": if mainItem in fit.implants: position = fit.implants.index(mainItem) diff --git a/gui/fitCommands/__init__.py b/gui/fitCommands/__init__.py index 08e118097..fa2c38db5 100644 --- a/gui/fitCommands/__init__.py +++ b/gui/fitCommands/__init__.py @@ -29,7 +29,7 @@ from .gui.localFighter.abilityToggleState import GuiToggleLocalFighterAbilitySta from .gui.localFighter.add import GuiAddLocalFighterCommand from .gui.localFighter.changeAmount import GuiChangeLocalFighterAmountCommand from .gui.localFighter.changeMeta import GuiChangeLocalFighterMetaCommand -from .gui.localFighter.remove import GuiRemoveLocalFighterCommand +from .gui.localFighter.remove import GuiRemoveLocalFightersCommand from .gui.localFighter.toggleState import GuiToggleLocalFighterStateCommand from .gui.localModule.add import GuiAddLocalModuleCommand from .gui.localModule.changeCharges import GuiChangeLocalModuleChargesCommand diff --git a/gui/fitCommands/calc/fighter/localAdd.py b/gui/fitCommands/calc/fighter/localAdd.py index 98940a9dc..6fab4c39b 100644 --- a/gui/fitCommands/calc/fighter/localAdd.py +++ b/gui/fitCommands/calc/fighter/localAdd.py @@ -11,11 +11,12 @@ pyfalog = Logger(__name__) class CalcAddLocalFighterCommand(wx.Command): - def __init__(self, fitID, fighterInfo, position=None): + def __init__(self, fitID, fighterInfo, position=None, commit=True): wx.Command.__init__(self, True, 'Add Fighter') self.fitID = fitID self.fighterInfo = fighterInfo self.position = position + self.commit = commit def Do(self): pyfalog.debug('Doing addition of fighter {} to fit {}'.format(self.fighterInfo, self.fitID)) @@ -43,7 +44,8 @@ class CalcAddLocalFighterCommand(wx.Command): fit.fighters.append(fighter) except HandledListActionError: pyfalog.warning('Failed to append to list') - eos.db.commit() + if self.commit: + eos.db.commit() return False self.position = fit.fighters.index(fighter) else: @@ -51,14 +53,16 @@ class CalcAddLocalFighterCommand(wx.Command): fit.fighters.insert(self.position, fighter) except HandledListActionError: pyfalog.warning('Failed to insert to list') - eos.db.commit() + if self.commit: + eos.db.commit() return False - eos.db.commit() + if self.commit: + eos.db.commit() return True def Undo(self): pyfalog.debug('Undoing addition of fighter {} to fit {}'.format(self.fighterInfo, self.fitID)) from .localRemove import CalcRemoveLocalFighterCommand - cmd = CalcRemoveLocalFighterCommand(fitID=self.fitID, position=self.position) + cmd = CalcRemoveLocalFighterCommand(fitID=self.fitID, position=self.position, commit=self.commit) cmd.Do() return True diff --git a/gui/fitCommands/calc/fighter/localRemove.py b/gui/fitCommands/calc/fighter/localRemove.py index e4baae280..4af640447 100644 --- a/gui/fitCommands/calc/fighter/localRemove.py +++ b/gui/fitCommands/calc/fighter/localRemove.py @@ -11,10 +11,11 @@ pyfalog = Logger(__name__) class CalcRemoveLocalFighterCommand(wx.Command): - def __init__(self, fitID, position): + def __init__(self, fitID, position, commit=True): wx.Command.__init__(self, True, 'Remove Fighter') self.fitID = fitID self.position = position + self.commit = commit self.savedFighterInfo = None def Do(self): @@ -23,11 +24,16 @@ class CalcRemoveLocalFighterCommand(wx.Command): fighter = fit.fighters[self.position] self.savedFighterInfo = FighterInfo.fromFighter(fighter) fit.fighters.remove(fighter) - eos.db.commit() + if self.commit: + eos.db.commit() return True def Undo(self): pyfalog.debug('Undoing removal of fighter at position {} from fit {}'.format(self.position, self.fitID)) from .localAdd import CalcAddLocalFighterCommand - cmd = CalcAddLocalFighterCommand(fitID=self.fitID, fighterInfo=self.savedFighterInfo, position=self.position) + cmd = CalcAddLocalFighterCommand( + fitID=self.fitID, + fighterInfo=self.savedFighterInfo, + position=self.position, + commit=self.commit) return cmd.Do() diff --git a/gui/fitCommands/gui/localDrone/remove.py b/gui/fitCommands/gui/localDrone/remove.py index 24dec98e8..abe97167d 100644 --- a/gui/fitCommands/gui/localDrone/remove.py +++ b/gui/fitCommands/gui/localDrone/remove.py @@ -19,7 +19,7 @@ class GuiRemoveLocalDronesCommand(wx.Command): def Do(self): results = [] - for position in self.positions: + for position in sorted(self.positions, reverse=True): cmd = CalcRemoveLocalDroneCommand( fitID=self.fitID, position=position, diff --git a/gui/fitCommands/gui/localFighter/remove.py b/gui/fitCommands/gui/localFighter/remove.py index ed0c73020..d48c7efa6 100644 --- a/gui/fitCommands/gui/localFighter/remove.py +++ b/gui/fitCommands/gui/localFighter/remove.py @@ -1,5 +1,6 @@ import wx +import eos.db import gui.mainFrame from gui import globalEvents as GE from gui.fitCommands.calc.fighter.localRemove import CalcRemoveLocalFighterCommand @@ -7,23 +8,28 @@ from gui.fitCommands.helpers import InternalCommandHistory from service.fit import Fit -class GuiRemoveLocalFighterCommand(wx.Command): +class GuiRemoveLocalFightersCommand(wx.Command): - def __init__(self, fitID, position): - wx.Command.__init__(self, True, 'Remove Local Fighter') + def __init__(self, fitID, positions): + wx.Command.__init__(self, True, 'Remove Local Fighters') self.internalHistory = InternalCommandHistory() self.fitID = fitID - self.position = position + self.positions = positions def Do(self): - cmd = CalcRemoveLocalFighterCommand(fitID=self.fitID, position=self.position) - success = self.internalHistory.submit(cmd) + results = [] + for position in sorted(self.positions, reverse=True): + cmd = CalcRemoveLocalFighterCommand(fitID=self.fitID, position=position, commit=False) + results.append(self.internalHistory.submit(cmd)) + success = any(results) + eos.db.commit() Fit.getInstance().recalc(self.fitID) wx.PostEvent(gui.mainFrame.MainFrame.getInstance(), GE.FitChanged(fitID=self.fitID)) return success def Undo(self): success = self.internalHistory.undoAll() + eos.db.commit() Fit.getInstance().recalc(self.fitID) wx.PostEvent(gui.mainFrame.MainFrame.getInstance(), GE.FitChanged(fitID=self.fitID)) return success diff --git a/gui/fitCommands/helpers.py b/gui/fitCommands/helpers.py index 3bf3348bc..2410e0c0f 100644 --- a/gui/fitCommands/helpers.py +++ b/gui/fitCommands/helpers.py @@ -377,3 +377,31 @@ def getSimilarModPositions(mods, mainMod): positions.append(position) continue return positions + + +def getSimilarFighters(fighters, mainFighter): + sMkt = Market.getInstance() + mainGroupID = getattr(sMkt.getGroupByItem(mainFighter.item), 'ID', None) + mainAbilityIDs = set(a.effectID for a in mainFighter.abilities) + similarFighters = [] + for fighter in fighters: + # Always include selected fighter itself + if fighter is mainFighter: + similarFighters.append(fighter) + continue + if fighter.itemID is None: + continue + # Fighters which have the same item ID + if fighter.itemID == mainFighter.itemID: + similarFighters.append(fighter) + continue + # And fighters from the same group and with the same abilities too + fighterGroupID = getattr(sMkt.getGroupByItem(fighter.item), 'ID', None) + fighterAbilityIDs = set(a.effectID for a in fighter.abilities) + if ( + fighterGroupID is not None and fighterGroupID == mainGroupID and + len(fighterAbilityIDs) > 0 and fighterAbilityIDs == mainAbilityIDs + ): + similarFighters.append(fighter) + continue + return similarFighters