diff --git a/eos/saveddata/ship.py b/eos/saveddata/ship.py index c18856c66..018570d0d 100644 --- a/eos/saveddata/ship.py +++ b/eos/saveddata/ship.py @@ -70,7 +70,7 @@ class Ship(ItemAttrShortcut, HandledItem): """ Checks if provided item is a valid mode. - If ship has modes, and current mode is not valid, return forced mode + If ship has modes, and current item is not valid, return forced mode else if mode is valid, return Mode else if ship does not have modes, return None diff --git a/gui/builtinContextMenus/__init__.py b/gui/builtinContextMenus/__init__.py index ac7c30edd..7ce9ed894 100644 --- a/gui/builtinContextMenus/__init__.py +++ b/gui/builtinContextMenus/__init__.py @@ -14,6 +14,7 @@ __all__ = [ "whProjector", "cargo", "shipJump", + #"changeAffectingSkills", "tacticalMode", "targetResists", "priceClear" diff --git a/gui/builtinContextMenus/ammoPattern.py b/gui/builtinContextMenus/ammoPattern.py index 1a236ddac..d8d789b68 100644 --- a/gui/builtinContextMenus/ammoPattern.py +++ b/gui/builtinContextMenus/ammoPattern.py @@ -8,7 +8,6 @@ class AmmoPattern(ContextMenu): def __init__(self): self.mainFrame = gui.mainFrame.MainFrame.getInstance() - def display(self, srcContext, selection): if srcContext not in ("marketItemGroup", "marketItemMisc") or self.mainFrame.getActiveFit() is None: return False @@ -33,5 +32,4 @@ class AmmoPattern(ContextMenu): def getBitmap(self, context, selection): return None - AmmoPattern.register() diff --git a/gui/builtinContextMenus/changeAffectingSkills.py b/gui/builtinContextMenus/changeAffectingSkills.py index 5748ce78a..e8248a960 100644 --- a/gui/builtinContextMenus/changeAffectingSkills.py +++ b/gui/builtinContextMenus/changeAffectingSkills.py @@ -10,17 +10,17 @@ import gui.globalEvents as GE class ChangeAffectingSkills(ContextMenu): def __init__(self): self.mainFrame = gui.mainFrame.MainFrame.getInstance() - self.sChar = service.Character.getInstance() - - self.sFit = service.Fit.getInstance() - fit = self.sFit.getFit(self.mainFrame.getActiveFit()) - - self.charID = fit.character.ID def display(self, srcContext, selection): if self.mainFrame.getActiveFit() is None or srcContext not in ("fittingModule", "fittingShip"): return False + self.sChar = service.Character.getInstance() + self.sFit = service.Fit.getInstance() + fit = self.sFit.getFit(self.mainFrame.getActiveFit()) + + self.charID = fit.character.ID + if self.sChar.getCharName(self.charID) in ("All 0", "All 5"): return False @@ -52,9 +52,6 @@ class ChangeAffectingSkills(ContextMenu): def getText(self, itmContext, selection): return "Change %s Skills" % itmContext - def activate(self, fullContext, selection, i): - pass - def addSkill(self, rootMenu, skill, i): if i < 0: label = "Not Learned" @@ -63,32 +60,30 @@ class ChangeAffectingSkills(ContextMenu): id = wx.NewId() self.skillIds[id] = (skill, i) - menuItem = wx.MenuItem(rootMenu, id, label, kind=wx.ITEM_CHECK) + menuItem = wx.MenuItem(rootMenu, id, label, kind=wx.ITEM_RADIO) rootMenu.Bind(wx.EVT_MENU, self.handleSkillChange, menuItem) return menuItem - def getSubMenu(self, context, selection, menu, i, pitem): - self.context = context + def getSubMenu(self, context, selection, rootMenu, i, pitem): self.skillIds = {} - - m = wx.Menu() + sub = wx.Menu() for skill in self.skills: - skillItem = wx.MenuItem(m, wx.NewId(), skill.item.name) - sub = wx.Menu() - skillItem.SetSubMenu(sub) + skillItem = wx.MenuItem(sub, wx.NewId(), skill.item.name) + grandSub = wx.Menu() + skillItem.SetSubMenu(grandSub) if skill.learned: bitmap = bitmapLoader.getBitmap("lvl%s" % skill.level, "icons") if bitmap is not None: skillItem.SetBitmap(bitmap) for i in xrange(-1, 6): - levelItem = self.addSkill(menu, skill, i) - sub.AppendItem(levelItem) + levelItem = self.addSkill(rootMenu, skill, i) + grandSub.AppendItem(levelItem) #@ todo: add check to current level. Need to fix #109 first - m.AppendItem(skillItem) + sub.AppendItem(skillItem) - return m + return sub def handleSkillChange(self, event): skill, level = self.skillIds[event.Id] diff --git a/gui/builtinContextMenus/damagePattern.py b/gui/builtinContextMenus/damagePattern.py index e9e554fe7..724e7ac57 100644 --- a/gui/builtinContextMenus/damagePattern.py +++ b/gui/builtinContextMenus/damagePattern.py @@ -15,7 +15,7 @@ class DamagePattern(ContextMenu): self.mainFrame = gui.mainFrame.MainFrame.getInstance() def display(self, srcContext, selection): - return srcContext in ("resistancesViewFull",) and self.mainFrame.getActiveFit() is not None + return srcContext == "resistancesViewFull" and self.mainFrame.getActiveFit() is not None def getText(self, itmContext, selection): sDP = service.DamagePattern.getInstance() @@ -24,12 +24,11 @@ class DamagePattern(ContextMenu): self.fit = sFit.getFit(fitID) self.patterns = sDP.getDamagePatternList() - self.patterns.sort( key=lambda p: (p.name not in ["Uniform", - "Selected Ammo"], p.name) ) + self.patterns.sort(key=lambda p: (p.name not in ["Uniform","Selected Ammo"], p.name)) self.patternIds = {} self.subMenus = OrderedDict() - self.singles = [] + self.singles = [] # iterate and separate damage patterns based on "[Parent] Child" for pattern in self.patterns: @@ -48,6 +47,50 @@ class DamagePattern(ContextMenu): self.m = map(lambda p: p.name, self.singles) + self.subMenus.keys() return self.m + def addPattern(self, rootMenu, pattern): + id = wx.NewId() + name = getattr(pattern, "_name", pattern.name) if pattern is not None else "No Profile" + + self.patternIds[id] = pattern + menuItem = wx.MenuItem(rootMenu, id, name) + rootMenu.Bind(wx.EVT_MENU, self.handlePatternSwitch, menuItem) + + # set pattern attr to menu item + menuItem.pattern = pattern + + # determine active pattern + sFit = service.Fit.getInstance() + fitID = self.mainFrame.getActiveFit() + f = sFit.getFit(fitID) + dp = f.damagePattern + + if dp == pattern: + bitmap = bitmapLoader.getBitmap("state_active_small", "icons") + menuItem.SetBitmap(bitmap) + return menuItem + + def getSubMenu(self, context, selection, rootMenu, i, pitem): + rootMenu.Bind(wx.EVT_MENU, self.handlePatternSwitch) # this bit is required for some reason + + if self.m[i] not in self.subMenus: + # if we're trying to get submenu to something that shouldn't have one, + # redirect event of the item to handlePatternSwitch and put pattern in + # our patternIds mapping, then return None for no submenu + id = pitem.GetId() + self.patternIds[id] = self.singles[i] + if self.patternIds[id] == self.fit.damagePattern: + bitmap = bitmapLoader.getBitmap("state_active_small", "icons") + pitem.SetBitmap(bitmap) + return None + + sub = wx.Menu() + + # Items that have a parent + for pattern in self.subMenus[self.m[i]]: + sub.AppendItem(self.addPattern(rootMenu, pattern)) + + return sub + def handlePatternSwitch(self, event): pattern = self.patternIds.get(event.Id, False) if pattern is False: @@ -60,50 +103,4 @@ class DamagePattern(ContextMenu): setattr(self.mainFrame,"_activeDmgPattern", pattern) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) - def addPattern(self, menu, pattern): - id = wx.NewId() - name = getattr(pattern, "_name", pattern.name) if pattern is not None else "No Profile" - - self.patternIds[id] = pattern - item = wx.MenuItem(menu, id, name) - menu.Bind(wx.EVT_MENU, self.handlePatternSwitch, item) - - # set pattern attr to menu item - item.pattern = pattern - - # determine active pattern - sFit = service.Fit.getInstance() - fitID = self.mainFrame.getActiveFit() - f = sFit.getFit(fitID) - dp = f.damagePattern - - if dp == pattern: - bitmap = bitmapLoader.getBitmap("state_active_small", "icons") - item.SetBitmap(bitmap) - return item - - def getSubMenu(self, context, selection, menu, i, pitem): - menu.Bind(wx.EVT_MENU, self.handlePatternSwitch) # this bit is required for some reason - - if self.m[i] not in self.subMenus: - # if we're trying to get submenu to something that shouldn't have one, - # redirect event of the item to handlePatternSwitch and put pattern in - # our patternIds mapping, then return None for no submenu - id = pitem.GetId() - self.patternIds[id] = self.singles[i] - menu.Bind(wx.EVT_MENU, self.handlePatternSwitch, pitem) - if self.patternIds[id] == self.fit.damagePattern: - bitmap = bitmapLoader.getBitmap("state_active_small", "icons") - pitem.SetBitmap(bitmap) - return None - - sub = wx.Menu() - sub.Bind(wx.EVT_MENU, self.handlePatternSwitch) - - # Items that have a parent - for pattern in self.subMenus[self.m[i]]: - sub.AppendItem(self.addPattern(sub, pattern)) - - return sub - DamagePattern.register() diff --git a/gui/builtinContextMenus/droneRemoveStack.py b/gui/builtinContextMenus/droneRemoveStack.py index c3063ca52..f5c94853b 100644 --- a/gui/builtinContextMenus/droneRemoveStack.py +++ b/gui/builtinContextMenus/droneRemoveStack.py @@ -15,7 +15,6 @@ class ItemRemove(ContextMenu): return "Remove {0} Stack".format(itmContext) def activate(self, fullContext, selection, i): - srcContext = fullContext[0] sFit = service.Fit.getInstance() fitID = self.mainFrame.getActiveFit() fit = sFit.getFit(fitID) diff --git a/gui/builtinContextMenus/factorReload.py b/gui/builtinContextMenus/factorReload.py index ca499e163..133acad51 100644 --- a/gui/builtinContextMenus/factorReload.py +++ b/gui/builtinContextMenus/factorReload.py @@ -10,7 +10,7 @@ class FactorReload(ContextMenu): self.mainFrame = gui.mainFrame.MainFrame.getInstance() def display(self, srcContext, selection): - return srcContext in ("firepowerViewFull",) and self.mainFrame.getActiveFit() is not None + return srcContext == "firepowerViewFull" and self.mainFrame.getActiveFit() is not None def getText(self, itmContext, selection): return "Factor in Reload Time" diff --git a/gui/builtinContextMenus/itemStats.py b/gui/builtinContextMenus/itemStats.py index df0e7b771..47054edc6 100644 --- a/gui/builtinContextMenus/itemStats.py +++ b/gui/builtinContextMenus/itemStats.py @@ -9,8 +9,13 @@ class ItemStats(ContextMenu): self.mainFrame = gui.mainFrame.MainFrame.getInstance() def display(self, srcContext, selection): - return srcContext in ("marketItemGroup", "marketItemMisc", "fittingModule", "fittingCharge", "fittingShip", "baseShip", "cargoItem", - "droneItem", "implantItem", "boosterItem", "skillItem", "projectedModule", "projectedDrone", "projectedCharge") + return srcContext in ("marketItemGroup", "marketItemMisc", + "fittingModule", "fittingCharge", + "fittingShip", "baseShip", + "cargoItem", "droneItem", + "implantItem", "boosterItem", + "skillItem", "projectedModule", + "projectedDrone", "projectedCharge") def getText(self, itmContext, selection): return "{0} Stats".format(itmContext if itmContext is not None else "Item") @@ -33,7 +38,7 @@ class ItemStats(ContextMenu): if mstate.CmdDown(): reuse = True - if self.mainFrame.GetActiveStatsWindow() == None and reuse: + if self.mainFrame.GetActiveStatsWindow() is None and reuse: ItemStatsDialog(stuff, fullContext) elif reuse: diff --git a/gui/builtinContextMenus/marketJump.py b/gui/builtinContextMenus/marketJump.py index 11b0651cf..4980bf61f 100644 --- a/gui/builtinContextMenus/marketJump.py +++ b/gui/builtinContextMenus/marketJump.py @@ -8,19 +8,24 @@ class MarketJump(ContextMenu): self.mainFrame = gui.mainFrame.MainFrame.getInstance() def display(self, srcContext, selection): - validContexts = ("marketItemMisc", "fittingModule", "fittingCharge", "droneItem", "implantItem", - "boosterItem", "projectedModule", "projectedDrone", "projectedCharge", "cargoItem") - if not srcContext in validContexts: + validContexts = ("marketItemMisc", "fittingModule", + "fittingCharge", "droneItem", + "implantItem", "boosterItem", + "projectedModule", "projectedDrone", + "projectedCharge", "cargoItem") + + if not srcContext in validContexts or selection is None or len(selection) < 1: return False + sMkt = service.Market.getInstance() - if selection is None or len(selection) < 1: - return False item = getattr(selection[0], "item", selection[0]) mktGrp = sMkt.getMarketGroupByItem(item) + # 1663 is Special Edition Festival Assets, we don't have root group for it if mktGrp is None or mktGrp.ID == 1663: return False - doit = not selection[0].isEmpty if srcContext == "fittingModule" else True + + doit = not selection[0].isEmpty if srcContext == "fittingModule" else True return doit def getText(self, itmContext, selection): @@ -28,7 +33,9 @@ class MarketJump(ContextMenu): def activate(self, fullContext, selection, i): srcContext = fullContext[0] - if srcContext in ("fittingModule", "droneItem", "implantItem", "boosterItem", "projectedModule", "projectedDrone", "cargoItem"): + if srcContext in ("fittingModule", "droneItem", "implantItem", + "boosterItem", "projectedModule", "projectedDrone", + "cargoItem"): item = selection[0].item elif srcContext in ("fittingCharge", "projectedCharge"): item = selection[0].charge diff --git a/gui/builtinContextMenus/moduleAmmoPicker.py b/gui/builtinContextMenus/moduleAmmoPicker.py index 55b03cf8b..ddb3dff44 100644 --- a/gui/builtinContextMenus/moduleAmmoPicker.py +++ b/gui/builtinContextMenus/moduleAmmoPicker.py @@ -8,6 +8,9 @@ from eos.types import Hardpoint import gui.globalEvents as GE class ModuleAmmoPicker(ContextMenu): + DAMAGE_TYPES = ("em", "explosive", "kinetic", "thermal") + MISSILE_ORDER = ("em", "thermal", "kinetic", "explosive", "mixed") + def __init__(self): self.mainFrame = gui.mainFrame.MainFrame.getInstance() @@ -19,7 +22,9 @@ class ModuleAmmoPicker(ContextMenu): validCharges = None checkedTypes = set() + for mod in modules: + # loop through modules and gather list of valid charges if mod.item.ID in checkedTypes: continue checkedTypes.add(mod.item.ID) @@ -41,10 +46,6 @@ class ModuleAmmoPicker(ContextMenu): def getText(self, itmContext, selection): return "Charge" - def activate(self, fullContext, selection, i): - pass - - DAMAGE_TYPES = ("em", "explosive", "kinetic", "thermal") def turretSorter(self, charge): damage = 0 range = (self.module.getModifiedItemAttr("maxRange") or 0) * (charge.getAttribute("weaponRangeMultiplier") or 1) @@ -57,15 +58,14 @@ class ModuleAmmoPicker(ContextMenu): # Take optimal and half falloff as range factor rangeFactor = range + falloff / 2 - return (- rangeFactor, charge.name.rsplit()[-2:], damage, charge.name) + return - rangeFactor, charge.name.rsplit()[-2:], damage, charge.name - MISSILE_ORDER = ("em", "thermal", "kinetic", "explosive", "mixed") def missileSorter(self, charge): # Get charge damage type and total damage chargeDamageType, totalDamage = self.damageInfo(charge) # Find its position in sort list position = self.MISSILE_ORDER.index(chargeDamageType) - return (position, totalDamage, charge.name) + return position, totalDamage, charge.name def damageInfo(self, charge): # Set up data storage for missile damage stuff @@ -90,7 +90,6 @@ class ModuleAmmoPicker(ContextMenu): return chargeDamageType, totalDamage - def numericConverter(self, string): return int(string) if string.isdigit() else string @@ -98,11 +97,12 @@ class ModuleAmmoPicker(ContextMenu): parts = charge.name.split(" ") return map(self.numericConverter, parts) - def addCharge(self, menu, charge): + def addCharge(self, rootMenu, charge): id = wx.NewId() name = charge.name if charge is not None else "Empty" self.chargeIds[id] = charge - item = wx.MenuItem(menu, id, name) + item = wx.MenuItem(rootMenu, id, name) + rootMenu.Bind(wx.EVT_MENU, self.handleAmmoSwitch, item) item.charge = charge if charge is not None and charge.icon is not None: bitmap = bitmapLoader.getBitmap(charge.icon.iconFile, "pack") @@ -116,11 +116,8 @@ class ModuleAmmoPicker(ContextMenu): m.Append(id, u'─ %s ─' % text) m.Enable(id, False) - def getSubMenu(self, context, selection, menu, i, pitem): - self.context = context - menu.Bind(wx.EVT_MENU, self.handleAmmoSwitch) + def getSubMenu(self, context, selection, rootMenu, i, pitem): m = wx.Menu() - m.Bind(wx.EVT_MENU, self.handleAmmoSwitch) self.chargeIds = {} hardpoint = self.module.hardpoint moduleName = self.module.item.name @@ -150,7 +147,7 @@ class ModuleAmmoPicker(ContextMenu): base = charge nameBase = currBase range = currRange - item = self.addCharge(m, charge) + item = self.addCharge(rootMenu, charge) items.append(item) else: if sub is None: @@ -158,9 +155,9 @@ class ModuleAmmoPicker(ContextMenu): sub.Bind(wx.EVT_MENU, self.handleAmmoSwitch) self.addSeperator(sub, "Less Damage") item.SetSubMenu(sub) - sub.AppendItem(self.addCharge(sub, base)) + sub.AppendItem(self.addCharge(rootMenu, base)) - sub.AppendItem(self.addCharge(sub, charge)) + sub.AppendItem(self.addCharge(rootMenu, charge)) if sub is not None: self.addSeperator(sub, "More Damage") @@ -194,20 +191,20 @@ class ModuleAmmoPicker(ContextMenu): m.AppendItem(item) if charge.name not in ("Light Defender Missile I", "Heavy Defender Missile I"): - sub.AppendItem(self.addCharge(sub, charge)) + sub.AppendItem(self.addCharge(rootMenu, charge)) else: defender = charge if defender is not None: - m.AppendItem(self.addCharge(sub, defender)) + m.AppendItem(self.addCharge(rootMenu, defender)) if sub is not None: self.addSeperator(sub, "More Damage") else: self.charges.sort(key=self.nameSorter) for charge in self.charges: - m.AppendItem(self.addCharge(m, charge)) + m.AppendItem(self.addCharge(rootMenu, charge)) - m.AppendItem(self.addCharge(m, None)) + m.AppendItem(self.addCharge(rootMenu, None)) return m def handleAmmoSwitch(self, event): diff --git a/gui/builtinContextMenus/moduleGlobalAmmoPicker.py b/gui/builtinContextMenus/moduleGlobalAmmoPicker.py index 61893819c..ad520e8ff 100644 --- a/gui/builtinContextMenus/moduleGlobalAmmoPicker.py +++ b/gui/builtinContextMenus/moduleGlobalAmmoPicker.py @@ -33,7 +33,7 @@ class ModuleGlobalAmmoPicker(ModuleAmmoPicker): selectedModule = self.modules[0] allModules = [] for mod in fit.modules: - if mod.itemID == None: + if mod.itemID is None: continue if mod.itemID == selectedModule.itemID: allModules.append(mod) diff --git a/gui/builtinContextMenus/openFit.py b/gui/builtinContextMenus/openFit.py index 384a7f5f1..eaf38832e 100644 --- a/gui/builtinContextMenus/openFit.py +++ b/gui/builtinContextMenus/openFit.py @@ -8,7 +8,7 @@ class OpenFit(ContextMenu): self.mainFrame = gui.mainFrame.MainFrame.getInstance() def display(self, srcContext, selection): - return "projectedFit" in srcContext + return srcContext == "projectedFit" def getText(self, itmContext, selection): return "Open Fit in New Tab" diff --git a/gui/builtinContextMenus/priceClear.py b/gui/builtinContextMenus/priceClear.py index 1b0cd0dc4..da33bfc21 100644 --- a/gui/builtinContextMenus/priceClear.py +++ b/gui/builtinContextMenus/priceClear.py @@ -9,7 +9,7 @@ class PriceClear(ContextMenu): self.mainFrame = gui.mainFrame.MainFrame.getInstance() def display(self, srcContext, selection): - return "priceViewFull" in srcContext + return srcContext == "priceViewFull" def getText(self, itmContext, selection): return "Reset Price Cache" diff --git a/gui/builtinContextMenus/shipJump.py b/gui/builtinContextMenus/shipJump.py index 7d8fc0fbc..d7ea3b343 100644 --- a/gui/builtinContextMenus/shipJump.py +++ b/gui/builtinContextMenus/shipJump.py @@ -9,10 +9,7 @@ class ShipJump(ContextMenu): self.mainFrame = gui.mainFrame.MainFrame.getInstance() def display(self, srcContext, selection): - validContexts = ("fittingShip") - if not srcContext in validContexts: - return False - return True + return srcContext == "fittingShip" def getText(self, itmContext, selection): return "Open in Ship Browser" diff --git a/gui/builtinContextMenus/tacticalMode.py b/gui/builtinContextMenus/tacticalMode.py index 12d149aa2..393379dcf 100644 --- a/gui/builtinContextMenus/tacticalMode.py +++ b/gui/builtinContextMenus/tacticalMode.py @@ -12,36 +12,36 @@ class TacticalMode(ContextMenu): sFit = service.Fit.getInstance() fitID = self.mainFrame.getActiveFit() self.ship = sFit.getFit(fitID).ship - self.modes = self.ship.getValidModes() + self.modeItems = self.ship.getModeItems() - if not srcContext in ("fittingShip") or self.modes is None: - return False - - return True + return srcContext == "fittingShip" and self.modeItems is not None def getText(self, itmContext, selection): - return "Modes" + return "Tactical Modes" - def handleModeChange(self, event): - mode = self.modeIds[event.Id] - print mode - # @todo fit service change mode - - def addMode(self, menu, mode): - label = mode.item.name.rsplit()[-2] + def addMode(self, rootMenu, item): + label = item.name.rsplit()[-2] id = wx.NewId() - self.modeIds[id] = mode - menuItem = wx.MenuItem(menu, id, label, kind=wx.ITEM_CHECK) - menu.Bind(wx.EVT_MENU, self.handleModeChange, menuItem) + self.itemIds[id] = item + menuItem = wx.MenuItem(rootMenu, id, label, kind=wx.ITEM_RADIO) + rootMenu.Bind(wx.EVT_MENU, self.handleMode, menuItem) return menuItem - def getSubMenu(self, context, selection, menu, i, pitem): - sub = wx.Menu() - self.modeIds = {} - # Items that have a parent - for mode in self.modes: - sub.AppendItem(self.addMode(sub, mode)) + def getSubMenu(self, context, selection, rootMenu, i, pitem): + self.context = context + self.itemIds = {} - return sub + m = wx.Menu() + + for item in self.modeItems: + menuItem = self.addMode(rootMenu, item) + m.AppendItem(menuItem) + + return m + + def handleMode(self, event): + item = self.itemIds[event.Id] + print item + # @todo fit service change mode TacticalMode.register() diff --git a/gui/builtinContextMenus/targetResists.py b/gui/builtinContextMenus/targetResists.py index fa02a3ad1..6f725fe4a 100644 --- a/gui/builtinContextMenus/targetResists.py +++ b/gui/builtinContextMenus/targetResists.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from gui.contextMenu import ContextMenu import gui.mainFrame import service @@ -17,21 +15,18 @@ class TargetResists(ContextMenu): self.mainFrame = gui.mainFrame.MainFrame.getInstance() def display(self, srcContext, selection): - if self.mainFrame.getActiveFit() is None or srcContext not in ("firepowerViewFull",): + if self.mainFrame.getActiveFit() is None or srcContext != "firepowerViewFull": return False sTR = service.TargetResists.getInstance() self.patterns = sTR.getTargetResistsList() - self.patterns.sort( key=lambda p: (p.name in ["None"], p.name) ) + self.patterns.sort(key=lambda p: (p.name in ["None"], p.name)) return len(self.patterns) > 0 def getText(self, itmContext, selection): return "Target Resists" - def activate(self, fullContext, selection, i): - pass - def handleResistSwitch(self, event): pattern = self.patternIds.get(event.Id, False) if pattern is False: @@ -43,12 +38,14 @@ class TargetResists(ContextMenu): sFit.setTargetResists(fitID, pattern) wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) - def addPattern(self, menu, pattern, currBase = None): + def addPattern(self, rootMenu, pattern): id = wx.NewId() name = getattr(pattern, "_name", pattern.name) if pattern is not None else "No Profile" self.patternIds[id] = pattern - item = wx.MenuItem(menu, id, name) + item = wx.MenuItem(rootMenu, id, name) + rootMenu.Bind(wx.EVT_MENU, self.handleResistSwitch, item) + # set pattern attr to menu item item.pattern = pattern @@ -63,21 +60,12 @@ class TargetResists(ContextMenu): item.SetBitmap(bitmap) return item - def addSeperator(self, m, text): - id = wx.NewId() - m.Append(id, u'─ %s ─' % text) - m.Enable(id, False) - - def getSubMenu(self, context, selection, menu, i, pitem): - self.context = context - menu.Bind(wx.EVT_MENU, self.handleResistSwitch) - m = wx.Menu() - m.Bind(wx.EVT_MENU, self.handleResistSwitch) + def getSubMenu(self, context, selection, rootMenu, i, pitem): self.patternIds = {} - self.subMenus = OrderedDict() self.singles = [] + sub = wx.Menu() for pattern in self.patterns: start, end = pattern.name.find('['), pattern.name.find(']') if start is not -1 and end is not -1: @@ -90,30 +78,30 @@ class TargetResists(ContextMenu): else: self.singles.append(pattern) - m.AppendItem(self.addPattern(m, None)) # Add reset - m.AppendSeparator() + sub.AppendItem(self.addPattern(rootMenu, None)) # Add reset + sub.AppendSeparator() # Single items, no parent for pattern in self.singles: - m.AppendItem(self.addPattern(m, pattern)) + sub.AppendItem(self.addPattern(rootMenu, pattern)) # Items that have a parent for menuName, patterns in self.subMenus.items(): # Create parent item for root menu that is simply name of parent - item = wx.MenuItem(menu, wx.NewId(), menuName) + item = wx.MenuItem(rootMenu, wx.NewId(), menuName) # Create menu for child items - sub = wx.Menu() - sub.Bind(wx.EVT_MENU, self.handleResistSwitch) + grandSub = wx.Menu() + #sub.Bind(wx.EVT_MENU, self.handleResistSwitch) # Apply child menu to parent item - item.SetSubMenu(sub) + item.SetSubMenu(grandSub) # Append child items to child menu for pattern in patterns: - sub.AppendItem(self.addPattern(sub, pattern)) - m.AppendItem(item) #finally, append parent item to root menu + grandSub.AppendItem(self.addPattern(rootMenu, pattern)) + sub.AppendItem(item) #finally, append parent item to root menu - return m + return sub TargetResists.register() diff --git a/gui/builtinContextMenus/whProjector.py b/gui/builtinContextMenus/whProjector.py index fb32f34a8..5b4c10e38 100644 --- a/gui/builtinContextMenus/whProjector.py +++ b/gui/builtinContextMenus/whProjector.py @@ -14,29 +14,27 @@ class WhProjector(ContextMenu): def getText(self, itmContext, selection): return "Add System Effects" - def activate(self, fullContext, selection, i): - pass - - def getSubMenu(self, context, selection, menu, i, pitem): - self.idmap = {} - menu.Bind(wx.EVT_MENU, self.handleSelection) - m = wx.Menu() + def getSubMenu(self, context, selection, rootMenu, i, pitem): sMkt = service.Market.getInstance() effdata = sMkt.getSystemWideEffects() + + self.idmap = {} + sub = wx.Menu() + for swType in sorted(effdata): - item = wx.MenuItem(m, wx.ID_ANY, swType) - sub = wx.Menu() - sub.Bind(wx.EVT_MENU, self.handleSelection) - item.SetSubMenu(sub) - m.AppendItem(item) + subItem = wx.MenuItem(sub, wx.ID_ANY, swType) + grandSub = wx.Menu() + subItem.SetSubMenu(grandSub) + sub.AppendItem(subItem) + for swData in sorted(effdata[swType], key=lambda tpl: tpl[2]): wxid = wx.NewId() swObj, swName, swClass = swData self.idmap[wxid] = (swObj, swName) - subitem = wx.MenuItem(sub, wxid, swClass) - sub.AppendItem(subitem) - return m - + grandSubItem = wx.MenuItem(grandSub, wxid, swClass) + rootMenu.Bind(wx.EVT_MENU, self.handleSelection, grandSubItem) + grandSub.AppendItem(grandSubItem) + return sub def handleSelection(self, event): #Skip events ids that aren't mapped diff --git a/gui/contextMenu.py b/gui/contextMenu.py index 9c6213d63..41bbca392 100644 --- a/gui/contextMenu.py +++ b/gui/contextMenu.py @@ -21,29 +21,47 @@ import wx class ContextMenu(object): menus = [] + @classmethod def register(cls): ContextMenu.menus.append(cls) @classmethod def getMenu(cls, selection, *fullContexts): - menu = wx.Menu() - menu.info = {} - menu.selection = selection + """ + getMenu returns a menu that is used with wx.PopupMenu. + + selection: provides a list of what was selected. If only 1 item was + selected, it's is a 1-item list or tuple. Can also be None for + contexts without selection, such as statsPane or projected view + fullContexts: a number of tuples of the following tuple: + srcContext - context were menu was spawned, eg: projectedFit, + cargoItem, etc + itemContext - usually the name of the item's category + + eg: + (('fittingModule', 'Module'), ('fittingShip', 'Ship')) + (('marketItemGroup', 'Implant'),) + (('fittingShip', 'Ship'),) + """ + + rootMenu = wx.Menu() + rootMenu.info = {} + rootMenu.selection = (selection,) if not hasattr(selection, "__iter__") else selection empty = True - menu.Bind(wx.EVT_MENU, cls.handler) for i, fullContext in enumerate(fullContexts): amount = 0 srcContext = fullContext[0] try: - itmContext = fullContext[1] + itemContext = fullContext[1] except IndexError: - itmContext = None + itemContext = None for menuHandler in cls.menus: + # loop through registered menus m = menuHandler() if m.display(srcContext, selection): amount += 1 - texts = m.getText(itmContext, selection) + texts = m.getText(itemContext, selection) if isinstance(texts, basestring): texts = (texts,) @@ -51,54 +69,72 @@ class ContextMenu(object): multiple = not isinstance(bitmap, wx.Bitmap) for it, text in enumerate(texts): id = wx.NewId() - item = wx.MenuItem(menu, id, text) - menu.info[id] = (m, fullContext, it) + rootItem = wx.MenuItem(rootMenu, id, text) + rootMenu.info[id] = (m, fullContext, it) - sub = m.getSubMenu(srcContext, selection, menu, it, item) - if sub is not None: - item.SetSubMenu(sub) + sub = m.getSubMenu(srcContext, selection, rootMenu, it, rootItem) + if sub is None: + # if there is no sub menu, bind the handler to the rootItem + rootMenu.Bind(wx.EVT_MENU, cls.handler, rootItem) + else: + # If there is a submenu, it is expected that the sub + # logic take care of it's own binding. No binding is + # done here + # + # It is important to remember that when binding sub + # menu items, bind them to the rootMenu for proper + # event handling, eg: + # rootMenu.Bind(wx.EVE_MENU, self.handle, menuItem) + rootItem.SetSubMenu(sub) if bitmap is not None: if multiple: bp = bitmap[it] if bp: - item.SetBitmap(bp) + rootItem.SetBitmap(bp) else: - item.SetBitmap(bitmap) + rootItem.SetBitmap(bitmap) - menu.AppendItem(item) + rootMenu.AppendItem(rootItem) empty = False if amount > 0 and i != len(fullContexts) - 1: - menu.AppendSeparator() + rootMenu.AppendSeparator() - return menu if empty is False else None + return rootMenu if empty is False else None @classmethod def handler(cls, event): menu = event.EventObject stuff = menu.info.get(event.Id) if stuff is not None: - m, context, i = stuff + menuHandler, context, i = stuff selection = menu.selection if not hasattr(selection, "__iter__"): selection = (selection,) - m.activate(context, selection, i) + menuHandler.activate(context, selection, i) else: event.Skip() def display(self, context, selection): raise NotImplementedError() - def activate(self, context, selection, i): + def activate(self, fullContext, selection, i): return None - def getSubMenu(self, context, selection, menu, i, pitem): + def getSubMenu(self, context, selection, rootMenu, i, pitem): return None def getText(self, context, selection): + """ + getText should be implemented in child classes, and should return either + a string that will make up a menu item label or a list of strings which + will make numerous menu items. + + These menu items will be added to the root menu + """ raise NotImplementedError() def getBitmap(self, context, selection):