Merge pull request #168 from blitzmann/161-effDps

Implement effective DPS
This commit is contained in:
Ryan Holmes
2014-09-19 19:18:20 -04:00
28 changed files with 1075 additions and 151 deletions

View File

@@ -1,2 +1,3 @@
__all__ = ["moduleAmmoPicker", "itemStats", "damagePattern", "marketJump", "droneSplit", "itemRemove",
"droneRemoveStack", "ammoPattern", "project", "factorReload", "whProjector", "cargo", "shipJump"]
"droneRemoveStack", "ammoPattern", "project", "factorReload", "whProjector", "cargo", "shipJump",
"targetResists"]

View File

@@ -67,7 +67,7 @@ class ChangeAffectingSkills(ContextMenu):
rootMenu.Bind(wx.EVT_MENU, self.handleSkillChange, menuItem)
return menuItem
def getSubMenu(self, context, selection, menu, i):
def getSubMenu(self, context, selection, menu, i, pitem):
self.context = context
self.skillIds = {}

View File

@@ -13,35 +13,92 @@ class DamagePattern(ContextMenu):
return srcContext in ("resistancesViewFull",) and self.mainFrame.getActiveFit() is not None
def getText(self, itmContext, selection):
sDP = service.DamagePattern.getInstance()
self.patterns = sDP.getDamagePatternList()
self.patterns.sort( key=lambda p: (p.name in ["Selected Ammo",
"Uniform"], p.name) )
m = map(lambda p: p.name, self.patterns)
return m
def activate(self, fullContext, selection, i):
sDP = service.DamagePattern.getInstance()
sFit = service.Fit.getInstance()
fitID = self.mainFrame.getActiveFit()
sFit.setDamagePattern(fitID, self.patterns[i])
setattr(self.mainFrame,"_activeDmgPattern",self.patterns[i])
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.patternIds = {}
self.subMenus = {}
self.singles = []
# iterate and separate damage patterns based on "[Parent] Child"
for pattern in self.patterns:
start, end = pattern.name.find('['), pattern.name.find(']')
if start is not -1 and end is not -1:
currBase = pattern.name[start+1:end]
# set helper attr
setattr(pattern, "_name", pattern.name[end+1:].strip())
if currBase not in self.subMenus:
self.subMenus[currBase] = []
self.subMenus[currBase].append(pattern)
else:
self.singles.append(pattern)
# return list of names, with singles first followed by submenu names
self.m = map(lambda p: p.name, self.singles) + self.subMenus.keys()
return self.m
def handlePatternSwitch(self, event):
pattern = self.patternIds.get(event.Id, False)
if pattern is False:
event.Skip()
return
sFit = service.Fit.getInstance()
fitID = self.mainFrame.getActiveFit()
sFit.setDamagePattern(fitID, pattern)
setattr(self.mainFrame,"_activeDmgPattern", pattern)
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))
def getBitmap(self, context, selection):
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 is None:
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
index = self.patterns.index(dp)
bitmap = bitmapLoader.getBitmap("state_active_small", "icons")
l = [None] * len(self.patterns)
l[index] = bitmap
sub = wx.Menu()
sub.Bind(wx.EVT_MENU, self.handlePatternSwitch)
return l
# 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

@@ -116,7 +116,7 @@ class ModuleAmmoPicker(ContextMenu):
m.Append(id, u'%s' % text)
m.Enable(id, False)
def getSubMenu(self, context, selection, menu, i):
def getSubMenu(self, context, selection, menu, i, pitem):
self.context = context
menu.Bind(wx.EVT_MENU, self.handleAmmoSwitch)
m = wx.Menu()

View File

