Merge branch 'master' into wx3

This commit is contained in:
DarkPhoenix
2014-12-12 14:42:25 +03:00
104 changed files with 1847 additions and 1009 deletions

View File

@@ -25,7 +25,7 @@ import time
try:
from collections import OrderedDict
except ImportError:
from gui.utils.compat import OrderedDict
from utils.compat import OrderedDict
cachedBitmapsCount = 0
cachedBitmaps = OrderedDict()

View File

@@ -14,5 +14,8 @@ __all__ = [
"whProjector",
"cargo",
"shipJump",
"targetResists"
#"changeAffectingSkills",
"tacticalMode",
"targetResists",
"priceClear"
]

View File

@@ -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()

View File

@@ -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,31 @@ 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):
msw = True if "wxMSW" in wx.PlatformInfo else False
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 if msw else grandSub, 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]

View File

@@ -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,51 @@ 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):
msw = True if "wxMSW" in wx.PlatformInfo else False
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 if msw else sub, pattern))
return sub
def handlePatternSwitch(self, event):
pattern = self.patternIds.get(event.Id, False)
if pattern is False:
@@ -60,50 +104,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()

View File

@@ -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)

View File

@@ -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"

View File

@@ -9,7 +9,10 @@ class ItemRemove(ContextMenu):
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
def display(self, srcContext, selection):
return srcContext in ("fittingModule", "fittingCharge", "droneItem", "implantItem", "boosterItem", "projectedModule", "projectedCharge",
return srcContext in ("fittingModule", "fittingCharge",
"droneItem", "implantItem",
"boosterItem", "projectedModule",
"projectedCharge", "cargoItem",
"projectedFit", "projectedDrone")
def getText(self, itmContext, selection):
@@ -33,6 +36,8 @@ class ItemRemove(ContextMenu):
sFit.removeImplant(fitID, fit.implants.index(selection[0]))
elif srcContext == "boosterItem":
sFit.removeBooster(fitID, fit.boosters.index(selection[0]))
elif srcContext == "cargoItem":
sFit.removeCargo(fitID, fit.cargo.index(selection[0]))
else:
sFit.removeProjected(fitID, selection[0])

View File

@@ -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:

View File

@@ -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

View File

@@ -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
@@ -103,6 +102,7 @@ class ModuleAmmoPicker(ContextMenu):
name = charge.name if charge is not None else "Empty"
self.chargeIds[id] = charge
item = wx.MenuItem(menu, id, name)
menu.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,9 @@ 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):
msw = True if "wxMSW" in wx.PlatformInfo else False
m = wx.Menu()
m.Bind(wx.EVT_MENU, self.handleAmmoSwitch)
self.chargeIds = {}
hardpoint = self.module.hardpoint
moduleName = self.module.item.name
@@ -150,7 +148,7 @@ class ModuleAmmoPicker(ContextMenu):
base = charge
nameBase = currBase
range = currRange
item = self.addCharge(m, charge)
item = self.addCharge(rootMenu if msw else m, charge)
items.append(item)
else:
if sub is None:
@@ -158,9 +156,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 if msw else sub, base))
sub.AppendItem(self.addCharge(sub, charge))
sub.AppendItem(self.addCharge(rootMenu if msw else sub, charge))
if sub is not None:
self.addSeperator(sub, "More Damage")
@@ -194,20 +192,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 if msw else sub, charge))
else:
defender = charge
if defender is not None:
m.AppendItem(self.addCharge(sub, defender))
m.AppendItem(self.addCharge(rootMenu if msw else m, 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 if msw else m, charge))
m.AppendItem(self.addCharge(m, None))
m.AppendItem(self.addCharge(rootMenu if msw else m, None))
return m
def handleAmmoSwitch(self, event):

View File

@@ -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)

View File

@@ -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"

View File

@@ -0,0 +1,22 @@
from gui.contextMenu import ContextMenu
import gui.mainFrame
import wx
import gui.globalEvents as GE
import service
class PriceClear(ContextMenu):
def __init__(self):
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
def display(self, srcContext, selection):
return srcContext == "priceViewFull"
def getText(self, itmContext, selection):
return "Reset Price Cache"
def activate(self, fullContext, selection, i):
sMkt = service.Market.getInstance()
sMkt.clearPriceCache()
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit()))
PriceClear.register()

