From 8d6ae56f3355059027363d162e8af938a4aeab32 Mon Sep 17 00:00:00 2001 From: PhatPhuckDave Date: Thu, 1 Jan 2026 20:38:18 +0100 Subject: [PATCH] Implement copy skills to clipboard --- gui/mainFrame.py | 63 +++++++++++++++++++++++++++++++++++++++++++++- gui/mainMenuBar.py | 3 +++ locale/lang.pot | 8 ++++++ 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/gui/mainFrame.py b/gui/mainFrame.py index 44bfc5c49..ed4da0038 100644 --- a/gui/mainFrame.py +++ b/gui/mainFrame.py @@ -18,6 +18,7 @@ # ============================================================================= import datetime +import itertools import os.path import threading import time @@ -60,8 +61,12 @@ from gui.shipBrowser import ShipBrowser from gui.statsPane import StatsPane from gui.targetProfileEditor import TargetProfileEditor from gui.updateDialog import UpdateDialog -from gui.utils.clipboard import fromClipboard +from gui.utils.clipboard import fromClipboard, toClipboard from gui.utils.progressHelper import ProgressHelper +from eos.const import FittingSlot as es_Slot +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 service.character import Character from service.esi import Esi from service.fit import Fit @@ -522,6 +527,8 @@ class MainFrame(wx.Frame): self.Bind(wx.EVT_MENU, self.backupToXml, id=menuBar.backupFitsId) # Export skills needed self.Bind(wx.EVT_MENU, self.exportSkillsNeeded, id=menuBar.exportSkillsNeededId) + # Copy skills needed + self.Bind(wx.EVT_MENU, self.copySkillsNeeded, id=menuBar.copySkillsNeededId) # Import character self.Bind(wx.EVT_MENU, self.importCharacter, id=menuBar.importCharacterId) # Export HTML @@ -832,6 +839,60 @@ class MainFrame(wx.Frame): self.waitDialog = wx.BusyInfo(_t("Exporting skills needed..."), parent=self) sCharacter.backupSkills(filePath, saveFmt, self.getActiveFit(), self.closeWaitDialog) + def copySkillsNeeded(self, event): + """ Copies skills used by the fit that the character has to clipboard """ + activeFitID = self.getActiveFit() + if activeFitID is None: + return + + sFit = Fit.getInstance() + fit = sFit.getFit(activeFitID) + if fit is None: + return + + if not fit.calculated: + fit.calculate() + + char = fit.character + skillsMap = {} + for thing in itertools.chain(fit.modules, fit.drones, fit.fighters, [fit.ship], fit.appliedImplants, fit.boosters, fit.cargo): + self._collectAffectingSkills(thing, char, skillsMap) + + skillsList = "" + for skillName in sorted(skillsMap): + charLevel = skillsMap[skillName] + for level in range(1, charLevel + 1): + skillsList += "%s %d\n" % (skillName, level) + + toClipboard(skillsList) + + def _collectAffectingSkills(self, thing, char, skillsMap): + """ Collect skills that affect items in the fit that the character has """ + 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 fileImportDialog(self, event): """Handles importing single/multiple EVE XML / EFT cfg fit files""" with wx.FileDialog( diff --git a/gui/mainMenuBar.py b/gui/mainMenuBar.py index ef677575d..d0ffcda6c 100644 --- a/gui/mainMenuBar.py +++ b/gui/mainMenuBar.py @@ -42,6 +42,7 @@ class MainMenuBar(wx.MenuBar): self.graphFrameId = wx.NewId() self.backupFitsId = wx.NewId() self.exportSkillsNeededId = wx.NewId() + self.copySkillsNeededId = wx.NewId() self.importCharacterId = wx.NewId() self.exportHtmlId = wx.NewId() self.wikiId = wx.NewId() @@ -117,6 +118,7 @@ class MainMenuBar(wx.MenuBar): characterMenu.AppendSeparator() characterMenu.Append(self.importCharacterId, _t("&Import Character File"), _t("Import characters into pyfa from file")) characterMenu.Append(self.exportSkillsNeededId, _t("&Export Skills Needed"), _t("Export skills needed for this fitting")) + characterMenu.Append(self.copySkillsNeededId, _t("&Copy Skills Needed"), _t("Copy skills needed for this fitting to clipboard")) characterMenu.AppendSeparator() characterMenu.Append(self.ssoLoginId, _t("&Manage ESI Characters")) @@ -178,6 +180,7 @@ class MainMenuBar(wx.MenuBar): self.Enable(wx.ID_SAVEAS, enable) self.Enable(wx.ID_COPY, enable) self.Enable(self.exportSkillsNeededId, enable) + self.Enable(self.copySkillsNeededId, enable) self.refreshUndo() diff --git a/locale/lang.pot b/locale/lang.pot index 9ce405514..6225326cd 100644 --- a/locale/lang.pot +++ b/locale/lang.pot @@ -77,6 +77,14 @@ msgstr "" msgid "&Export Skills Needed" msgstr "" +#: gui/mainMenuBar.py:120 +msgid "&Copy Skills Needed" +msgstr "" + +#: gui/mainMenuBar.py:120 +msgid "Copy skills needed for this fitting to clipboard" +msgstr "" + #: gui/mainMenuBar.py:66 gui/propertyEditor.py:42 msgid "&File" msgstr ""