@@ -0,0 +1,114 @@
# -*- coding: utf-8 -*-
from gui.contextMenu import ContextMenu
import gui.mainFrame
import service
import gui.globalEvents as GE
import wx
from gui import bitmapLoader
class TargetResists(ContextMenu):
def __init__(self):
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
def display(self, srcContext, selection):
if self.mainFrame.getActiveFit() is None or srcContext not in ("firepowerViewFull",):
return False
sTR = service.TargetResists.getInstance()
self.patterns = sTR.getTargetResistsList()
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:
event.Skip()
return
sFit = service.Fit.getInstance()
fitID = self.mainFrame.getActiveFit()
sFit.setTargetResists(fitID, pattern)
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))
def addPattern(self, menu, pattern, currBase = None):
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)
# set pattern attr to menu item
item.pattern = pattern
# determine active pattern
sFit = service.Fit.getInstance()
fitID = self.mainFrame.getActiveFit()
f = sFit.getFit(fitID)
tr = f.targetResists
if tr == pattern:
bitmap = bitmapLoader.getBitmap("state_active_small", "icons")
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)
self.patternIds = {}
self.subMenus = {}
self.singles = []
for pattern in self.patterns:
start, end = pattern.name.find('['), pattern.name.find(']')
if start is not -1 and end is not -1:
currBase = pattern.name[start+1:end]
# set helper attr
setattr(pattern, "_name", pattern.name[end+1:].strip())
if currBase not in self.subMenus:
self.subMenus[currBase] = []
self.subMenus[currBase].append(pattern)
else:
self.singles.append(pattern)
m.AppendItem(self.addPattern(m, None)) # Add reset
m.AppendSeparator()
# Single items, no parent
for pattern in self.singles:
m.AppendItem(self.addPattern(m, 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)
# Create menu for child items
sub = wx.Menu()
sub.Bind(wx.EVT_MENU, self.handleResistSwitch)
# Apply child menu to parent item
item.SetSubMenu(sub)
# 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
return m
TargetResists.register()

View File

@@ -17,7 +17,7 @@ class WhProjector(ContextMenu):
def activate(self, fullContext, selection, i):
pass
def getSubMenu(self, context, selection, menu, i):
def getSubMenu(self, context, selection, menu, i, pitem):
self.idmap = {}
menu.Bind(wx.EVT_MENU, self.handleSelection)
m = wx.Menu()

View File

@@ -40,13 +40,20 @@ class FirepowerViewFull(StatsView):
def populatePanel(self, contentPanel, headerPanel):
contentSizer = contentPanel.GetSizer()
parent = self.panel = contentPanel
self.headerPanel = headerPanel
headerContentSizer = wx.BoxSizer(wx.HORIZONTAL)
hsizer = headerPanel.GetSizer()
hsizer.Add(headerContentSizer,0,0,0)
self.stEff = wx.StaticText(headerPanel, wx.ID_ANY, "( Effective )")
headerContentSizer.Add(self.stEff)
headerPanel.GetParent().AddToggleItem(self.stEff)
panel = "full"
sizerFirepower = wx.FlexGridSizer(1, 4)
sizerFirepower.AddGrowableCol(1)
contentSizer.Add( sizerFirepower, 0, wx.EXPAND, 0)
counter = 0
@@ -129,6 +136,10 @@ class FirepowerViewFull(StatsView):
def refreshPanel(self, fit):
#If we did anything intresting, we'd update our labels to reflect the new fit's stats here
if fit is not None and fit.targetResists is not None:
self.stEff.Show()
else:
self.stEff.Hide()
stats = (("labelFullDpsWeapon", lambda: fit.weaponDPS, 3, 0, 0, "%s DPS",None),
("labelFullDpsDrone", lambda: fit.droneDPS, 3, 0, 0, "%s DPS", None),

View File

@@ -54,7 +54,7 @@ class ContextMenu(object):
item = wx.MenuItem(menu, id, text)
menu.info[id] = (m, fullContext, it)
sub = m.getSubMenu(srcContext, selection, menu, it)
sub = m.getSubMenu(srcContext, selection, menu, it, item)
if sub is not None:
item.SetSubMenu(sub)
@@ -95,7 +95,7 @@ class ContextMenu(object):
def activate(self, context, selection, i):
return None
def getSubMenu(self, context, selection, menu, i):
def getSubMenu(self, context, selection, menu, i, pitem):
return None
def getText(self, context, selection):

View File

@@ -46,6 +46,7 @@ from gui.shipBrowser import ShipBrowser, FitSelected
from gui.characterEditor import CharacterEditor
from gui.characterSelection import CharacterSelection
from gui.patternEditor import DmgPatternEditorDlg
from gui.resistsEditor import ResistsEditorDlg
from gui.preferenceDialog import PreferenceDialog
from gui.graphFrame import GraphFrame
from gui.copySelectDialog import CopySelectDialog
@@ -311,6 +312,11 @@ class MainFrame(wx.Frame):
dlg=CharacterEditor(self)
dlg.Show()
def showTargetResistsEditor(self, event):
dlg=ResistsEditorDlg(self)
dlg.ShowModal()
dlg.Destroy()
def showDamagePatternEditor(self, event):
dlg=DmgPatternEditorDlg(self)
dlg.ShowModal()
@@ -392,6 +398,8 @@ class MainFrame(wx.Frame):
self.Bind(wx.EVT_MENU, self.showCharacterEditor, id=menuBar.characterEditorId)
# Damage pattern editor
self.Bind(wx.EVT_MENU, self.showDamagePatternEditor, id=menuBar.damagePatternEditorId)
# Target Resists editor
self.Bind(wx.EVT_MENU, self.showTargetResistsEditor, id=menuBar.targetResistsEditorId)
# Import dialog
self.Bind(wx.EVT_MENU, self.showImportDialog, id=wx.ID_OPEN)
# Export dialog

View File

@@ -28,6 +28,7 @@ class MainMenuBar(wx.MenuBar):
def __init__(self):
self.characterEditorId = wx.NewId()
self.damagePatternEditorId = wx.NewId()
self.targetResistsEditorId = wx.NewId()
self.graphFrameId = wx.NewId()
self.backupFitsId = wx.NewId()
self.exportSkillsNeededId = wx.NewId()
@@ -82,6 +83,10 @@ class MainMenuBar(wx.MenuBar):
damagePatternEditItem.SetBitmap(bitmapLoader.getBitmap("damagePattern_small", "icons"))
windowMenu.AppendItem(damagePatternEditItem)
targetResistsEditItem = wx.MenuItem(windowMenu, self.targetResistsEditorId, "Target Resists Editor\tCTRL+R")
targetResistsEditItem.SetBitmap(bitmapLoader.getBitmap("explosive_big", "icons"))
windowMenu.AppendItem(targetResistsEditItem)
graphFrameItem = wx.MenuItem(windowMenu, self.graphFrameId, "Graphs\tCTRL+G")
graphFrameItem.SetBitmap(bitmapLoader.getBitmap("graphs_small", "icons"))
windowMenu.AppendItem(graphFrameItem)

View File

@@ -22,12 +22,14 @@ import bitmapLoader
import service
from wx.lib.intctrl import IntCtrl
from gui.utils.clipboard import toClipboard, fromClipboard
from service.damagePattern import ImportError
###########################################################################
## Class DmgPatternEditorDlg
###########################################################################
class DmgPatternEditorDlg (wx.Dialog):
DAMAGE_TYPES = ("em", "thermal", "kinetic", "explosive")
def __init__(self, parent):
wx.Dialog.__init__ (self, parent, id = wx.ID_ANY, title = u"Damage Pattern Editor", size = wx.Size( 400,240 ))
@@ -93,34 +95,37 @@ class DmgPatternEditorDlg (wx.Dialog):
self.kinbitmap = bitmapLoader.getBitmap("kinetic_big", "icons")
self.expbitmap = bitmapLoader.getBitmap("explosive_big", "icons")
dmgeditSizer = wx.FlexGridSizer(2, 4, 0, 2)
dmgeditSizer = wx.FlexGridSizer(2, 6, 0, 2)
dmgeditSizer.AddGrowableCol(0)
dmgeditSizer.AddGrowableCol(3)
dmgeditSizer.AddGrowableCol(5)
dmgeditSizer.SetFlexibleDirection(wx.BOTH)
dmgeditSizer.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED)
width = -1
defSize = wx.Size(width,-1)
self.bmpEM = wx.StaticBitmap(self, wx.ID_ANY, self.embitmap)
dmgeditSizer.Add(self.bmpEM, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT, 5)
self.editEm = IntCtrl(self, wx.ID_ANY, 0, wx.DefaultPosition, defSize)
dmgeditSizer.Add(self.editEm, 0, wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_VERTICAL, 5)
for i, type in enumerate(self.DAMAGE_TYPES):
bmp = wx.StaticBitmap(self, wx.ID_ANY, bitmapLoader.getBitmap("%s_big"%type, "icons"))
if i%2:
style = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT
border = 10
else:
style = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT
border = 5
self.bmpTHERM = wx.StaticBitmap(self, wx.ID_ANY, self.thermbitmap)
dmgeditSizer.Add(self.bmpTHERM, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT, 25)
self.editThermal = IntCtrl(self, wx.ID_ANY, 0, wx.DefaultPosition, defSize, 0)
dmgeditSizer.Add(self.editThermal, 0, wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_VERTICAL, 5)
# set text edit
setattr(self, "%sEdit"%type, IntCtrl(self, wx.ID_ANY, 0, wx.DefaultPosition, defSize))
setattr(self, "%sPerc"%type, wx.StaticText(self, wx.ID_ANY, u"0%"))
editObj = getattr(self, "%sEdit"%type)
self.bmpKIN = wx.StaticBitmap(self, wx.ID_ANY, self.kinbitmap)
dmgeditSizer.Add(self.bmpKIN, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT, 5)
self.editKinetic = IntCtrl(self, wx.ID_ANY, 0, wx.DefaultPosition, defSize)
dmgeditSizer.Add(self.editKinetic, 0, wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_VERTICAL, 5)
dmgeditSizer.Add(bmp, 0, style, border)
dmgeditSizer.Add(editObj, 0, wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_VERTICAL, 5)
dmgeditSizer.Add(getattr(self, "%sPerc"%type), 0, wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 5)
self.bmpEXP = wx.StaticBitmap(self, wx.ID_ANY, self.expbitmap)
dmgeditSizer.Add(self.bmpEXP, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT, 25)
self.editExplosive = IntCtrl(self, wx.ID_ANY, 0, wx.DefaultPosition, defSize, 0)
dmgeditSizer.Add(self.editExplosive, 0, wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_VERTICAL, 5)
editObj.Bind(wx.EVT_TEXT, self.ValuesUpdated)
editObj.SetLimited(True)
editObj.SetMin(0)
editObj.SetMax(99999)
contentSizer.Add(dmgeditSizer, 1, wx.EXPAND | wx.ALL, 5)
self.slfooter = wx.StaticLine(self)
@@ -129,9 +134,9 @@ class DmgPatternEditorDlg (wx.Dialog):
footerSizer = wx.BoxSizer(wx.HORIZONTAL)
perSizer = wx.BoxSizer(wx.VERTICAL)
self.stPercentages = wx.StaticText(self, wx.ID_ANY, u"")
self.stPercentages.Wrap(-1)
perSizer.Add(self.stPercentages, 0, wx.BOTTOM | wx.TOP | wx.LEFT, 5)
self.stNotice = wx.StaticText(self, wx.ID_ANY, u"")
self.stNotice.Wrap(-1)
perSizer.Add(self.stNotice, 0, wx.BOTTOM | wx.TOP | wx.LEFT, 5)
footerSizer.Add(perSizer, 1, wx.ALIGN_CENTER_VERTICAL, 5)
@@ -167,22 +172,6 @@ class DmgPatternEditorDlg (wx.Dialog):
bsize = self.GetBestSize()
self.SetSize((-1,bsize.height))
self.editEm.SetLimited(True)
self.editThermal.SetLimited(True)
self.editKinetic.SetLimited(True)
self.editExplosive.SetLimited(True)
self.editEm.SetMin(0)
self.editThermal.SetMin(0)
self.editKinetic.SetMin(0)
self.editExplosive.SetMin(0)
self.editEm.SetMax(99999)
self.editThermal.SetMax(99999)
self.editKinetic.SetMax(99999)
self.editExplosive.SetMax(99999)
self.new.Bind(wx.EVT_BUTTON, self.newPattern)
self.rename.Bind(wx.EVT_BUTTON, self.renamePattern)
self.copy.Bind(wx.EVT_BUTTON, self.copyPattern)
@@ -190,11 +179,6 @@ class DmgPatternEditorDlg (wx.Dialog):
self.Import.Bind(wx.EVT_BUTTON, self.importPatterns)
self.Export.Bind(wx.EVT_BUTTON, self.exportPatterns)
self.editEm.Bind(wx.EVT_TEXT, self.ValuesUpdated)
self.editThermal.Bind(wx.EVT_TEXT, self.ValuesUpdated)
self.editKinetic.Bind(wx.EVT_TEXT, self.ValuesUpdated)
self.editExplosive.Bind(wx.EVT_TEXT, self.ValuesUpdated)
self.patternChanged()
def closeEvent(self, event):
@@ -205,18 +189,13 @@ class DmgPatternEditorDlg (wx.Dialog):
return
p = self.getActivePattern()
p.emAmount = self._EM = self.editEm.GetValue()
p.thermalAmount = self._THERM = self.editThermal.GetValue()
p.kineticAmount = self._KIN = self.editKinetic.GetValue()
p.explosiveAmount = self._EXP = self.editExplosive.GetValue()
total = self._EM + self._THERM + self._KIN + self._EXP
format = "EM: %d%%, THERM: %d%%, KIN: %d%%, EXP: %d%%"
if total > 0:
ltext = format %(self._EM*100/total, self._THERM*100/total, self._KIN*100/total, self._EXP*100/total)
else:
ltext = format %(0, 0, 0, 0)
total = sum(map(lambda attr: getattr(self, "%sEdit"%attr).GetValue(), self.DAMAGE_TYPES))
for type in self.DAMAGE_TYPES:
editObj = getattr(self, "%sEdit"%type)
percObj = getattr(self, "%sPerc"%type)
setattr(p, "%sAmount"%type, editObj.GetValue())
percObj.SetLabel("%.1f%%"%(float(editObj.GetValue())*100/total if total > 0 else 0))
self.stPercentages.SetLabel(ltext)
self.totSizer.Layout()
if event is not None:
@@ -225,18 +204,16 @@ class DmgPatternEditorDlg (wx.Dialog):
service.DamagePattern.getInstance().saveChanges(p)
def restrict(self):
self.editEm.Enable(False)
self.editExplosive.Enable(False)
self.editKinetic.Enable(False)
self.editThermal.Enable(False)
for type in self.DAMAGE_TYPES:
editObj = getattr(self, "%sEdit"%type)
editObj.Enable(False)
self.rename.Enable(False)
self.delete.Enable(False)
def unrestrict(self):
self.editEm.Enable()
self.editExplosive.Enable()
self.editKinetic.Enable()
self.editThermal.Enable()
for type in self.DAMAGE_TYPES:
editObj = getattr(self, "%sEdit"%type)
editObj.Enable()
self.rename.Enable()
self.delete.Enable()
@@ -248,6 +225,7 @@ class DmgPatternEditorDlg (wx.Dialog):
def patternChanged(self, event=None):
p = self.getActivePattern()
if p is None:
return
@@ -257,8 +235,9 @@ class DmgPatternEditorDlg (wx.Dialog):
self.unrestrict()
self.block = True
for field in ("em", "thermal", "kinetic", "explosive"):
edit = getattr(self, "edit%s" % field.capitalize())
for field in self.DAMAGE_TYPES:
edit = getattr(self, "%sEdit" % field)
amount = getattr(p, "%sAmount" % field)
edit.SetValue(amount)
@@ -271,6 +250,13 @@ class DmgPatternEditorDlg (wx.Dialog):
self.choices.append(p)
id = self.ccDmgPattern.Append(p.name)
self.ccDmgPattern.SetSelection(id)
self.restrict()
# reset values
for type in self.DAMAGE_TYPES:
editObj = getattr(self, "%sEdit"%type)
editObj.SetValue(0)
self.btnSave.SetLabel("Create")
self.renamePattern()
@@ -296,16 +282,16 @@ class DmgPatternEditorDlg (wx.Dialog):
def processRename(self, event):
newName = self.namePicker.GetLineText(0)
self.stPercentages.SetLabel("")
self.stNotice.SetLabel("")
p = self.getActivePattern()
for pattern in self.choices:
if pattern.name == newName and p != pattern:
self.stPercentages.SetLabel("Name already used, please pick another")
self.stNotice.SetLabel("Name already used, please choose another")
return
if newName == "":
self.stPercentages.SetLabel("Invalid name.")
self.stNotice.SetLabel("Invalid name.")
return
sDP = service.DamagePattern.getInstance()
@@ -349,16 +335,42 @@ class DmgPatternEditorDlg (wx.Dialog):
def __del__( self ):
pass
def updateChoices(self):
"Gathers list of patterns and updates choice selections"
sDP = service.DamagePattern.getInstance()
self.choices = sDP.getDamagePatternList()
for dp in self.choices:
if dp.name == "Selected Ammo": # don't include this special butterfly
self.choices.remove(dp)
# Sort the remaining list and continue on
self.choices.sort(key=lambda p: p.name)
self.ccDmgPattern.Clear()
for choice in map(lambda p: p.name, self.choices):
self.ccDmgPattern.Append(choice)
self.ccDmgPattern.SetSelection(0)
self.patternChanged()
def importPatterns(self, event):
text = fromClipboard()
if text:
sDP = service.DamagePattern.getInstance()
sDP.importPatterns(text)
self.stPercentages.SetLabel("Patterns imported from clipboard")
try:
sDP.importPatterns(text)
self.stNotice.SetLabel("Patterns successfully imported from clipboard")
except service.damagePattern.ImportError, e:
self.stNotice.SetLabel(str(e))
except Exception, e:
self.stNotice.SetLabel("Could not import from clipboard: unknown errors")
finally:
self.updateChoices()
else:
self.stPercentages.SetLabel("Could not import from clipboard")
self.stNotice.SetLabel("Could not import from clipboard")
def exportPatterns(self, event):
sDP = service.DamagePattern.getInstance()
toClipboard( sDP.exportPatterns() )
self.stPercentages.SetLabel("Patterns exported to clipboard")
self.stNotice.SetLabel("Patterns exported to clipboard")

407
gui/resistsEditor.py Normal file
View File

@@ -0,0 +1,407 @@
#===============================================================================
# Copyright (C) 2014 Ryan Holmes
#
# This file is part of pyfa.
#
# pyfa is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pyfa is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
#===============================================================================
import wx
import bitmapLoader
import service
from gui.utils.clipboard import toClipboard, fromClipboard
from service.targetResists import ImportError
class ResistsEditorDlg (wx.Dialog):
DAMAGE_TYPES = ("em", "thermal", "kinetic", "explosive")
def __init__(self, parent):
wx.Dialog.__init__ (self, parent, id = wx.ID_ANY, title = u"Target Resists Editor", size = wx.Size( 350,240 ))
self.block = False
self.SetSizeHintsSz(wx.DefaultSize, wx.DefaultSize)
mainSizer = wx.BoxSizer(wx.VERTICAL)
self.headerSizer = headerSizer = wx.BoxSizer(wx.HORIZONTAL)
sTR = service.TargetResists.getInstance()
self.choices = sTR.getTargetResistsList()
# Sort the remaining list and continue on
self.choices.sort(key=lambda p: p.name)
self.ccResists = wx.Choice(self, choices=map(lambda p: p.name, self.choices))
self.ccResists.Bind(wx.EVT_CHOICE, self.patternChanged)
self.ccResists.SetSelection(0)
self.namePicker = wx.TextCtrl(self, style=wx.TE_PROCESS_ENTER)
self.namePicker.Bind(wx.EVT_TEXT_ENTER, self.processRename)
self.namePicker.Hide()
self.btnSave = wx.Button(self, wx.ID_SAVE)
self.btnSave.Hide()
self.btnSave.Bind(wx.EVT_BUTTON, self.processRename)
size = None
headerSizer.Add(self.ccResists, 1, wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.LEFT, 3)
buttons = (("new", wx.ART_NEW),
("rename", bitmapLoader.getBitmap("rename", "icons")),
("copy", wx.ART_COPY),
("delete", wx.ART_DELETE))
for name, art in buttons:
bitmap = wx.ArtProvider.GetBitmap(art, wx.ART_BUTTON) if name != "rename" else art
btn = wx.BitmapButton(self, wx.ID_ANY, bitmap)
if size is None:
size = btn.GetSize()
btn.SetMinSize(size)
btn.SetMaxSize(size)
btn.Layout()
setattr(self, name, btn)
btn.Enable(True)
btn.SetToolTipString("%s resist profile" % name.capitalize())
headerSizer.Add(btn, 0, wx.ALIGN_CENTER_VERTICAL)
mainSizer.Add(headerSizer, 0, wx.EXPAND | wx.ALL, 2)
self.sl = wx.StaticLine(self)
mainSizer.Add(self.sl, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)
contentSizer = wx.BoxSizer(wx.VERTICAL)
resistEditSizer = wx.FlexGridSizer(2, 6, 0, 2)
resistEditSizer.AddGrowableCol(0)
resistEditSizer.AddGrowableCol(5)
resistEditSizer.SetFlexibleDirection(wx.BOTH)
resistEditSizer.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED)
width = -1
defSize = wx.Size(50,-1)
for i, type in enumerate(self.DAMAGE_TYPES):
if i%2:
style = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT
border = 25
else:
style = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT
border = 5
bmp = wx.StaticBitmap(self, wx.ID_ANY, bitmapLoader.getBitmap("%s_big"%type, "icons"))
resistEditSizer.Add(bmp, 0, style, border)
# set text edit
setattr(self, "%sEdit"%type, wx.TextCtrl(self, wx.ID_ANY, "", wx.DefaultPosition, defSize))
editObj = getattr(self, "%sEdit"%type)
resistEditSizer.Add(editObj, 0, wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_VERTICAL, 5)
resistEditSizer.Add(wx.StaticText( self, wx.ID_ANY, u"%", wx.DefaultPosition, wx.DefaultSize, 0 ), 0, wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_VERTICAL, 5)
editObj.Bind(wx.EVT_TEXT, self.ValuesUpdated)
contentSizer.Add(resistEditSizer, 1, wx.EXPAND | wx.ALL, 5)
self.slfooter = wx.StaticLine(self)
contentSizer.Add(self.slfooter, 0, wx.EXPAND | wx.TOP, 5)
footerSizer = wx.BoxSizer(wx.HORIZONTAL)
perSizer = wx.BoxSizer(wx.VERTICAL)
self.stNotice = wx.StaticText(self, wx.ID_ANY, u"")
self.stNotice.Wrap(-1)
perSizer.Add(self.stNotice, 0, wx.BOTTOM | wx.TOP | wx.LEFT, 5)
footerSizer.Add(perSizer, 1, wx.ALIGN_CENTER_VERTICAL, 5)
self.totSizer = wx.BoxSizer(wx.VERTICAL)
contentSizer.Add(footerSizer, 0, wx.EXPAND, 5)
mainSizer.Add(contentSizer, 1, wx.EXPAND, 0)
if "wxGTK" in wx.PlatformInfo:
self.closeBtn = wx.Button( self, wx.ID_ANY, u"Close", wx.DefaultPosition, wx.DefaultSize, 0 )
mainSizer.Add( self.closeBtn, 0, wx.ALL|wx.ALIGN_RIGHT, 5 )
self.closeBtn.Bind(wx.EVT_BUTTON, self.closeEvent)
self.SetSizer(mainSizer)
importExport = (("Import", wx.ART_FILE_OPEN, "from"),
("Export", wx.ART_FILE_SAVE_AS, "to"))
for name, art, direction in importExport:
bitmap = wx.ArtProvider.GetBitmap(art, wx.ART_BUTTON)
btn = wx.BitmapButton(self, wx.ID_ANY, bitmap)
btn.SetMinSize( btn.GetSize() )
btn.SetMaxSize( btn.GetSize() )
btn.Layout()
setattr(self, name, btn)
btn.Enable(True)
btn.SetToolTipString("%s patterns %s clipboard" % (name, direction) )
footerSizer.Add(btn, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_RIGHT)
self.Layout()
bsize = self.GetBestSize()
self.SetSize((-1,bsize.height))
self.new.Bind(wx.EVT_BUTTON, self.newPattern)
self.rename.Bind(wx.EVT_BUTTON, self.renamePattern)
self.copy.Bind(wx.EVT_BUTTON, self.copyPattern)
self.delete.Bind(wx.EVT_BUTTON, self.deletePattern)
self.Import.Bind(wx.EVT_BUTTON, self.importPatterns)
self.Export.Bind(wx.EVT_BUTTON, self.exportPatterns)
self.patternChanged()
def closeEvent(self, event):
self.Destroy()
def ValuesUpdated(self, event=None):
'''
Event that is fired when resists values change. Iterates through all
resist edit fields. If blank, sets it to 0.0. If it is not a proper
decimal value, sets text color to red and refuses to save changes until
issue is resolved
'''
if self.block:
return
try:
p = self.getActivePattern()
for type in self.DAMAGE_TYPES:
editObj = getattr(self, "%sEdit"%type)
if editObj.GetValue() == "":
# if we are blank, overwrite with 0
editObj.ChangeValue("0.0")
editObj.SetInsertionPointEnd()
value = float(editObj.GetValue())
# assertion, because they're easy
assert 0 <= value <= 100
# if everything checks out, set resist attribute
setattr(p, "%sAmount"%type, value/100)
self.totSizer.Layout()
if event is not None:
# If we get here, everything is normal. Reset color
event.EventObject.SetForegroundColour(wx.NullColor)
event.Skip()
service.TargetResists.getInstance().saveChanges(p)
except ValueError:
event.EventObject.SetForegroundColour(wx.RED)
self.stNotice.SetLabel("Incorrect Formatting (decimals only)")
except AssertionError:
event.EventObject.SetForegroundColour(wx.RED)
self.stNotice.SetLabel("Incorrect Range (must be 0-100)")
finally: # Refresh for color changes to take effect immediately
self.Refresh()
def restrict(self):
for type in self.DAMAGE_TYPES:
editObj = getattr(self, "%sEdit"%type)
editObj.Enable(False)
self.rename.Enable(False)
self.delete.Enable(False)
def unrestrict(self):
for type in self.DAMAGE_TYPES:
editObj = getattr(self, "%sEdit"%type)
editObj.Enable()
self.rename.Enable()
self.delete.Enable()
def getActivePattern(self):
if len(self.choices) == 0:
return None
return self.choices[self.ccResists.GetSelection()]
def patternChanged(self, event=None):
"Event fired when user selects pattern. Can also be called from script"
p = self.getActivePattern()
if p is None:
# This happens when there are no patterns in the DB. As such, force
# user to create one first or exit dlg.
self.newPattern(None)
return
self.block = True
# Set new values
for field in self.DAMAGE_TYPES:
edit = getattr(self, "%sEdit" % field)
amount = getattr(p, "%sAmount" % field)*100
edit.ChangeValue(str(amount))
self.block = False
self.ValuesUpdated()
def newPattern(self, event):
'''
Simply does new-pattern specifics: replaces label on button, restricts,
and resets values to default. Hands off to the rename function for
further handling.
'''
self.btnSave.SetLabel("Create")
self.restrict()
# reset values
for type in self.DAMAGE_TYPES:
editObj = getattr(self, "%sEdit"%type)
editObj.ChangeValue("0.0")
editObj.SetForegroundColour(wx.NullColor)
self.Refresh()
self.renamePattern()
def renamePattern(self, event=None):
"Changes layout to facilitate naming a pattern"
self.ccResists.Hide()
self.namePicker.Show()
self.headerSizer.Replace(self.ccResists, self.namePicker)
self.namePicker.SetFocus()
if event is not None: # Rename mode
self.btnSave.SetLabel("Rename")
self.namePicker.SetValue(self.getActivePattern().name)
else: # Create mode
self.namePicker.SetValue("")
for btn in (self.new, self.rename, self.delete, self.copy):
btn.Hide()
self.headerSizer.Remove(btn)
self.headerSizer.Add(self.btnSave, 0, wx.ALIGN_CENTER)
self.btnSave.Show()
self.headerSizer.Layout()
if event is not None:
event.Skip()
def processRename(self, event):
'''
Processes rename event (which can be new or old patterns). If new
pattern, creates it; if old, selects it. if checks are valid, rename
saves pattern to DB.
Also resets to default layout and unrestricts.
'''
newName = self.namePicker.GetLineText(0)
self.stNotice.SetLabel("")
if newName == "":
self.stNotice.SetLabel("Invalid name")
return
sTR = service.TargetResists.getInstance()
if event.EventObject.Label == "Create":
p = sTR.newPattern()
else:
# we are renaming, so get the current selection
p = self.getActivePattern()
# test for patterns of the same name
for pattern in self.choices:
if pattern.name == newName and p != pattern:
self.stNotice.SetLabel("Name already used, please choose another")
return
# rename regardless of new or rename
sTR.renamePattern(p, newName)
self.updateChoices(newName)
self.headerSizer.Replace(self.namePicker, self.ccResists)
self.ccResists.Show()
self.namePicker.Hide()
self.btnSave.Hide()
self.headerSizer.Remove(self.btnSave)
for btn in (self.new, self.rename, self.delete, self.copy):
self.headerSizer.Add(btn, 0, wx.ALIGN_CENTER_VERTICAL)
btn.Show()
sel = self.ccResists.GetSelection()
self.ValuesUpdated()
self.unrestrict()
def copyPattern(self,event):
sTR = service.TargetResists.getInstance()
p = sTR.copyPattern(self.getActivePattern())
self.choices.append(p)
id = self.ccResists.Append(p.name)
self.ccResists.SetSelection(id)
self.btnSave.SetLabel("Copy")
self.renamePattern()
self.patternChanged()
def deletePattern(self,event):
sTR = service.TargetResists.getInstance()
sel = self.ccResists.GetSelection()
sTR.deletePattern(self.getActivePattern())
self.ccResists.Delete(sel)
self.ccResists.SetSelection(max(0, sel - 1))
del self.choices[sel]
self.patternChanged()
def __del__( self ):
pass
def updateChoices(self, select=None):
"Gathers list of patterns and updates choice selections"
sTR = service.TargetResists.getInstance()
self.choices = sTR.getTargetResistsList()
# Sort the remaining list and continue on
self.choices.sort(key=lambda p: p.name)
self.ccResists.Clear()
for i, choice in enumerate(map(lambda p: p.name, self.choices)):
self.ccResists.Append(choice)
if select is not None and choice == select:
self.ccResists.SetSelection(i)
if select is None:
self.ccResists.SetSelection(0)
self.patternChanged()
def importPatterns(self, event):
"Event fired when import from clipboard button is clicked"
text = fromClipboard()
if text:
sTR = service.TargetResists.getInstance()
try:
sTR.importPatterns(text)
self.stNotice.SetLabel("Patterns successfully imported from clipboard")
except service.targetResists.ImportError, e:
self.stNotice.SetLabel(str(e))
except Exception, e:
self.stNotice.SetLabel("Could not import from clipboard: unknown errors")
finally:
self.updateChoices()
else:
self.stNotice.SetLabel("Could not import from clipboard")
def exportPatterns(self, event):
"Event fired when export to clipboard button is clicked"
sTR = service.TargetResists.getInstance()
toClipboard( sTR.exportPatterns() )
self.stNotice.SetLabel("Patterns exported to clipboard")