View File

@@ -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"

View File

@@ -0,0 +1,60 @@
import wx
from gui.contextMenu import ContextMenu
import gui.mainFrame
import service
import gui.globalEvents as GE
class TacticalMode(ContextMenu):
def __init__(self):
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
def display(self, srcContext, selection):
if self.mainFrame.getActiveFit() is None or srcContext != "fittingShip":
return False
sFit = service.Fit.getInstance()
fitID = self.mainFrame.getActiveFit()
fit = sFit.getFit(fitID)
self.modes = fit.ship.getModes()
self.currMode = fit.mode
return srcContext == "fittingShip" and self.modes is not None
def getText(self, itmContext, selection):
return "Tactical Mode"
def addMode(self, menu, mode):
label = mode.item.name.rsplit()[-2]
id = wx.NewId()
self.modeIds[id] = mode
menuItem = wx.MenuItem(menu, id, label, kind=wx.ITEM_RADIO)
menu.Bind(wx.EVT_MENU, self.handleMode, menuItem)
return menuItem
def getSubMenu(self, context, selection, rootMenu, i, pitem):
msw = True if "wxMSW" in wx.PlatformInfo else False
self.context = context
self.modeIds = {}
sub = wx.Menu()
for mode in self.modes:
menuItem = self.addMode(rootMenu if msw else sub, mode)
sub.AppendItem(menuItem)
menuItem.Check(self.currMode.item == mode.item)
return sub
def handleMode(self, event):
item = self.modeIds[event.Id]
if item is False or item not in self.modes:
event.Skip()
return
sFit = service.Fit.getInstance()
fitID = self.mainFrame.getActiveFit()
sFit.setMode(fitID, self.modeIds[event.Id])
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))
TacticalMode.register()

View File

@@ -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,13 @@ 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):
msw = True if "wxMSW" in wx.PlatformInfo else False
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 +79,30 @@ class TargetResists(ContextMenu):
else:
self.singles.append(pattern)
m.AppendItem(self.addPattern(m, None)) # Add reset
m.AppendSeparator()
sub.AppendItem(self.addPattern(rootMenu if msw else sub, 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 if msw else sub, 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 if msw else grandSub, pattern))
sub.AppendItem(item) #finally, append parent item to root menu
return m
return sub
TargetResists.register()

View File

@@ -14,29 +14,31 @@ 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):
msw = True if "wxMSW" in wx.PlatformInfo else False
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)
if msw:
rootMenu.Bind(wx.EVT_MENU, self.handleSelection, grandSubItem)
else:
grandSub.Bind(wx.EVT_MENU, self.handleSelection, grandSubItem)
grandSub.AppendItem(grandSubItem)
return sub
def handleSelection(self, event):
#Skip events ids that aren't mapped

View File

