Files
pyfa/gui/builtinContextMenus/moduleAmmoChange.py
2025-10-30 12:51:51 +01:00

203 lines
8.4 KiB
Python

from collections import OrderedDict
# noinspection PyPackageRequirements
import wx
import gui.fitCommands as cmd
import gui.mainFrame
from gui.bitmap_loader import BitmapLoader
from gui.contextMenu import ContextMenuCombined
from gui.fitCommands.helpers import getSimilarModPositions
from service.ammo import Ammo
from service.fit import Fit
_t = wx.GetTranslation
class ChangeModuleAmmo(ContextMenuCombined):
def __init__(self):
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
# Format: {type ID: set(loadable, charges)}
self.loadableChargesCache = {}
# Translations for the missile categories, as the text here is auto-generated via damage attributes
self.ddMissileChargeCatTrans = {
'em': _t('EM'),
'thermal': _t('Thermal'),
'explosive': _t('Explosive'),
'kinetic': _t('Kinetic'),
'mixed': _t('Mixed')}
self.oreChargeCatTrans = OrderedDict([
('a1', _t('Asteroid Simple')),
('a2', _t('Asteroid Coherent')),
('a3', _t('Asteroid Variegated')),
('a4', _t('Asteroid Complex')),
('a5', _t('Asteroid Abyssal')),
('a6', _t('Asteroid Mercoxit')),
('r4', _t('Moon Ubiquitous')),
('r8', _t('Moon Common')),
('r16', _t('Moon Uncommon')),
('r32', _t('Moon Rare')),
('r64', _t('Moon Exceptional')),
('err', _t('Erratic')),
('misc', _t('Misc'))])
def display(self, callingWindow, srcContext, mainItem, selection):
if srcContext not in ('fittingModule', 'projectedModule'):
return False
if self.mainFrame.getActiveFit() is None:
return False
self.mainCharges = self._getAmmo(mainItem)
if not self.mainCharges:
return False
self.module = mainItem
self.selection = selection
self.srcContext = srcContext
return True
def getText(self, callingWindow, itmContext, mainItem, selection):
return _t('Charge')
def _getAmmo(self, mod):
if mod.itemID is None:
return set()
if mod.itemID not in self.loadableChargesCache:
self.loadableChargesCache[mod.itemID] = Ammo.getInstance().getModuleFlatAmmo(mod)
return self.loadableChargesCache[mod.itemID]
def _addCharge(self, menu, charge):
id_ = ContextMenuCombined.nextID()
name = charge.name if charge is not None else _t('Empty')
self.chargeEventMap[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.iconID is not None:
bitmap = BitmapLoader.getBitmap(charge.iconID, 'icons')
if bitmap is not None:
item.SetBitmap(bitmap)
return item
@staticmethod
def _addSeparator(m, text):
id_ = ContextMenuCombined.nextID()
m.Append(id_, '%s' % text)
m.Enable(id_, False)
def getSubMenu(self, callingWindow, context, mainItem, selection, rootMenu, i, pitem):
msw = True if 'wxMSW' in wx.PlatformInfo else False
menu = wx.Menu()
self.chargeEventMap = {}
modType, chargeDict = Ammo.getInstance().getModuleStructuredAmmo(self.module, ammo=self.mainCharges)
if modType == 'ddTurret':
self._addSeparator(menu, _t('Long Range'))
menuItems = []
for charges in chargeDict.values():
if len(charges) == 1:
menuItems.append(self._addCharge(rootMenu if msw else menu, charges[0]))
else:
baseCharge = charges[0]
menuItem = self._addCharge(rootMenu if msw else menu, baseCharge)
menuItems.append(menuItem)
subMenu = wx.Menu()
subMenu.Bind(wx.EVT_MENU, self.handleAmmoSwitch)
menuItem.SetSubMenu(subMenu)
self._addSeparator(subMenu, _t('Less Damage'))
for charge in charges:
subMenu.Append(self._addCharge(rootMenu if msw else subMenu, charge))
self._addSeparator(subMenu, _t('More Damage'))
for menuItem in menuItems:
menu.Append(menuItem)
self._addSeparator(menu, _t('Short Range'))
elif modType == 'ddMissile':
menuItems = []
for chargeCatName, charges in chargeDict.items():
menuItem = wx.MenuItem(menu, wx.ID_ANY, self.ddMissileChargeCatTrans.get(chargeCatName, chargeCatName))
bitmap = BitmapLoader.getBitmap("%s_small" % chargeCatName, "gui")
if bitmap is not None:
menuItem.SetBitmap(bitmap)
menuItems.append(menuItem)
subMenu = wx.Menu()
subMenu.Bind(wx.EVT_MENU, self.handleAmmoSwitch)
menuItem.SetSubMenu(subMenu)
self._addSeparator(subMenu, _t('Less Damage'))
for charge in charges:
subMenu.Append(self._addCharge(rootMenu if msw else subMenu, charge))
self._addSeparator(subMenu, _t('More Damage'))
for menuItem in menuItems:
menu.Append(menuItem)
elif modType == 'miner':
menuItems = []
for catHandle, catLabel in self.oreChargeCatTrans.items():
charges = chargeDict.get(catHandle)
if not charges:
continue
if len(charges) == 1:
menuItems.append(self._addCharge(rootMenu if msw else menu, charges[0]))
else:
menuItem = wx.MenuItem(menu, wx.ID_ANY, catLabel)
menuItems.append(menuItem)
subMenu = wx.Menu()
subMenu.Bind(wx.EVT_MENU, self.handleAmmoSwitch)
menuItem.SetSubMenu(subMenu)
for charge in charges:
subMenu.Append(self._addCharge(rootMenu if msw else subMenu, charge))
for menuItem in menuItems:
menu.Append(menuItem)
elif modType == 'general':
for charge in chargeDict['general']:
menu.Append(self._addCharge(rootMenu if msw else menu, charge))
menu.Append(self._addCharge(rootMenu if msw else menu, None))
return menu
def handleAmmoSwitch(self, event):
charge = self.chargeEventMap.get(event.Id, False)
if charge is False:
event.Skip()
return
fitID = self.mainFrame.getActiveFit()
sFit = Fit.getInstance()
fit = sFit.getFit(fitID)
# Switch in selection or all modules, depending on modifier key state and settings
switchAll = sFit.serviceFittingOptions['ammoChangeAll'] is not (wx.GetMouseState().GetModifiers() in (wx.MOD_ALT, wx.MOD_CONTROL))
if switchAll:
if self.srcContext == 'fittingModule':
command = cmd.GuiChangeLocalModuleChargesCommand
modContainer = fit.modules
elif self.srcContext == 'projectedModule':
command = cmd.GuiChangeProjectedModuleChargesCommand
modContainer = fit.projectedModules
else:
return
positions = getSimilarModPositions(modContainer, self.module)
self.mainFrame.command.Submit(command(
fitID=fitID,
positions=positions,
chargeItemID=charge.ID if charge is not None else None))
else:
if self.srcContext == 'fittingModule':
command = cmd.GuiChangeLocalModuleChargesCommand
modContainer = fit.modules
elif self.srcContext == 'projectedModule':
command = cmd.GuiChangeProjectedModuleChargesCommand
modContainer = fit.projectedModules
else:
return
positions = []
for position, mod in enumerate(modContainer):
if mod in self.selection:
modCharges = self._getAmmo(mod)
if modCharges.issubset(self.mainCharges):
positions.append(position)
self.mainFrame.command.Submit(command(
fitID=fitID,
positions=positions,
chargeItemID=charge.ID if charge is not None else None))
ChangeModuleAmmo.register()