Compare commits
5 Commits
feature/co
...
v2.65.2.9
| Author | SHA1 | Date | |
|---|---|---|---|
| eadf18ec00 | |||
| b70833ea3e | |||
| f12a0fe237 | |||
| de7f6a0523 | |||
| fa6dc76d10 |
220
gui/builtinItemStatsViews/itemSkills.py
Normal file
220
gui/builtinItemStatsViews/itemSkills.py
Normal file
@@ -0,0 +1,220 @@
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
import itertools
|
||||
|
||||
import gui.mainFrame
|
||||
from eos.saveddata.character import Skill
|
||||
from eos.saveddata.fighter import Fighter as es_Fighter
|
||||
from eos.saveddata.module import Module as es_Module
|
||||
from eos.saveddata.ship import Ship
|
||||
from gui.utils.clipboard import toClipboard
|
||||
from gui.utils.numberFormatter import formatAmount
|
||||
from service.fit import Fit
|
||||
|
||||
_t = wx.GetTranslation
|
||||
|
||||
|
||||
class ItemSkills(wx.Panel):
|
||||
def __init__(self, parent, stuff, item):
|
||||
wx.Panel.__init__(self, parent)
|
||||
self.stuff = stuff
|
||||
self.item = item
|
||||
|
||||
mainSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
leftPanel = wx.Panel(self)
|
||||
leftSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
leftPanel.SetSizer(leftSizer)
|
||||
|
||||
header = wx.StaticText(leftPanel, wx.ID_ANY, _t("Components"))
|
||||
font = header.GetFont()
|
||||
font.SetWeight(wx.FONTWEIGHT_BOLD)
|
||||
header.SetFont(font)
|
||||
leftSizer.Add(header, 0, wx.ALL, 5)
|
||||
|
||||
self.checkboxes = {}
|
||||
components = [
|
||||
("Ship", "ship"),
|
||||
("Modules", "modules"),
|
||||
("Drones", "drones"),
|
||||
("Fighters", "fighters"),
|
||||
("Cargo", "cargo"),
|
||||
("Implants", "appliedImplants"),
|
||||
("Boosters", "boosters"),
|
||||
("Necessary", "necessary"),
|
||||
]
|
||||
|
||||
for label, key in components:
|
||||
cb = wx.CheckBox(leftPanel, wx.ID_ANY, label)
|
||||
cb.SetValue(True)
|
||||
cb.Bind(wx.EVT_CHECKBOX, self.onCheckboxChange)
|
||||
self.checkboxes[key] = cb
|
||||
leftSizer.Add(cb, 0, wx.ALL, 2)
|
||||
|
||||
leftSizer.AddStretchSpacer()
|
||||
|
||||
mainSizer.Add(leftPanel, 0, wx.EXPAND | wx.ALL, 5)
|
||||
|
||||
rightPanel = wx.Panel(self)
|
||||
rightSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
rightPanel.SetSizer(rightSizer)
|
||||
|
||||
headerRight = wx.StaticText(rightPanel, wx.ID_ANY, _t("Skills"))
|
||||
fontRight = headerRight.GetFont()
|
||||
fontRight.SetWeight(wx.FONTWEIGHT_BOLD)
|
||||
headerRight.SetFont(fontRight)
|
||||
rightSizer.Add(headerRight, 0, wx.ALL, 5)
|
||||
|
||||
self.skillsText = wx.TextCtrl(rightPanel, wx.ID_ANY, "", style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_DONTWRAP)
|
||||
font = wx.Font(9, wx.FONTFAMILY_TELETYPE, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
|
||||
self.skillsText.SetFont(font)
|
||||
rightSizer.Add(self.skillsText, 1, wx.EXPAND | wx.ALL, 5)
|
||||
|
||||
mainSizer.Add(rightPanel, 1, wx.EXPAND | wx.ALL, 5)
|
||||
|
||||
self.SetSizer(mainSizer)
|
||||
|
||||
self.nbContainer = parent if isinstance(parent, wx.Notebook) else None
|
||||
if self.nbContainer:
|
||||
self.nbContainer.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.onTabChanged)
|
||||
|
||||
self.updateSkills()
|
||||
|
||||
def onCheckboxChange(self, event):
|
||||
self.updateSkills()
|
||||
self._copyToClipboard()
|
||||
|
||||
def updateSkills(self):
|
||||
fitID = gui.mainFrame.MainFrame.getInstance().getActiveFit()
|
||||
if fitID is None:
|
||||
self.skillsText.SetValue("")
|
||||
self._updateCheckboxStates(None)
|
||||
return
|
||||
|
||||
sFit = Fit.getInstance()
|
||||
fit = sFit.getFit(fitID)
|
||||
if fit is None:
|
||||
self.skillsText.SetValue("")
|
||||
self._updateCheckboxStates(None)
|
||||
return
|
||||
|
||||
if not fit.calculated:
|
||||
fit.calculate()
|
||||
|
||||
self._updateCheckboxStates(fit)
|
||||
|
||||
char = fit.character
|
||||
skillsMap = {}
|
||||
|
||||
items = []
|
||||
if self.checkboxes["ship"].GetValue():
|
||||
items.append(fit.ship)
|
||||
if self.checkboxes["modules"].GetValue():
|
||||
items.extend(fit.modules)
|
||||
if self.checkboxes["drones"].GetValue():
|
||||
items.extend(fit.drones)
|
||||
if self.checkboxes["fighters"].GetValue():
|
||||
items.extend(fit.fighters)
|
||||
if self.checkboxes["cargo"].GetValue():
|
||||
items.extend(fit.cargo)
|
||||
if self.checkboxes["appliedImplants"].GetValue():
|
||||
items.extend(fit.appliedImplants)
|
||||
if self.checkboxes["boosters"].GetValue():
|
||||
items.extend(fit.boosters)
|
||||
|
||||
for thing in items:
|
||||
self._collectAffectingSkills(thing, char, skillsMap)
|
||||
|
||||
if self.checkboxes["necessary"].GetValue():
|
||||
self._collectRequiredSkills(items, char, skillsMap)
|
||||
|
||||
skillsList = ""
|
||||
for skillName in sorted(skillsMap):
|
||||
charLevel = skillsMap[skillName]
|
||||
for level in range(1, charLevel + 1):
|
||||
skillsList += "%s %d\n" % (skillName, level)
|
||||
|
||||
self.skillsText.SetValue(skillsList)
|
||||
self._copyToClipboard()
|
||||
|
||||
def _copyToClipboard(self):
|
||||
skillsText = self.skillsText.GetValue()
|
||||
if skillsText:
|
||||
toClipboard(skillsText)
|
||||
|
||||
def onTabChanged(self, event):
|
||||
if self.nbContainer:
|
||||
pageIndex = self.nbContainer.FindPage(self)
|
||||
if pageIndex != -1 and event.GetSelection() == pageIndex:
|
||||
self.updateSkills()
|
||||
event.Skip()
|
||||
|
||||
def _updateCheckboxStates(self, fit):
|
||||
if fit is None:
|
||||
for cb in self.checkboxes.values():
|
||||
cb.Enable(False)
|
||||
return
|
||||
|
||||
self.checkboxes["ship"].Enable(True)
|
||||
self.checkboxes["modules"].Enable(len(fit.modules) > 0)
|
||||
self.checkboxes["drones"].Enable(len(fit.drones) > 0)
|
||||
self.checkboxes["fighters"].Enable(len(fit.fighters) > 0)
|
||||
self.checkboxes["cargo"].Enable(len(fit.cargo) > 0)
|
||||
self.checkboxes["appliedImplants"].Enable(len(fit.appliedImplants) > 0)
|
||||
self.checkboxes["boosters"].Enable(len(fit.boosters) > 0)
|
||||
self.checkboxes["necessary"].Enable(True)
|
||||
|
||||
def _collectAffectingSkills(self, thing, char, skillsMap):
|
||||
for attr in ("item", "charge"):
|
||||
if attr == "charge" and isinstance(thing, es_Fighter):
|
||||
continue
|
||||
subThing = getattr(thing, attr, None)
|
||||
if subThing is None:
|
||||
continue
|
||||
if isinstance(thing, es_Fighter) and attr == "charge":
|
||||
continue
|
||||
|
||||
if attr == "charge":
|
||||
cont = getattr(thing, "chargeModifiedAttributes", None)
|
||||
else:
|
||||
cont = getattr(thing, "itemModifiedAttributes", None)
|
||||
|
||||
if cont is not None:
|
||||
for attrName in cont.iterAfflictions():
|
||||
for fit, afflictors in cont.getAfflictions(attrName).items():
|
||||
for afflictor, operator, stackingGroup, preResAmount, postResAmount, used in afflictors:
|
||||
if isinstance(afflictor, Skill) and afflictor.character == char:
|
||||
skillName = afflictor.item.name
|
||||
if skillName not in skillsMap:
|
||||
skillsMap[skillName] = afflictor.level
|
||||
elif skillsMap[skillName] < afflictor.level:
|
||||
skillsMap[skillName] = afflictor.level
|
||||
|
||||
def _collectRequiredSkills(self, items, char, skillsMap):
|
||||
"""Collect required skills from items (necessary to use them)"""
|
||||
for thing in items:
|
||||
for attr in ("item", "charge"):
|
||||
if attr == "charge" and isinstance(thing, es_Fighter):
|
||||
continue
|
||||
subThing = getattr(thing, attr, None)
|
||||
if subThing is None:
|
||||
continue
|
||||
if isinstance(thing, es_Fighter) and attr == "charge":
|
||||
continue
|
||||
|
||||
if hasattr(subThing, "requiredSkills"):
|
||||
for reqSkill, level in subThing.requiredSkills.items():
|
||||
skillName = reqSkill.name
|
||||
charSkill = char.getSkill(reqSkill) if char else None
|
||||
charLevel = charSkill.level if charSkill else 0
|
||||
|
||||
if charLevel > 0:
|
||||
if skillName not in skillsMap:
|
||||
skillsMap[skillName] = charLevel
|
||||
elif skillsMap[skillName] < charLevel:
|
||||
skillsMap[skillName] = charLevel
|
||||
else:
|
||||
if skillName not in skillsMap:
|
||||
skillsMap[skillName] = level
|
||||
elif skillsMap[skillName] < level:
|
||||
skillsMap[skillName] = level
|
||||
@@ -23,6 +23,7 @@ class ItemView(Display):
|
||||
|
||||
DEFAULT_COLS = ["Base Icon",
|
||||
"Base Name",
|
||||
"Price",
|
||||
"attr:power,,,True",
|
||||
"attr:cpu,,,True"]
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
|
||||
from eos.gamedata import Item
|
||||
from eos.saveddata.cargo import Cargo
|
||||
from eos.saveddata.drone import Drone
|
||||
from eos.saveddata.fighter import Fighter
|
||||
@@ -53,7 +54,14 @@ class Price(ViewColumn):
|
||||
self.imageId = fittingView.imageList.GetImageIndex("totalPrice_small", "gui")
|
||||
|
||||
def getText(self, stuff):
|
||||
if stuff.item is None or stuff.item.group.name == "Ship Modifiers":
|
||||
if isinstance(stuff, Item):
|
||||
item = stuff
|
||||
else:
|
||||
if not hasattr(stuff, "item") or stuff.item is None:
|
||||
return ""
|
||||
item = stuff.item
|
||||
|
||||
if item.group.name == "Ship Modifiers":
|
||||
return ""
|
||||
|
||||
if hasattr(stuff, "isEmpty"):
|
||||
@@ -63,7 +71,7 @@ class Price(ViewColumn):
|
||||
if isinstance(stuff, Module) and stuff.isMutated:
|
||||
return ""
|
||||
|
||||
priceObj = stuff.item.price
|
||||
priceObj = item.price
|
||||
|
||||
if not priceObj.isValid():
|
||||
return False
|
||||
@@ -79,7 +87,11 @@ class Price(ViewColumn):
|
||||
|
||||
display.SetItem(colItem)
|
||||
|
||||
sPrice.getPrices([mod.item], callback, waitforthread=True)
|
||||
if isinstance(mod, Item):
|
||||
item = mod
|
||||
else:
|
||||
item = mod.item
|
||||
sPrice.getPrices([item], callback, waitforthread=True)
|
||||
|
||||
def getImageId(self, mod):
|
||||
return -1
|
||||
|
||||
@@ -49,6 +49,10 @@ class CharacterSelection(wx.Panel):
|
||||
|
||||
# cache current selection to fall back in case we choose to open char editor
|
||||
self.charCache = None
|
||||
|
||||
# history for Shift-Tab navigation
|
||||
self.charHistory = []
|
||||
self._updatingFromHistory = False
|
||||
|
||||
self.charChoice = wx.Choice(self)
|
||||
mainSizer.Add(self.charChoice, 1, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.LEFT, 3)
|
||||
@@ -189,6 +193,13 @@ class CharacterSelection(wx.Panel):
|
||||
sFit = Fit.getInstance()
|
||||
sFit.changeChar(fitID, charID)
|
||||
self.charCache = self.charChoice.GetCurrentSelection()
|
||||
|
||||
if not self._updatingFromHistory and charID is not None:
|
||||
currentChar = self.getActiveCharacter()
|
||||
if currentChar is not None:
|
||||
if not self.charHistory or self.charHistory[-1] != currentChar:
|
||||
self.charHistory.append(currentChar)
|
||||
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitIDs=(fitID,)))
|
||||
|
||||
def toggleRefreshButton(self):
|
||||
@@ -210,6 +221,29 @@ class CharacterSelection(wx.Panel):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def selectPreviousChar(self):
|
||||
currentChar = self.getActiveCharacter()
|
||||
if currentChar is None:
|
||||
return
|
||||
|
||||
if not self.charHistory:
|
||||
return
|
||||
|
||||
if self.charHistory and self.charHistory[-1] == currentChar:
|
||||
self.charHistory.pop()
|
||||
|
||||
if not self.charHistory:
|
||||
return
|
||||
|
||||
prevChar = self.charHistory.pop()
|
||||
if currentChar != prevChar:
|
||||
self.charHistory.append(currentChar)
|
||||
|
||||
self._updatingFromHistory = True
|
||||
if self.selectChar(prevChar):
|
||||
self.charChanged(None)
|
||||
self._updatingFromHistory = False
|
||||
|
||||
def fitChanged(self, event):
|
||||
"""
|
||||
@@ -222,7 +256,7 @@ class CharacterSelection(wx.Panel):
|
||||
self.charChoice.Enable(activeFitID is not None)
|
||||
choice = self.charChoice
|
||||
sFit = Fit.getInstance()
|
||||
currCharID = choice.GetClientData(choice.GetCurrentSelection())
|
||||
currCharID = choice.GetClientData(choice.GetCurrentSelection()) if choice.GetCurrentSelection() != -1 else None
|
||||
fit = sFit.getFit(activeFitID)
|
||||
newCharID = fit.character.ID if fit is not None else None
|
||||
|
||||
@@ -256,6 +290,9 @@ class CharacterSelection(wx.Panel):
|
||||
self.selectChar(sChar.all5ID())
|
||||
|
||||
elif currCharID != newCharID:
|
||||
if currCharID is not None and not self._updatingFromHistory:
|
||||
if not self.charHistory or self.charHistory[-1] != currCharID:
|
||||
self.charHistory.append(currCharID)
|
||||
self.selectChar(newCharID)
|
||||
if not fit.calculated:
|
||||
self.charChanged(None)
|
||||
|
||||
@@ -24,6 +24,7 @@ import config
|
||||
import gui.mainFrame
|
||||
from eos.saveddata.drone import Drone
|
||||
from eos.saveddata.module import Module
|
||||
from eos.saveddata.ship import Ship
|
||||
from gui.auxWindow import AuxiliaryFrame
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from gui.builtinItemStatsViews.itemAffectedBy import ItemAffectedBy
|
||||
@@ -35,6 +36,7 @@ from gui.builtinItemStatsViews.itemEffects import ItemEffects
|
||||
from gui.builtinItemStatsViews.itemMutator import ItemMutatorPanel
|
||||
from gui.builtinItemStatsViews.itemProperties import ItemProperties
|
||||
from gui.builtinItemStatsViews.itemRequirements import ItemRequirements
|
||||
from gui.builtinItemStatsViews.itemSkills import ItemSkills
|
||||
from gui.builtinItemStatsViews.itemTraits import ItemTraits
|
||||
from service.market import Market
|
||||
|
||||
@@ -156,6 +158,8 @@ class ItemStatsContainer(wx.Panel):
|
||||
def __init__(self, parent, stuff, item, context=None):
|
||||
wx.Panel.__init__(self, parent)
|
||||
sMkt = Market.getInstance()
|
||||
self.stuff = stuff
|
||||
self.context = context
|
||||
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
@@ -196,6 +200,10 @@ class ItemStatsContainer(wx.Panel):
|
||||
self.affectedby = ItemAffectedBy(self.nbContainer, stuff, item)
|
||||
self.nbContainer.AddPage(self.affectedby, _t("Affected by"))
|
||||
|
||||
if stuff is not None and isinstance(stuff, Ship):
|
||||
self.skills = ItemSkills(self.nbContainer, stuff, item)
|
||||
self.nbContainer.AddPage(self.skills, _t("Skills"))
|
||||
|
||||
if config.debug:
|
||||
self.properties = ItemProperties(self.nbContainer, stuff, item, context)
|
||||
self.nbContainer.AddPage(self.properties, _t("Properties"))
|
||||
|
||||
@@ -578,6 +578,7 @@ class MainFrame(wx.Frame):
|
||||
toggleShipMarketId = wx.NewId()
|
||||
ctabnext = wx.NewId()
|
||||
ctabprev = wx.NewId()
|
||||
charPrevId = wx.NewId()
|
||||
|
||||
# Close Page
|
||||
self.Bind(wx.EVT_MENU, self.CloseCurrentPage, id=self.closePageId)
|
||||
@@ -587,6 +588,7 @@ class MainFrame(wx.Frame):
|
||||
self.Bind(wx.EVT_MENU, self.toggleShipMarket, id=toggleShipMarketId)
|
||||
self.Bind(wx.EVT_MENU, self.CTabNext, id=ctabnext)
|
||||
self.Bind(wx.EVT_MENU, self.CTabPrev, id=ctabprev)
|
||||
self.Bind(wx.EVT_MENU, self.selectPreviousCharacter, id=charPrevId)
|
||||
|
||||
actb = [(wx.ACCEL_CTRL, ord('T'), self.addPageId),
|
||||
(wx.ACCEL_CMD, ord('T'), self.addPageId),
|
||||
@@ -620,7 +622,10 @@ class MainFrame(wx.Frame):
|
||||
(wx.ACCEL_CMD, wx.WXK_PAGEDOWN, ctabnext),
|
||||
(wx.ACCEL_CMD, wx.WXK_PAGEUP, ctabprev),
|
||||
|
||||
(wx.ACCEL_CMD | wx.ACCEL_SHIFT, ord("Z"), wx.ID_REDO)
|
||||
(wx.ACCEL_CMD | wx.ACCEL_SHIFT, ord("Z"), wx.ID_REDO),
|
||||
|
||||
# Shift+Tab for previous character
|
||||
(wx.ACCEL_SHIFT, wx.WXK_TAB, charPrevId)
|
||||
]
|
||||
|
||||
# Ctrl/Cmd+# for addition pane selection
|
||||
@@ -746,6 +751,9 @@ class MainFrame(wx.Frame):
|
||||
|
||||
def CTabPrev(self, event):
|
||||
self.fitMultiSwitch.PrevPage()
|
||||
|
||||
def selectPreviousCharacter(self, event):
|
||||
self.charSelection.selectPreviousChar()
|
||||
|
||||
def HAddPage(self, event):
|
||||
self.fitMultiSwitch.AddPage()
|
||||
@@ -855,7 +863,8 @@ class MainFrame(wx.Frame):
|
||||
|
||||
char = fit.character
|
||||
skillsMap = {}
|
||||
for thing in itertools.chain(fit.modules, fit.drones, fit.fighters, [fit.ship], fit.appliedImplants, fit.boosters, fit.cargo):
|
||||
# for thing in itertools.chain(fit.modules, fit.drones, fit.fighters, [fit.ship], fit.appliedImplants, fit.boosters, fit.cargo):
|
||||
for thing in itertools.chain(fit.modules, fit.drones, fit.fighters, fit.appliedImplants, fit.boosters, fit.cargo):
|
||||
self._collectAffectingSkills(thing, char, skillsMap)
|
||||
|
||||
skillsList = ""
|
||||
|
||||
Reference in New Issue
Block a user