@@ -30,6 +30,7 @@ class FirepowerViewFull(StatsView):
StatsView.__init__(self)
self.parent = parent
self._cachedValues = []
def getHeaderText(self, fit):
return "Firepower"
@@ -44,7 +45,7 @@ class FirepowerViewFull(StatsView):
self.headerPanel = headerPanel
headerContentSizer = wx.BoxSizer(wx.HORIZONTAL)
hsizer = headerPanel.GetSizer()
hsizer.Add(headerContentSizer,0,0,0)
hsizer.Add(headerContentSizer, 0, 0, 0)
self.stEff = wx.StaticText(headerPanel, wx.ID_ANY, "( Effective )")
headerContentSizer.Add(self.stEff)
headerPanel.GetParent().AddToggleItem(self.stEff)
@@ -54,7 +55,7 @@ class FirepowerViewFull(StatsView):
sizerFirepower = wx.FlexGridSizer(1, 4)
sizerFirepower.AddGrowableCol(1)
contentSizer.Add( sizerFirepower, 0, wx.EXPAND, 0)
contentSizer.Add(sizerFirepower, 0, wx.EXPAND, 0)
counter = 0
@@ -73,10 +74,9 @@ class FirepowerViewFull(StatsView):
box.Add(hbox, 1, wx.ALIGN_CENTER)
lbl = wx.StaticText(parent, wx.ID_ANY, "0.0 DPS")
setattr(self, "label%sDps%s" % (panel.capitalize() ,damageType.capitalize()), lbl)
setattr(self, "label%sDps%s" % (panel.capitalize(), damageType.capitalize()), lbl)
hbox.Add(lbl, 0, wx.ALIGN_CENTER)
# hbox.Add(wx.StaticText(parent, wx.ID_ANY, " DPS"), 0, wx.ALIGN_CENTER)
self._cachedValues.append(0)
counter += 1
targetSizer = sizerFirepower
@@ -143,7 +143,7 @@ class FirepowerViewFull(StatsView):
stats = (("labelFullDpsWeapon", lambda: fit.weaponDPS, 3, 0, 0, "%s DPS",None),
("labelFullDpsDrone", lambda: fit.droneDPS, 3, 0, 0, "%s DPS", None),
("labelFullVolleyTotal", lambda: fit.weaponVolley, 3, 0, 0, "%s", "Volley: %.1f"),
("labelFullVolleyTotal", lambda: fit.totalVolley, 3, 0, 0, "%s", "Volley: %.1f"),
("labelFullDpsTotal", lambda: fit.totalDPS, 3, 0, 0, "%s", None))
# See GH issue #
#if fit is not None and fit.totalYield > 0:

View File

@@ -41,7 +41,7 @@ class PriceViewFull(StatsView):
self._cachedFittings = 0
self._cachedTotal = 0
def OnTimer( self, event):
def OnTimer(self, event):
if self._timerId == event.GetId():
if self._timerRuns >= self._timerRunsBeforeUpdate:
self._timerRuns = 0
@@ -53,11 +53,12 @@ class PriceViewFull(StatsView):
if self._timerIdUpdate == event.GetId():
self._timerUpdate.Stop()
self.labelEMStatus.SetLabel("")
def getHeaderText(self, fit):
return "Price"
def getTextExtentW(self, text):
width, height = self.parent.GetTextExtent( text )
width, height = self.parent.GetTextExtent(text)
return width
def populatePanel(self, contentPanel, headerPanel):
@@ -65,8 +66,15 @@ class PriceViewFull(StatsView):
self.panel = contentPanel
self.headerPanel = headerPanel
headerContentSizer = wx.BoxSizer(wx.HORIZONTAL)
hsizer = headerPanel.GetSizer()
hsizer.Add(headerContentSizer, 0, 0, 0)
self.labelEMStatus = wx.StaticText(headerPanel, wx.ID_ANY, "")
headerContentSizer.Add(self.labelEMStatus)
headerPanel.GetParent().AddToggleItem(self.labelEMStatus)
gridPrice = wx.GridSizer(1, 3)
contentSizer.Add( gridPrice, 0, wx.EXPAND | wx.ALL, 0)
contentSizer.Add(gridPrice, 0, wx.EXPAND | wx.ALL, 0)
for type in ("ship", "fittings", "total"):
image = "%sPrice_big" % type if type != "ship" else "ship_big"
box = wx.BoxSizer(wx.HORIZONTAL)
@@ -86,9 +94,6 @@ class PriceViewFull(StatsView):
setattr(self, "labelPrice%s" % type.capitalize(), lbl)
hbox.Add(lbl, 0, wx.ALIGN_LEFT)
# hbox.Add(wx.StaticText(contentPanel, wx.ID_ANY, " ISK"), 0, wx.ALIGN_LEFT)
self.labelEMStatus = wx.StaticText(contentPanel, wx.ID_ANY, "")
contentSizer.Add(self.labelEMStatus,0)
def refreshPanel(self, fit):
if fit is not None:
self.fit = fit

View File

@@ -26,7 +26,7 @@ import locale
try:
from collections import OrderedDict
except ImportError:
from gui.utils.compat import OrderedDict
from utils.compat import OrderedDict
class TargetingMiscViewFull(StatsView):
name = "targetingmiscViewFull"

View File

