diff --git a/eos/effectHandlerHelpers.py b/eos/effectHandlerHelpers.py index 3bf576a4c1..eca4d64379 100644 --- a/eos/effectHandlerHelpers.py +++ b/eos/effectHandlerHelpers.py @@ -159,6 +159,10 @@ def toDummy(self, index): dummy.position = index self[index] = dummy + def toModule(self, index, mod): + mod.position = index + self[index] = mod + def freeSlot(self, slot): for i in range(len(self) -1, -1, -1): mod = self[i] diff --git a/gui/builtinContextMenus/__init__.py b/gui/builtinContextMenus/__init__.py index d1da03023d..785e3eebf9 100644 --- a/gui/builtinContextMenus/__init__.py +++ b/gui/builtinContextMenus/__init__.py @@ -19,4 +19,5 @@ "targetResists", "priceClear", "amount", + "metaSwap", ] diff --git a/gui/builtinContextMenus/metaSwap.py b/gui/builtinContextMenus/metaSwap.py new file mode 100644 index 0000000000..35ae4b36ff --- /dev/null +++ b/gui/builtinContextMenus/metaSwap.py @@ -0,0 +1,97 @@ +# -*- coding: utf-8 -*- +from gui.contextMenu import ContextMenu +from gui.itemStats import ItemStatsDialog +import gui.mainFrame +import service +import wx +import gui.globalEvents as GE + +class MetaSwap(ContextMenu): + def __init__(self): + self.mainFrame = gui.mainFrame.MainFrame.getInstance() + + def display(self, srcContext, selection): + + if self.mainFrame.getActiveFit() is None or srcContext not in ("fittingModule",): + return False + + # Check if list of variations is same for all of selection + # If not - don't show the menu + mkt = service.Market.getInstance() + self.variations = None + for i in selection: + variations = mkt.getVariationsByItems([i.item]) + if self.variations is None: + self.variations = variations + else: + if variations != self.variations: + return False + + self.selection = selection + + return True + + def getText(self, itmContext, selection): + return "Variations" + + def getSubMenu(self, context, selection, rootMenu, i, pitem): + self.moduleLookup = {} + + def get_metalevel(x): + return x.attributes["metaLevel"].value + + def get_metagroup(x): + return x.metaGroup.ID if x.metaGroup is not None else 0 + + m = wx.Menu() + + # If on Windows we need to bind out events into the root menu, on other + # platforms they need to go to our sub menu + if "wxMSW" in wx.PlatformInfo: + bindmenu = rootMenu + else: + bindmenu = m + + # Sort items by metalevel, and group within that metalevel + items = list(self.variations) + items.sort(key=get_metalevel) + items.sort(key=get_metagroup) + + group = None + for item in items: + # Apparently no metaGroup for the Tech I variant: + if item.metaGroup is None: + thisgroup = "Tech I" + else: + thisgroup = item.metaGroup.name + + if thisgroup != group: + group = thisgroup + id = wx.NewId() + m.Append(id, u'─ %s ─' % group) + m.Enable(id, False) + + id = wx.NewId() + mitem = wx.MenuItem(rootMenu, id, item.name) + bindmenu.Bind(wx.EVT_MENU, self.handleModule, mitem) + self.moduleLookup[id] = item + m.AppendItem(mitem) + return m + + def handleModule(self, event): + item = self.moduleLookup.get(event.Id, None) + if item is None: + event.Skip() + return + + sFit = service.Fit.getInstance() + fitID = self.mainFrame.getActiveFit() + fit = sFit.getFit(fitID) + + for mod in self.selection: + pos = fit.modules.index(mod) + sFit.changeModule(fitID, pos, item.ID) + + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + +MetaSwap.register() diff --git a/service/fit.py b/service/fit.py index ee6294cd7e..ce400bdf10 100644 --- a/service/fit.py +++ b/service/fit.py @@ -440,6 +440,38 @@ def removeModule(self, fitID, position): eos.db.commit() return numSlots != len(fit.modules) + def changeModule(self, fitID, position, newItemID): + fit = eos.db.getFit(fitID) + if fit.modules[position].isEmpty: + return None + + # Dummy it out in case the next bit fails + fit.modules.toDummy(position) + + item = eos.db.getItem(newItemID, eager=("attributes", "group.category")) + try: + m = eos.types.Module(item) + except ValueError: + return False + + if m.fits(fit): + m.owner = fit + fit.modules.toModule(position, m) + if m.isValidState(State.ACTIVE): + m.state = State.ACTIVE + + # As some items may affect state-limiting attributes of the ship, calculate new attributes first + self.recalc(fit) + # Then, check states of all modules and change where needed. This will recalc if needed + self.checkStates(fit, m) + + fit.fill() + eos.db.commit() + + return True + else: + return None + def moveCargoToModule(self, fitID, moduleIdx, cargoIdx, copyMod=False): """ Moves cargo to fitting window. Can either do a copy, move, or swap with current module