@@ -42,7 +42,10 @@ class BaseName(ViewColumn):
return "%s (%s)" % (stuff.name, stuff.ship.item.name)
elif isinstance(stuff, Rack):
if service.Fit.getInstance().serviceFittingOptions["rackLabels"]:
return u'{} Slots ─'.format(Slot.getName(stuff.slot).capitalize())
if stuff.slot == Slot.MODE:
return u'─ Tactical Mode ─'
else:
return u'{} Slots ─'.format(Slot.getName(stuff.slot).capitalize())
else:
return ""
elif isinstance(stuff, Module):

View File

@@ -23,6 +23,7 @@ import service
from gui.utils.numberFormatter import formatAmount
from gui.viewColumn import ViewColumn
from gui import bitmapLoader
from eos.types import Mode
class CapacitorUse(ViewColumn):
name = "Capacitor Usage"
@@ -38,6 +39,9 @@ class CapacitorUse(ViewColumn):
def getText(self, mod):
if isinstance(mod, Mode):
return ""
capUse = mod.capUse
if capUse:
return "%s%s" % ("+" if capUse < 0 else "", (formatAmount(-capUse, 3, 0, 3)))

View File

@@ -23,6 +23,7 @@ from gui import bitmapLoader
import service
from gui.utils.numberFormatter import formatAmount
import wx
from eos.types import Mode
class MaxRange(ViewColumn):
name = "Max Range"
@@ -51,6 +52,9 @@ class MaxRange(ViewColumn):
self.mask |= wx.LIST_MASK_TEXT
def getText(self, stuff):
if isinstance(stuff, Mode):
return ""
maxRange = stuff.maxRange if hasattr(stuff, "maxRange") else stuff.getModifiedItemAttr("maxRange")
falloff = stuff.falloff
if falloff:

View File

@@ -19,7 +19,6 @@
import gui.mainFrame
from gui import builtinViewColumns
from gui.viewColumn import ViewColumn
from gui import bitmapLoader
from gui.utils.numberFormatter import formatAmount
@@ -62,19 +61,30 @@ class Miscellanea(ViewColumn):
return (("displayName", bool, False),
("showIcon", bool, True))
def __getData(self, stuff):
item = stuff.item
if item is None:
return "", None
itemGroup = item.group.name
if itemGroup in ("Energy Weapon", "Hybrid Weapon", "Projectile Weapon", "Combat Drone", "Fighter Drone"):
itemCategory = item.category.name
if itemGroup == "Ship Modifiers":
return "", None
elif itemGroup in ("Energy Weapon", "Hybrid Weapon", "Projectile Weapon", "Combat Drone", "Fighter Drone"):
trackingSpeed = stuff.getModifiedItemAttr("trackingSpeed")
if not trackingSpeed:
return "", None
text = "{0}".format(formatAmount(trackingSpeed, 3, 0, 3))
tooltip = "Tracking speed"
return text, tooltip
elif itemCategory == "Subsystem":
slots = ("hi", "med", "low")
info = []
for slot in slots:
n = int(stuff.getModifiedItemAttr("%sSlotModifier"%slot))
if n > 0:
info.append("{0}{1}".format(n, slot[0].upper()))
return "+ "+", ".join(info), "Slot Modifiers"
elif itemGroup == "Energy Destabilizer":
neutAmount = stuff.getModifiedItemAttr("energyDestabilizationAmount")
cycleTime = stuff.cycleTime

View File

@@ -403,6 +403,10 @@ class FittingView(d.Display):
self.mods = fit.modules[:]
self.mods.sort(key=lambda mod: (slotOrder.index(mod.slot), mod.position))
# Blanks is a list of indexes that mark non-module positions (such
# as Racks and tactical Modes. This allows us to skip over common
# module operations such as swapping, removing, copying, etc. that
# would otherwise cause complications
self.blanks = [] # preliminary markers where blanks will be inserted
if sFit.serviceFittingOptions["rackSlots"]:
@@ -419,6 +423,15 @@ class FittingView(d.Display):
for i, (x, slot) in enumerate(self.blanks):
self.blanks[i] = x+i # modify blanks with actual index
self.mods.insert(x+i, Rack.buildRack(slot))
if fit.mode:
# Modes are special snowflakes and need a little manual loving
# We basically append the Mode rack and Mode to the modules
# while also marking their positions in the Blanks list
self.blanks.append(len(self.mods))
self.mods.append(Rack.buildRack(Slot.MODE))
self.blanks.append(len(self.mods))
self.mods.append(fit.mode)
else:
self.mods = None
@@ -457,7 +470,7 @@ class FittingView(d.Display):
sel = self.GetFirstSelected()
contexts = []
while sel != -1:
while sel != -1 and sel not in self.blanks:
mod = self.mods[self.GetItemData(sel)]
if not mod.isEmpty:
srcContext = "fittingModule"
@@ -544,14 +557,17 @@ class FittingView(d.Display):
font = (self.GetClassDefaultAttributes()).font
for i, mod in enumerate(self.mods):
if slotMap[mod.slot]:
if hasattr(mod,"slot") and slotMap[mod.slot]:
self.SetItemBackgroundColour(i, wx.Colour(204, 51, 51))
elif sFit.serviceFittingOptions["colorFitBySlot"] and not isinstance(mod, Rack):
self.SetItemBackgroundColour(i, self.slotColour(mod.slot))
else:
self.SetItemBackgroundColour(i, self.GetBackgroundColour())
if i in self.blanks and sFit.serviceFittingOptions["rackSlots"] and sFit.serviceFittingOptions["rackLabels"]:
# Set rack face to bold
if isinstance(mod, Rack) and \
sFit.serviceFittingOptions["rackSlots"] and \
sFit.serviceFittingOptions["rackLabels"]:
font.SetWeight(wx.FONTWEIGHT_BOLD)
self.SetItemFont(i, font)
else:

View File

@@ -31,13 +31,13 @@ class CharacterSelection(wx.Panel):
mainSizer = wx.BoxSizer(wx.HORIZONTAL)
self.SetSizer(mainSizer)
mainSizer.Add(wx.StaticText(self, wx.ID_ANY, "Character: "), 0, wx.CENTER | wx.TOP | wx.RIGHT | wx.LEFT, 3)
mainSizer.Add(wx.StaticText(self, wx.ID_ANY, "Character: "), 0, wx.CENTER | wx.RIGHT | wx.LEFT, 3)
# cache current selection to fall back in case we choose to open char editor
self.charCache = None
self.charChoice = wx.Choice(self)
mainSizer.Add(self.charChoice, 1, wx.ALIGN_CENTER_VERTICAL | wx.TOP | wx.RIGHT | wx.LEFT, 3)
mainSizer.Add(self.charChoice, 1, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.LEFT, 3)
self.refreshCharacterList()
@@ -56,11 +56,11 @@ class CharacterSelection(wx.Panel):
self.btnRefresh.Bind(wx.EVT_BUTTON, self.refreshApi)
self.btnRefresh.Enable(False)
mainSizer.Add(self.btnRefresh, 0, wx.ALIGN_CENTER_VERTICAL | wx.TOP | wx.RIGHT | wx.LEFT, 2)
mainSizer.Add(self.btnRefresh, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.LEFT, 2)
self.skillReqsStaticBitmap = wx.StaticBitmap(self)
self.skillReqsStaticBitmap.SetBitmap(self.cleanSkills)
mainSizer.Add(self.skillReqsStaticBitmap, 0, wx.ALIGN_CENTER_VERTICAL | wx.TOP | wx.RIGHT | wx.LEFT, 3)
mainSizer.Add(self.skillReqsStaticBitmap, 0, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.LEFT, 3)
self.Bind(wx.EVT_CHOICE, self.charChanged)
self.mainFrame.Bind(GE.CHAR_LIST_UPDATED, self.refreshCharacterList)

View File

@@ -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):

View File

@@ -203,6 +203,8 @@ class GraphFrame(wx.Frame):
legend.append(fit.name)
except:
self.SetStatusText("Invalid values in '%s'" % fit.name)
self.canvas.draw()
return
if self.legendFix and len(legend) > 0:
leg = self.subplot.legend(tuple(legend), "upper right" , shadow = False)

View File

@@ -22,9 +22,9 @@ import re
import gui.mainFrame
import bitmapLoader
import sys
import wx.lib.mixins.listctrl as listmix
import wx.lib.mixins.listctrl as listmix
import wx.html
from eos.types import Ship, Module, Skill, Booster, Implant, Drone
from eos.types import Ship, Module, Skill, Booster, Implant, Drone, Mode
from gui.utils.numberFormatter import formatAmount
import service
import config
@@ -32,7 +32,7 @@ import config
try:
from collections import OrderedDict
except ImportError:
from gui.utils.compat import OrderedDict
from utils.compat import OrderedDict
class ItemStatsDialog(wx.Dialog):
counter = 0
@@ -535,7 +535,7 @@ class ItemEffects (wx.Panel):
class ItemAffectedBy (wx.Panel):
ORDER = [Ship, Module, Drone, Implant, Booster, Skill]
ORDER = [Ship, Mode, Module, Drone, Implant, Booster, Skill]
def __init__(self, parent, stuff, item):
wx.Panel.__init__ (self, parent)
self.stuff = stuff

View File

@@ -100,7 +100,8 @@ class MainFrame(wx.Frame):
return cls.__instance if cls.__instance is not None else MainFrame()
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, title="pyfa - Python Fitting Assistant")
title="pyfa %s%s - Python Fitting Assistant"%(config.version, "" if config.tag.lower() != 'git' else " (git)")
wx.Frame.__init__(self, None, wx.ID_ANY, title)
MainFrame.__instance = self
@@ -166,7 +167,7 @@ class MainFrame(wx.Frame):
self.statsPane = StatsPane(self)
cstatsSizer.Add(self.statsPane, 0, wx.EXPAND)
mainSizer.Add(cstatsSizer, 0 , wx.EXPAND)
mainSizer.Add(cstatsSizer, 0, wx.EXPAND)
self.SetSizer(mainSizer)
@@ -214,7 +215,7 @@ class MainFrame(wx.Frame):
def LoadMainFrameAttribs(self):
mainFrameDefaultAttribs = {"wnd_width":1000, "wnd_height": 700, "wnd_maximized": False}
mainFrameDefaultAttribs = {"wnd_width": 1000, "wnd_height": 680, "wnd_maximized": False}
self.mainFrameAttribs = service.SettingsProvider.getInstance().getSettings("pyfaMainWindowAttribs", mainFrameDefaultAttribs)
if self.mainFrameAttribs["wnd_maximized"]:
@@ -289,6 +290,7 @@ class MainFrame(wx.Frame):
event.Skip()
def ShowAboutBox(self, evt):
import eos.config
info = wx.AboutDialogInfo()
info.Name = "pyfa"
info.Version = gui.aboutData.versionString
@@ -298,7 +300,8 @@ class MainFrame(wx.Frame):
"\n\t".join(gui.aboutData.credits) +
"\n\nLicenses:\n\t" +
"\n\t".join(gui.aboutData.licenses) +
"\n\nPython: \t" + sys.version +
"\n\nEVE Data: \t" + eos.config.gamedata_version +
"\nPython: \t" + sys.version +
"\nwxPython: \t" + wx.__version__ +
"\nSQLAlchemy: \t" + sqlalchemy.__version__,
700, wx.ClientDC(self))

View File

@@ -708,7 +708,12 @@ class ShipBrowser(wx.Panel):
self.raceselect.Show(False)
self.Layout()
RACE_ORDER = ["amarr", "caldari", "gallente", "minmatar", "sisters", "ore", "serpentis", "angel", "blood", "sansha", "guristas", "jove", None]
RACE_ORDER = [
"amarr", "caldari", "gallente", "minmatar",
"sisters", "ore",
"serpentis", "angel", "blood", "sansha", "guristas", "mordu",
"jove", None
]
def raceNameKey(self, ship):
return self.RACE_ORDER.index(ship.race), ship.name

View File

@@ -79,7 +79,7 @@ class StatsPane(wx.Panel):
mainSizer.Add(tp, 0, wx.EXPAND | wx.LEFT, 3)
if i < maxviews - 1:
mainSizer.Add(wx.StaticLine(self, wx.ID_ANY, style=wx.HORIZONTAL), 0, wx.EXPAND | wx.ALL,2)
mainSizer.Add(wx.StaticLine(self, wx.ID_ANY, style=wx.HORIZONTAL), 0, wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, 2)
i+=1
tp.OnStateChange(tp.GetBestSize())