Merge branch 'master' into charImplants
# Conflicts: # gui/characterEditor.py
This commit is contained in:
@@ -25,8 +25,16 @@ licenses = (
|
||||
"Silk Icons Set by famfamfam.com - Creative Commons Attribution 2.5 License",
|
||||
"Fat Cow Icons by fatcow.com - Creative Commons Attribution 3.0 License"
|
||||
)
|
||||
developers = ("blitzmann \t(Sable Blitzmann)", "cncfanatics \t(Sakari Orisi) (founder)" , "DarkPhoenix \t(Kadesh Priestess) (project lead)", "Darriele \t(Darriele)")
|
||||
credits = ("Entity (Entity) \t\tCapacitor calculations / EVEAPI python lib / Reverence", "Aurora \t\t\tMaths", "Corollax (Aamrr) \tVarious EOS / pyfa improvements")
|
||||
developers = (
|
||||
"blitzmann \t(Sable Blitzmann) (maintainer)",
|
||||
"cncfanatics \t(Sakari Orisi)" ,
|
||||
"DarkPhoenix \t(Kadesh Priestess)",
|
||||
"Darriele \t\t(Darriele)")
|
||||
credits = (
|
||||
"Entity (Entity) \tCapacitor calculations / EVEAPI python lib / Reverence",
|
||||
"Aurora \t\tMaths",
|
||||
"Corollax (Aamrr) \tVarious EOS / pyfa improvements",
|
||||
"Dreae (Dreae)\tPyCrest")
|
||||
description = (
|
||||
"Pyfa (the Python Fitting Assistant) is an open-source standalone application able to "
|
||||
"create and simulate fittings for EVE-Online SciFi MMORPG with a very high degree of "
|
||||
|
||||
@@ -7,6 +7,8 @@ import gui.mainFrame
|
||||
import service
|
||||
from service.crest import CrestModes
|
||||
|
||||
from wx.lib.intctrl import IntCtrl
|
||||
|
||||
class PFCrestPref ( PreferenceView):
|
||||
title = "CREST"
|
||||
|
||||
@@ -46,6 +48,19 @@ class PFCrestPref ( PreferenceView):
|
||||
|
||||
mainSizer.Add(rbSizer, 1, wx.ALL|wx.EXPAND, 0)
|
||||
|
||||
timeoutSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
self.stTimout = wx.StaticText( panel, wx.ID_ANY, u"Timeout (seconds):", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.stTimout.Wrap( -1 )
|
||||
|
||||
timeoutSizer.Add( self.stTimout, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5 )
|
||||
|
||||
self.intTimeout = IntCtrl(panel, max=300000, limited=True, value=self.settings.get('timeout'))
|
||||
timeoutSizer.Add(self.intTimeout, 0, wx.ALL, 5 )
|
||||
self.intTimeout.Bind(wx.lib.intctrl.EVT_INT, self.OnTimeoutChange)
|
||||
|
||||
mainSizer.Add(timeoutSizer, 0, wx.ALL|wx.EXPAND, 0)
|
||||
|
||||
detailsTitle = wx.StaticText( panel, wx.ID_ANY, "CREST client details", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
detailsTitle.Wrap( -1 )
|
||||
detailsTitle.SetFont( wx.Font( 12, 70, 90, 90, False, wx.EmptyString ) )
|
||||
@@ -53,7 +68,6 @@ class PFCrestPref ( PreferenceView):
|
||||
mainSizer.Add( detailsTitle, 0, wx.ALL, 5 )
|
||||
mainSizer.Add( wx.StaticLine( panel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL ), 0, wx.EXPAND, 5 )
|
||||
|
||||
|
||||
fgAddrSizer = wx.FlexGridSizer( 2, 2, 0, 0 )
|
||||
fgAddrSizer.AddGrowableCol( 1 )
|
||||
fgAddrSizer.SetFlexibleDirection( wx.BOTH )
|
||||
@@ -87,6 +101,9 @@ class PFCrestPref ( PreferenceView):
|
||||
panel.SetSizer( mainSizer )
|
||||
panel.Layout()
|
||||
|
||||
def OnTimeoutChange(self, event):
|
||||
self.settings.set('timeout', event.GetEventObject().GetValue())
|
||||
|
||||
def OnModeChange(self, event):
|
||||
self.settings.set('mode', event.GetInt())
|
||||
self.ToggleProxySettings(self.settings.get('mode'))
|
||||
@@ -97,8 +114,8 @@ class PFCrestPref ( PreferenceView):
|
||||
service.Crest.restartService()
|
||||
|
||||
def OnBtnApply(self, event):
|
||||
self.settings.set('clientID', self.inputClientID.GetValue())
|
||||
self.settings.set('clientSecret', self.inputClientSecret.GetValue())
|
||||
self.settings.set('clientID', self.inputClientID.GetValue().strip())
|
||||
self.settings.set('clientSecret', self.inputClientSecret.GetValue().strip())
|
||||
sCrest = service.Crest.getInstance()
|
||||
sCrest.delAllCharacters()
|
||||
|
||||
|
||||
@@ -59,6 +59,12 @@ class PFGeneralPref ( PreferenceView):
|
||||
self.cbMarketShortcuts = wx.CheckBox( panel, wx.ID_ANY, u"Show market shortcuts", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
mainSizer.Add( self.cbMarketShortcuts, 0, wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
self.cbGaugeAnimation = wx.CheckBox( panel, wx.ID_ANY, u"Animate gauges", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
mainSizer.Add( self.cbGaugeAnimation, 0, wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
self.cbExportCharges = wx.CheckBox( panel, wx.ID_ANY, u"Export loaded charges", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
mainSizer.Add( self.cbExportCharges, 0, wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
defCharSizer = wx.BoxSizer( wx.HORIZONTAL )
|
||||
|
||||
self.sFit = service.Fit.getInstance()
|
||||
@@ -73,6 +79,8 @@ class PFGeneralPref ( PreferenceView):
|
||||
self.cbReopenFits.SetValue(self.openFitsSettings["enabled"])
|
||||
self.cbShowTooltip.SetValue(self.sFit.serviceFittingOptions["showTooltip"] or False)
|
||||
self.cbMarketShortcuts.SetValue(self.sFit.serviceFittingOptions["showMarketShortcuts"] or False)
|
||||
self.cbGaugeAnimation.SetValue(self.sFit.serviceFittingOptions["enableGaugeAnimation"])
|
||||
self.cbExportCharges.SetValue(self.sFit.serviceFittingOptions["exportCharges"])
|
||||
|
||||
self.cbGlobalChar.Bind(wx.EVT_CHECKBOX, self.OnCBGlobalCharStateChange)
|
||||
self.cbGlobalDmgPattern.Bind(wx.EVT_CHECKBOX, self.OnCBGlobalDmgPatternStateChange)
|
||||
@@ -84,6 +92,8 @@ class PFGeneralPref ( PreferenceView):
|
||||
self.cbReopenFits.Bind(wx.EVT_CHECKBOX, self.onCBReopenFits)
|
||||
self.cbShowTooltip.Bind(wx.EVT_CHECKBOX, self.onCBShowTooltip)
|
||||
self.cbMarketShortcuts.Bind(wx.EVT_CHECKBOX, self.onCBShowShortcuts)
|
||||
self.cbGaugeAnimation.Bind(wx.EVT_CHECKBOX, self.onCBGaugeAnimation)
|
||||
self.cbExportCharges.Bind(wx.EVT_CHECKBOX, self.onCBExportCharges)
|
||||
|
||||
self.cbRackLabels.Enable(self.sFit.serviceFittingOptions["rackSlots"] or False)
|
||||
|
||||
@@ -143,6 +153,12 @@ class PFGeneralPref ( PreferenceView):
|
||||
def onCBShowShortcuts(self, event):
|
||||
self.sFit.serviceFittingOptions["showMarketShortcuts"] = self.cbMarketShortcuts.GetValue()
|
||||
|
||||
def onCBGaugeAnimation(self, event):
|
||||
self.sFit.serviceFittingOptions["enableGaugeAnimation"] = self.cbGaugeAnimation.GetValue()
|
||||
|
||||
def onCBExportCharges(self, event):
|
||||
self.sFit.serviceFittingOptions["exportCharges"] = self.cbExportCharges.GetValue()
|
||||
|
||||
def getImage(self):
|
||||
return BitmapLoader.getBitmap("prefs_settings", "gui")
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ class PFUpdatePref (PreferenceView):
|
||||
self.resetButton.Hide()
|
||||
|
||||
def OnDownload(self, event):
|
||||
wx.LaunchDefaultBrowser('https://github.com/DarkFenX/Pyfa/releases/tag/'+self.UpdateSettings.get('version'))
|
||||
wx.LaunchDefaultBrowser('https://github.com/pyfa-org/Pyfa/releases/tag/'+self.UpdateSettings.get('version'))
|
||||
|
||||
def getImage(self):
|
||||
return BitmapLoader.getBitmap("prefs_update", "gui")
|
||||
|
||||
@@ -23,7 +23,6 @@ from gui import builtinStatsViews
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
from gui.utils.numberFormatter import formatAmount
|
||||
import service
|
||||
import locale
|
||||
|
||||
class PriceViewFull(StatsView):
|
||||
name = "priceViewFull"
|
||||
@@ -107,15 +106,15 @@ class PriceViewFull(StatsView):
|
||||
|
||||
if self._cachedShip != shipPrice:
|
||||
self.labelPriceShip.SetLabel("%s ISK" % formatAmount(shipPrice, 3, 3, 9, currency=True))
|
||||
self.labelPriceShip.SetToolTip(wx.ToolTip(locale.format('%.2f', shipPrice, 1)))
|
||||
self.labelPriceShip.SetToolTip(wx.ToolTip('{:,.2f}'.format(shipPrice)))
|
||||
self._cachedShip = shipPrice
|
||||
if self._cachedFittings != modPrice:
|
||||
self.labelPriceFittings.SetLabel("%s ISK" % formatAmount(modPrice, 3, 3, 9, currency=True))
|
||||
self.labelPriceFittings.SetToolTip(wx.ToolTip(locale.format('%.2f', modPrice, 1)))
|
||||
self.labelPriceFittings.SetToolTip(wx.ToolTip('{:,.2f}'.format(modPrice)))
|
||||
self._cachedFittings = modPrice
|
||||
if self._cachedTotal != (shipPrice+modPrice):
|
||||
self.labelPriceTotal.SetLabel("%s ISK" % formatAmount(shipPrice + modPrice, 3, 3, 9, currency=True))
|
||||
self.labelPriceTotal.SetToolTip(wx.ToolTip(locale.format('%.2f', (shipPrice + modPrice), 1)))
|
||||
self.labelPriceTotal.SetToolTip(wx.ToolTip('{:,.2f}'.format(shipPrice + modPrice)))
|
||||
self._cachedTotal = shipPrice + modPrice
|
||||
self.panel.Layout()
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ from gui.statsView import StatsView
|
||||
from gui import builtinStatsViews
|
||||
from gui.utils.numberFormatter import formatAmount
|
||||
import locale
|
||||
|
||||
try:
|
||||
from collections import OrderedDict
|
||||
except ImportError:
|
||||
@@ -153,7 +152,7 @@ class TargetingMiscViewFull(StatsView):
|
||||
("labelFullAlignTime", {"main": lambda: fit.alignTime}, 3, 0, 0, "s"),
|
||||
("labelFullSigRadius", {"main": lambda: fit.ship.getModifiedItemAttr("signatureRadius")}, 3, 0, 9, ""),
|
||||
("labelFullWarpSpeed", {"main": lambda: fit.warpSpeed}, 3, 0, 0, "AU/s"),
|
||||
("labelFullCargo", cargoValues, 3, 0, 9, u"m\u00B3"))
|
||||
("labelFullCargo", cargoValues, 4, 0, 9, u"m\u00B3"))
|
||||
|
||||
counter = 0
|
||||
RADII = [("Pod",25), ("Interceptor",33), ("Frigate",38),
|
||||
@@ -201,15 +200,15 @@ class TargetingMiscViewFull(StatsView):
|
||||
label.SetToolTip(wx.ToolTip("Type: %s" % (fit.scanType)))
|
||||
elif labelName == "labelFullAlignTime":
|
||||
alignTime = "Align:\t%.3fs"%mainValue
|
||||
mass = "Mass:\t%skg"%locale.format('%d', fit.ship.getModifiedItemAttr("mass"), 1)
|
||||
mass = 'Mass:\t{:,.0f}kg'.format(fit.ship.getModifiedItemAttr("mass"))
|
||||
agility = "Agility:\t%.3fx"%fit.ship.getModifiedItemAttr("agility")
|
||||
label.SetToolTip(wx.ToolTip("%s\n%s\n%s" % (alignTime, mass, agility)))
|
||||
elif labelName == "labelFullCargo":
|
||||
tipLines = []
|
||||
tipLines.append(u"Cargohold: %.1fm\u00B3 / %sm\u00B3"% (fit.cargoBayUsed, newValues["main"]))
|
||||
tipLines.append(u"Cargohold: {:,.2f}m\u00B3 / {:,.2f}m\u00B3".format(fit.cargoBayUsed, newValues["main"]))
|
||||
for attrName, tipAlias in cargoNamesOrder.items():
|
||||
if newValues[attrName] > 0:
|
||||
tipLines.append(u"%s: %sm\u00B3"% (tipAlias, newValues[attrName]))
|
||||
tipLines.append(u"{}: {:,.2f}m\u00B3".format(tipAlias, newValues[attrName]))
|
||||
label.SetToolTip(wx.ToolTip(u"\n".join(tipLines)))
|
||||
else:
|
||||
label.SetToolTip(wx.ToolTip("%.1f" % mainValue))
|
||||
@@ -235,10 +234,10 @@ class TargetingMiscViewFull(StatsView):
|
||||
# if you add stuff to cargo, the capacity doesn't change and thus it is still cached
|
||||
# This assures us that we force refresh of cargo tooltip
|
||||
tipLines = []
|
||||
tipLines.append(u"Cargohold: %.1fm\u00B3 / %sm\u00B3"% (fit.cargoBayUsed, cachedCargo["main"]))
|
||||
tipLines.append(u"Cargohold: {:,.2f}m\u00B3 / {:,.2f}m\u00B3".format(fit.cargoBayUsed, cachedCargo["main"]))
|
||||
for attrName, tipAlias in cargoNamesOrder.items():
|
||||
if cachedCargo[attrName] > 0:
|
||||
tipLines.append(u"%s: %sm\u00B3"% (tipAlias, cachedCargo[attrName]))
|
||||
tipLines.append(u"{}: {:,.2f}m\u00B3".format(tipAlias, cachedCargo[attrName]))
|
||||
label.SetToolTip(wx.ToolTip(u"\n".join(tipLines)))
|
||||
else:
|
||||
label.SetToolTip(wx.ToolTip(""))
|
||||
|
||||
@@ -42,7 +42,7 @@ class AmmoIcon(ViewColumn):
|
||||
if stuff.charge is None:
|
||||
return -1
|
||||
else:
|
||||
iconFile = stuff.charge.icon.iconFile if stuff.item.icon else ""
|
||||
iconFile = stuff.charge.icon.iconFile if stuff.charge.icon else ""
|
||||
if iconFile:
|
||||
return self.fittingView.imageList.GetImageIndex(iconFile, "icons")
|
||||
else:
|
||||
|
||||
@@ -85,7 +85,7 @@ class Miscellanea(ViewColumn):
|
||||
if n > 0:
|
||||
info.append("{0}{1}".format(n, slot[0].upper()))
|
||||
return "+ "+", ".join(info), "Slot Modifiers"
|
||||
elif itemGroup == "Energy Destabilizer":
|
||||
elif itemGroup == "Energy Neutralizer":
|
||||
neutAmount = stuff.getModifiedItemAttr("energyDestabilizationAmount")
|
||||
cycleTime = stuff.cycleTime
|
||||
if not neutAmount or not cycleTime:
|
||||
@@ -94,7 +94,7 @@ class Miscellanea(ViewColumn):
|
||||
text = "{0}/s".format(formatAmount(capPerSec, 3, 0, 3))
|
||||
tooltip = "Energy neutralization per second"
|
||||
return text, tooltip
|
||||
elif itemGroup == "Energy Vampire":
|
||||
elif itemGroup == "Energy Nosferatu":
|
||||
neutAmount = stuff.getModifiedItemAttr("powerTransferAmount")
|
||||
cycleTime = stuff.cycleTime
|
||||
if not neutAmount or not cycleTime:
|
||||
@@ -139,7 +139,7 @@ class Miscellanea(ViewColumn):
|
||||
text = "{0}%".format(formatAmount(sigRadBonus, 3, 0, 3, forceSign=True))
|
||||
tooltip = "Signature radius increase"
|
||||
return text, tooltip
|
||||
elif itemGroup == "Remote Sensor Damper":
|
||||
elif itemGroup == "Sensor Dampener":
|
||||
lockRangeBonus = stuff.getModifiedItemAttr("maxTargetRangeBonus")
|
||||
scanResBonus = stuff.getModifiedItemAttr("scanResolutionBonus")
|
||||
if lockRangeBonus is None or scanResBonus is None:
|
||||
@@ -158,29 +158,54 @@ class Miscellanea(ViewColumn):
|
||||
ttEntries.append("scan resolution")
|
||||
tooltip = "{0} dampening".format(formatList(ttEntries)).capitalize()
|
||||
return text, tooltip
|
||||
elif itemGroup == "Tracking Disruptor":
|
||||
elif itemGroup == "Weapon Disruptor":
|
||||
# Weapon disruption now covers both tracking and guidance (missile) disruptors
|
||||
# First get the attributes for tracking disruptors
|
||||
optimalRangeBonus = stuff.getModifiedItemAttr("maxRangeBonus")
|
||||
falloffRangeBonus = stuff.getModifiedItemAttr("falloffBonus")
|
||||
trackingSpeedBonus = stuff.getModifiedItemAttr("trackingSpeedBonus")
|
||||
if optimalRangeBonus is None or falloffRangeBonus is None or trackingSpeedBonus is None:
|
||||
return "", None
|
||||
display = 0
|
||||
for bonus in (optimalRangeBonus, falloffRangeBonus, trackingSpeedBonus):
|
||||
if abs(bonus) > abs(display):
|
||||
display = bonus
|
||||
if not display:
|
||||
|
||||
trackingDisruptorAttributes = {
|
||||
"optimal range": optimalRangeBonus,
|
||||
"falloff range": falloffRangeBonus,
|
||||
"tracking speed": trackingSpeedBonus}
|
||||
|
||||
isTrackingDisruptor = any(map(lambda x: x is not None and x != 0, trackingDisruptorAttributes.values()))
|
||||
|
||||
# Then get the attributes for guidance disruptors
|
||||
explosionVelocityBonus = stuff.getModifiedItemAttr("aoeVelocityBonus")
|
||||
explosionRadiusBonus = stuff.getModifiedItemAttr("aoeCloudSizeBonus")
|
||||
|
||||
flightTimeBonus = stuff.getModifiedItemAttr("explosionDelayBonus")
|
||||
missileVelocityBonus = stuff.getModifiedItemAttr("missileVelocityBonus")
|
||||
|
||||
guidanceDisruptorAttributes = {
|
||||
"explosion velocity": explosionVelocityBonus,
|
||||
"explosion radius": explosionRadiusBonus,
|
||||
"flight time": flightTimeBonus,
|
||||
"missile velocity": missileVelocityBonus}
|
||||
|
||||
isGuidanceDisruptor = any(map(lambda x: x is not None and x != 0, guidanceDisruptorAttributes.values()))
|
||||
|
||||
if isTrackingDisruptor:
|
||||
attributes = trackingDisruptorAttributes
|
||||
elif isGuidanceDisruptor:
|
||||
attributes = guidanceDisruptorAttributes
|
||||
else:
|
||||
return "", None
|
||||
|
||||
display = max(attributes.values(), key=lambda x: abs(x))
|
||||
|
||||
text = "{0}%".format(formatAmount(display, 3, 0, 3, forceSign=True))
|
||||
|
||||
ttEntries = []
|
||||
if display == optimalRangeBonus:
|
||||
ttEntries.append("optimal range")
|
||||
if display == falloffRangeBonus:
|
||||
ttEntries.append("falloff range")
|
||||
if display == trackingSpeedBonus:
|
||||
ttEntries.append("tracking speed")
|
||||
for attributeName, attributeValue in attributes.items():
|
||||
if attributeValue == display:
|
||||
ttEntries.append(attributeName)
|
||||
|
||||
tooltip = "{0} disruption".format(formatList(ttEntries)).capitalize()
|
||||
return text, tooltip
|
||||
elif itemGroup in ("ECM", "ECM Burst", "Remote ECM Burst"):
|
||||
elif itemGroup in ("ECM", "Burst Jammer", "Remote ECM Burst"):
|
||||
grav = stuff.getModifiedItemAttr("scanGravimetricStrengthBonus")
|
||||
ladar = stuff.getModifiedItemAttr("scanLadarStrengthBonus")
|
||||
radar = stuff.getModifiedItemAttr("scanRadarStrengthBonus")
|
||||
@@ -401,7 +426,7 @@ class Miscellanea(ViewColumn):
|
||||
ttEntries.append("shield")
|
||||
tooltip = "{0} repaired per second".format(formatList(ttEntries)).capitalize()
|
||||
return text, tooltip
|
||||
elif itemGroup == "Cap Drain Drone":
|
||||
elif itemGroup == "Energy Neutralizer Drone":
|
||||
neutAmount = stuff.getModifiedItemAttr("energyDestabilizationAmount")
|
||||
cycleTime = stuff.getModifiedItemAttr("duration")
|
||||
if not neutAmount or not cycleTime:
|
||||
@@ -462,7 +487,7 @@ class Miscellanea(ViewColumn):
|
||||
if chargeGroup in ("Rocket", "Advanced Rocket", "Light Missile", "Advanced Light Missile", "FoF Light Missile",
|
||||
"Heavy Assault Missile", "Advanced Heavy Assault Missile", "Heavy Missile", "Advanced Heavy Missile", "FoF Heavy Missile",
|
||||
"Torpedo", "Advanced Torpedo", "Cruise Missile", "Advanced Cruise Missile", "FoF Cruise Missile",
|
||||
"Citadel Torpedo", "Citadel Cruise"):
|
||||
"Capital Torpedo", "Capital Cruise"):
|
||||
cloudSize = stuff.getModifiedChargeAttr("aoeCloudSize")
|
||||
aoeVelocity = stuff.getModifiedChargeAttr("aoeVelocity")
|
||||
if not cloudSize or not aoeVelocity:
|
||||
|
||||
@@ -526,7 +526,8 @@ class FittingView(d.Display):
|
||||
|
||||
# update state tooltip
|
||||
tooltip = self.activeColumns[col].getToolTip(self.mods[self.GetItemData(row)])
|
||||
self.SetToolTipString(tooltip)
|
||||
if tooltip:
|
||||
self.SetToolTipString(tooltip)
|
||||
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit()))
|
||||
else:
|
||||
|
||||
@@ -32,15 +32,14 @@ import gui.globalEvents as GE
|
||||
class CharacterEditor(wx.Frame):
|
||||
def __init__(self, parent):
|
||||
wx.Frame.__init__ (self, parent, id=wx.ID_ANY, title=u"pyfa: Character Editor", pos=wx.DefaultPosition,
|
||||
size=wx.Size(641, 600), style=wx.DEFAULT_FRAME_STYLE|wx.FRAME_FLOAT_ON_PARENT|wx.TAB_TRAVERSAL)
|
||||
size=wx.Size(640, 600), style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)
|
||||
|
||||
i = wx.IconFromBitmap(BitmapLoader.getBitmap("character_small", "gui"))
|
||||
self.SetIcon(i)
|
||||
|
||||
self.mainFrame = parent
|
||||
#self.disableWin = wx.WindowDisabler(self)
|
||||
|
||||
self.disableWin= wx.WindowDisabler(self)
|
||||
self.SetSizeHintsSz(wx.Size(640, 600), wx.DefaultSize)
|
||||
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
|
||||
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
@@ -170,7 +169,7 @@ class CharacterEditor(wx.Frame):
|
||||
self.btnRestrict()
|
||||
|
||||
def editingFinished(self, event):
|
||||
del self.disableWin
|
||||
#del self.disableWin
|
||||
wx.PostEvent(self.mainFrame, GE.CharListUpdated())
|
||||
self.Destroy()
|
||||
|
||||
@@ -200,7 +199,7 @@ class CharacterEditor(wx.Frame):
|
||||
wx.PostEvent(self, GE.CharListUpdated())
|
||||
|
||||
def closeEvent(self, event):
|
||||
del self.disableWin
|
||||
#del self.disableWin
|
||||
wx.PostEvent(self.mainFrame, GE.CharListUpdated())
|
||||
self.Destroy()
|
||||
|
||||
@@ -821,4 +820,4 @@ class SaveCharacterAs(wx.Dialog):
|
||||
|
||||
event.Skip()
|
||||
self.Close()
|
||||
|
||||
|
||||
804
gui/characterEditor.py.BASE
Normal file
804
gui/characterEditor.py.BASE
Normal file
@@ -0,0 +1,804 @@
|
||||
#===============================================================================
|
||||
# Copyright (C) 2010 Diego Duclos
|
||||
#
|
||||
# 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 gui.mainFrame
|
||||
import wx.lib.newevent
|
||||
import wx.gizmos
|
||||
from gui.bitmapLoader import BitmapLoader
|
||||
import service
|
||||
import gui.display as d
|
||||
from gui.contextMenu import ContextMenu
|
||||
from wx.lib.buttons import GenBitmapButton
|
||||
import gui.globalEvents as GE
|
||||
|
||||
class CharacterEditor(wx.Frame):
|
||||
def __init__(self, parent):
|
||||
wx.Frame.__init__ (self, parent, id=wx.ID_ANY, title=u"pyfa: Character Editor", pos=wx.DefaultPosition,
|
||||
size=wx.Size(641, 600), style=wx.DEFAULT_FRAME_STYLE|wx.FRAME_FLOAT_ON_PARENT|wx.TAB_TRAVERSAL)
|
||||
|
||||
i = wx.IconFromBitmap(BitmapLoader.getBitmap("character_small", "gui"))
|
||||
self.SetIcon(i)
|
||||
|
||||
self.mainFrame = parent
|
||||
|
||||
self.disableWin= wx.WindowDisabler(self)
|
||||
self.SetSizeHintsSz(wx.Size(640, 600), wx.DefaultSize)
|
||||
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
|
||||
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
self.navSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
sChar = service.Character.getInstance()
|
||||
|
||||
self.btnSave = wx.Button(self, wx.ID_SAVE)
|
||||
self.btnSave.Hide()
|
||||
self.btnSave.Bind(wx.EVT_BUTTON, self.processRename)
|
||||
|
||||
self.characterRename = wx.TextCtrl(self, wx.ID_ANY, style=wx.TE_PROCESS_ENTER)
|
||||
self.characterRename.Hide()
|
||||
self.characterRename.Bind(wx.EVT_TEXT_ENTER, self.processRename)
|
||||
|
||||
self.charChoice = wx.Choice(self, wx.ID_ANY, style=0)
|
||||
self.navSizer.Add(self.charChoice, 1, wx.ALL | wx.EXPAND, 5)
|
||||
|
||||
charList = sChar.getCharacterList()
|
||||
|
||||
for id, name, active in charList:
|
||||
i = self.charChoice.Append(name, id)
|
||||
if active:
|
||||
self.charChoice.SetSelection(i)
|
||||
|
||||
self.navSizer.Add(self.btnSave, 0, wx.ALL , 5)
|
||||
|
||||
|
||||
buttons = (("new", wx.ART_NEW),
|
||||
("rename", BitmapLoader.getBitmap("rename", "gui")),
|
||||
("copy", wx.ART_COPY),
|
||||
("delete", wx.ART_DELETE))
|
||||
|
||||
size = None
|
||||
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.SetToolTipString("%s character" % name.capitalize())
|
||||
btn.Bind(wx.EVT_BUTTON, getattr(self, name))
|
||||
setattr(self, "btn%s" % name.capitalize(), btn)
|
||||
self.navSizer.Add(btn, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 2)
|
||||
|
||||
|
||||
mainSizer.Add(self.navSizer, 0, wx.ALL | wx.EXPAND, 5)
|
||||
|
||||
self.viewsNBContainer = wx.Notebook(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
|
||||
self.sview = SkillTreeView(self.viewsNBContainer)
|
||||
#self.iview = ImplantsTreeView(self.viewsNBContainer)
|
||||
#=======================================================================
|
||||
# RC2
|
||||
#self.iview.Show(False)
|
||||
#=======================================================================
|
||||
self.aview = APIView(self.viewsNBContainer)
|
||||
|
||||
self.viewsNBContainer.AddPage(self.sview, "Skills")
|
||||
|
||||
#=======================================================================
|
||||
# Disabled for RC2
|
||||
# self.viewsNBContainer.AddPage(self.iview, "Implants")
|
||||
#=======================================================================
|
||||
self.viewsNBContainer.AddPage(self.aview, "API")
|
||||
|
||||
mainSizer.Add(self.viewsNBContainer, 1, wx.EXPAND | wx.ALL, 5)
|
||||
|
||||
bSizerButtons = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
self.btnSaveChar = wx.Button(self, wx.ID_ANY, "Save")
|
||||
self.btnSaveAs = wx.Button(self, wx.ID_ANY, "Save As...")
|
||||
self.btnRevert = wx.Button(self, wx.ID_ANY, "Revert")
|
||||
self.btnOK = wx.Button(self, wx.ID_OK)
|
||||
|
||||
bSizerButtons.Add(self.btnSaveChar, 0, wx.ALL, 5)
|
||||
bSizerButtons.Add(self.btnSaveAs, 0, wx.ALL, 5)
|
||||
bSizerButtons.Add(self.btnRevert, 0, wx.ALL, 5)
|
||||
bSizerButtons.AddStretchSpacer()
|
||||
bSizerButtons.Add(self.btnOK, 0, wx.ALL, 5)
|
||||
|
||||
|
||||
self.btnSaveChar.Bind(wx.EVT_BUTTON, self.saveChar)
|
||||
self.btnSaveAs.Bind(wx.EVT_BUTTON, self.saveCharAs)
|
||||
self.btnRevert.Bind(wx.EVT_BUTTON, self.revertChar)
|
||||
self.btnOK.Bind(wx.EVT_BUTTON, self.editingFinished)
|
||||
|
||||
mainSizer.Add(bSizerButtons, 0, wx.EXPAND, 5)
|
||||
|
||||
self.btnRestrict()
|
||||
|
||||
self.SetSizer(mainSizer)
|
||||
self.Layout()
|
||||
|
||||
self.Centre(wx.BOTH)
|
||||
|
||||
charID = self.getActiveCharacter()
|
||||
if sChar.getCharName(charID) in ("All 0", "All 5"):
|
||||
self.restrict()
|
||||
|
||||
self.registerEvents()
|
||||
|
||||
def btnRestrict(self):
|
||||
sChar = service.Character.getInstance()
|
||||
charID = self.getActiveCharacter()
|
||||
char = sChar.getCharacter(charID)
|
||||
|
||||
# enable/disable character saving stuff
|
||||
self.btnSaveChar.Enable(not char.ro and char.isDirty)
|
||||
self.btnSaveAs.Enable(char.isDirty)
|
||||
self.btnRevert.Enable(char.isDirty)
|
||||
|
||||
def refreshCharacterList(self, event=None):
|
||||
sChar = service.Character.getInstance()
|
||||
charList = sChar.getCharacterList()
|
||||
active = self.getActiveCharacter()
|
||||
self.charChoice.Clear()
|
||||
|
||||
for id, name, _ in charList:
|
||||
i = self.charChoice.Append(name, id)
|
||||
if active == id:
|
||||
self.charChoice.SetSelection(i)
|
||||
|
||||
self.btnRestrict()
|
||||
|
||||
def editingFinished(self, event):
|
||||
del self.disableWin
|
||||
wx.PostEvent(self.mainFrame, GE.CharListUpdated())
|
||||
self.Destroy()
|
||||
|
||||
def registerEvents(self):
|
||||
self.Bind(wx.EVT_CLOSE, self.closeEvent)
|
||||
self.Bind(GE.CHAR_LIST_UPDATED, self.refreshCharacterList)
|
||||
self.charChoice.Bind(wx.EVT_CHOICE, self.charChanged)
|
||||
|
||||
def saveChar(self, event):
|
||||
sChr = service.Character.getInstance()
|
||||
charID = self.getActiveCharacter()
|
||||
sChr.saveCharacter(charID)
|
||||
self.sview.populateSkillTree()
|
||||
wx.PostEvent(self, GE.CharListUpdated())
|
||||
|
||||
def saveCharAs(self, event):
|
||||
charID = self.getActiveCharacter()
|
||||
dlg = SaveCharacterAs(self, charID)
|
||||
dlg.ShowModal()
|
||||
self.sview.populateSkillTree()
|
||||
|
||||
def revertChar(self, event):
|
||||
sChr = service.Character.getInstance()
|
||||
charID = self.getActiveCharacter()
|
||||
sChr.revertCharacter(charID)
|
||||
self.sview.populateSkillTree()
|
||||
wx.PostEvent(self, GE.CharListUpdated())
|
||||
|
||||
def closeEvent(self, event):
|
||||
del self.disableWin
|
||||
wx.PostEvent(self.mainFrame, GE.CharListUpdated())
|
||||
self.Destroy()
|
||||
|
||||
def restrict(self):
|
||||
self.btnRename.Enable(False)
|
||||
self.btnDelete.Enable(False)
|
||||
self.aview.stDisabledTip.Show()
|
||||
self.aview.inputID.Enable(False)
|
||||
self.aview.inputKey.Enable(False)
|
||||
self.aview.charChoice.Enable(False)
|
||||
self.aview.btnFetchCharList.Enable(False)
|
||||
self.aview.btnFetchSkills.Enable(False)
|
||||
self.aview.stStatus.SetLabel("")
|
||||
self.aview.Layout()
|
||||
|
||||
def unrestrict(self):
|
||||
self.btnRename.Enable(True)
|
||||
self.btnDelete.Enable(True)
|
||||
self.aview.stDisabledTip.Hide()
|
||||
self.aview.inputID.Enable(True)
|
||||
self.aview.inputKey.Enable(True)
|
||||
self.aview.btnFetchCharList.Enable(True)
|
||||
self.aview.btnFetchSkills.Enable(True)
|
||||
self.aview.stStatus.SetLabel("")
|
||||
self.aview.Layout()
|
||||
|
||||
def charChanged(self, event):
|
||||
self.sview.populateSkillTree()
|
||||
sChar = service.Character.getInstance()
|
||||
charID = self.getActiveCharacter()
|
||||
if sChar.getCharName(charID) in ("All 0", "All 5"):
|
||||
self.restrict()
|
||||
else:
|
||||
self.unrestrict()
|
||||
|
||||
wx.PostEvent(self, GE.CharChanged())
|
||||
if event is not None:
|
||||
event.Skip()
|
||||
|
||||
def getActiveCharacter(self):
|
||||
selection = self.charChoice.GetCurrentSelection()
|
||||
return self.charChoice.GetClientData(selection) if selection is not None else None
|
||||
|
||||
def new(self, event):
|
||||
sChar = service.Character.getInstance()
|
||||
charID = sChar.new()
|
||||
id = self.charChoice.Append(sChar.getCharName(charID), charID)
|
||||
self.charChoice.SetSelection(id)
|
||||
self.unrestrict()
|
||||
self.btnSave.SetLabel("Create")
|
||||
self.rename(None)
|
||||
self.charChanged(None)
|
||||
|
||||
def rename(self, event):
|
||||
if event is not None:
|
||||
self.btnSave.SetLabel("Rename")
|
||||
self.charChoice.Hide()
|
||||
self.characterRename.Show()
|
||||
self.navSizer.Replace(self.charChoice, self.characterRename)
|
||||
self.characterRename.SetFocus()
|
||||
for btn in (self.btnNew, self.btnCopy, self.btnRename, self.btnDelete):
|
||||
btn.Hide()
|
||||
|
||||
self.btnSave.Show()
|
||||
self.navSizer.Layout()
|
||||
|
||||
sChar = service.Character.getInstance()
|
||||
currName = sChar.getCharName(self.getActiveCharacter())
|
||||
self.characterRename.SetValue(currName)
|
||||
self.characterRename.SetSelection(0, len(currName))
|
||||
|
||||
def processRename(self, event):
|
||||
sChar = service.Character.getInstance()
|
||||
newName = self.characterRename.GetLineText(0)
|
||||
|
||||
if newName == "All 0" or newName == "All 5":
|
||||
newName = newName + " bases are belong to us"
|
||||
|
||||
charID = self.getActiveCharacter()
|
||||
sChar.rename(charID, newName)
|
||||
|
||||
self.charChoice.Show()
|
||||
self.characterRename.Hide()
|
||||
self.navSizer.Replace(self.characterRename, self.charChoice)
|
||||
for btn in (self.btnNew, self.btnCopy, self.btnRename, self.btnDelete):
|
||||
btn.Show()
|
||||
|
||||
self.btnSave.Hide()
|
||||
self.navSizer.Layout()
|
||||
self.refreshCharacterList()
|
||||
|
||||
def copy(self, event):
|
||||
sChar = service.Character.getInstance()
|
||||
charID = sChar.copy(self.getActiveCharacter())
|
||||
id = self.charChoice.Append(sChar.getCharName(charID), charID)
|
||||
self.charChoice.SetSelection(id)
|
||||
self.unrestrict()
|
||||
self.btnSave.SetLabel("Copy")
|
||||
self.rename(None)
|
||||
wx.PostEvent(self, GE.CharChanged())
|
||||
|
||||
def delete(self, event):
|
||||
dlg = wx.MessageDialog(self,
|
||||
"Do you really want to delete this character?",
|
||||
"Confirm Delete", wx.YES | wx.NO | wx.ICON_QUESTION)
|
||||
|
||||
if dlg.ShowModal() == wx.ID_YES:
|
||||
sChar = service.Character.getInstance()
|
||||
sChar.delete(self.getActiveCharacter())
|
||||
sel = self.charChoice.GetSelection()
|
||||
self.charChoice.Delete(sel)
|
||||
self.charChoice.SetSelection(sel - 1)
|
||||
newSelection = self.getActiveCharacter()
|
||||
if sChar.getCharName(newSelection) in ("All 0", "All 5"):
|
||||
self.restrict()
|
||||
|
||||
wx.PostEvent(self, GE.CharChanged())
|
||||
|
||||
def Destroy(self):
|
||||
sFit = service.Fit.getInstance()
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
if fitID is not None:
|
||||
sFit.clearFit(fitID)
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))
|
||||
|
||||
wx.Frame.Destroy(self)
|
||||
|
||||
class SkillTreeView (wx.Panel):
|
||||
def __init__(self, parent):
|
||||
wx.Panel.__init__ (self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(500, 300), style=wx.TAB_TRAVERSAL)
|
||||
self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
|
||||
|
||||
pmainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
tree = self.skillTreeListCtrl = wx.gizmos.TreeListCtrl(self, wx.ID_ANY, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT)
|
||||
pmainSizer.Add(tree, 1, wx.EXPAND | wx.ALL, 5)
|
||||
|
||||
|
||||
self.imageList = wx.ImageList(16, 16)
|
||||
tree.SetImageList(self.imageList)
|
||||
self.skillBookImageId = self.imageList.Add(BitmapLoader.getBitmap("skill_small", "gui"))
|
||||
|
||||
tree.AddColumn("Skill")
|
||||
tree.AddColumn("Level")
|
||||
tree.SetMainColumn(0)
|
||||
|
||||
self.root = tree.AddRoot("Skills")
|
||||
tree.SetItemText(self.root, "Levels", 1)
|
||||
|
||||
tree.SetColumnWidth(0, 500)
|
||||
|
||||
self.populateSkillTree()
|
||||
|
||||
tree.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.expandLookup)
|
||||
tree.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.scheduleMenu)
|
||||
|
||||
srcContext = "skillItem"
|
||||
itemContext = "Skill"
|
||||
context = (srcContext, itemContext)
|
||||
self.statsMenu = ContextMenu.getMenu(None, context)
|
||||
self.levelChangeMenu = ContextMenu.getMenu(None, context) or wx.Menu()
|
||||
self.levelChangeMenu.AppendSeparator()
|
||||
self.levelIds = {}
|
||||
|
||||
idUnlearned = wx.NewId()
|
||||
self.levelIds[idUnlearned] = "Not learned"
|
||||
self.levelChangeMenu.Append(idUnlearned, "Unlearn")
|
||||
|
||||
for level in xrange(6):
|
||||
id = wx.NewId()
|
||||
self.levelIds[id] = level
|
||||
self.levelChangeMenu.Append(id, "Level %d" % level)
|
||||
|
||||
self.levelChangeMenu.AppendSeparator()
|
||||
self.revertID = wx.NewId()
|
||||
self.levelChangeMenu.Append(self.revertID, "Revert")
|
||||
|
||||
|
||||
self.saveID = wx.NewId()
|
||||
self.levelChangeMenu.Append(self.saveID, "Save")
|
||||
|
||||
self.levelChangeMenu.Bind(wx.EVT_MENU, self.changeLevel)
|
||||
self.SetSizer(pmainSizer)
|
||||
|
||||
self.Layout()
|
||||
|
||||
def populateSkillTree(self):
|
||||
sChar = service.Character.getInstance()
|
||||
charID = self.Parent.Parent.getActiveCharacter()
|
||||
dirtySkills = sChar.getDirtySkills(charID)
|
||||
dirtyGroups = set([skill.item.group.ID for skill in dirtySkills])
|
||||
|
||||
groups = sChar.getSkillGroups()
|
||||
imageId = self.skillBookImageId
|
||||
root = self.root
|
||||
tree = self.skillTreeListCtrl
|
||||
tree.DeleteChildren(root)
|
||||
|
||||
for id, name in groups:
|
||||
childId = tree.AppendItem(root, name, imageId)
|
||||
tree.SetPyData(childId, id)
|
||||
tree.AppendItem(childId, "dummy")
|
||||
if id in dirtyGroups:
|
||||
tree.SetItemTextColour(childId, wx.BLUE)
|
||||
|
||||
tree.SortChildren(root)
|
||||
|
||||
def expandLookup(self, event):
|
||||
root = event.Item
|
||||
tree = self.skillTreeListCtrl
|
||||
child, cookie = tree.GetFirstChild(root)
|
||||
if tree.GetItemText(child) == "dummy":
|
||||
tree.Delete(child)
|
||||
|
||||
#Get the real intrestin' stuff
|
||||
sChar = service.Character.getInstance()
|
||||
char = self.Parent.Parent.getActiveCharacter()
|
||||
for id, name in sChar.getSkills(tree.GetPyData(root)):
|
||||
iconId = self.skillBookImageId
|
||||
childId = tree.AppendItem(root, name, iconId, data=wx.TreeItemData(id))
|
||||
level, dirty = sChar.getSkillLevel(char, id)
|
||||
tree.SetItemText(childId, "Level %d" % level if isinstance(level, int) else level, 1)
|
||||
if dirty:
|
||||
tree.SetItemTextColour(childId, wx.BLUE)
|
||||
|
||||
tree.SortChildren(root)
|
||||
|
||||
def scheduleMenu(self, event):
|
||||
event.Skip()
|
||||
wx.CallAfter(self.spawnMenu, event.Item)
|
||||
|
||||
def spawnMenu(self, item):
|
||||
self.skillTreeListCtrl.SelectItem(item)
|
||||
if self.skillTreeListCtrl.GetChildrenCount(item) > 0:
|
||||
return
|
||||
|
||||
sChar = service.Character.getInstance()
|
||||
charID = self.Parent.Parent.getActiveCharacter()
|
||||
sMkt = service.Market.getInstance()
|
||||
if sChar.getCharName(charID) not in ("All 0", "All 5"):
|
||||
self.levelChangeMenu.selection = sMkt.getItem(self.skillTreeListCtrl.GetPyData(item))
|
||||
self.PopupMenu(self.levelChangeMenu)
|
||||
else:
|
||||
self.statsMenu.selection = sMkt.getItem(self.skillTreeListCtrl.GetPyData(item))
|
||||
self.PopupMenu(self.statsMenu)
|
||||
|
||||
def changeLevel(self, event):
|
||||
level = self.levelIds.get(event.Id)
|
||||
|
||||
sChar = service.Character.getInstance()
|
||||
charID = self.Parent.Parent.getActiveCharacter()
|
||||
selection = self.skillTreeListCtrl.GetSelection()
|
||||
skillID = self.skillTreeListCtrl.GetPyData(selection)
|
||||
|
||||
if level is not None:
|
||||
self.skillTreeListCtrl.SetItemText(selection, "Level %d" % level if isinstance(level, int) else level, 1)
|
||||
sChar.changeLevel(charID, skillID, level, persist=True)
|
||||
elif event.Id == self.revertID:
|
||||
sChar.revertLevel(charID, skillID)
|
||||
elif event.Id == self.saveID:
|
||||
sChar.saveSkill(charID, skillID)
|
||||
|
||||
self.skillTreeListCtrl.SetItemTextColour(selection, None)
|
||||
|
||||
dirtySkills = sChar.getDirtySkills(charID)
|
||||
dirtyGroups = set([skill.item.group.ID for skill in dirtySkills])
|
||||
|
||||
parentID = self.skillTreeListCtrl.GetItemParent(selection)
|
||||
groupID = self.skillTreeListCtrl.GetPyData(parentID)
|
||||
|
||||
if groupID not in dirtyGroups:
|
||||
self.skillTreeListCtrl.SetItemTextColour(parentID, None)
|
||||
|
||||
wx.PostEvent(self.Parent.Parent, GE.CharListUpdated())
|
||||
event.Skip()
|
||||
|
||||
class ImplantsTreeView (wx.Panel):
|
||||
def addMarketViewImage(self, iconFile):
|
||||
if iconFile is None:
|
||||
return -1
|
||||
bitmap = BitmapLoader.getBitmap(iconFile, "icons")
|
||||
if bitmap is None:
|
||||
return -1
|
||||
else:
|
||||
return self.availableImplantsImageList.Add(bitmap)
|
||||
|
||||
def __init__(self, parent):
|
||||
wx.Panel.__init__ (self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(500, 300), style=wx.TAB_TRAVERSAL)
|
||||
|
||||
pmainSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
availableSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
pmainSizer.Add(availableSizer, 1, wx.ALL | wx.EXPAND, 5)
|
||||
|
||||
self.availableImplantsSearch = wx.SearchCtrl(self, wx.ID_ANY, style=wx.TE_PROCESS_ENTER)
|
||||
self.availableImplantsSearch.ShowCancelButton(True)
|
||||
availableSizer.Add(self.availableImplantsSearch, 0, wx.BOTTOM | wx.EXPAND, 2)
|
||||
|
||||
self.availableImplantsTree = wx.TreeCtrl(self, wx.ID_ANY, style=wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT)
|
||||
root = self.availableRoot = self.availableImplantsTree.AddRoot("Available")
|
||||
self.availableImplantsImageList = wx.ImageList(16, 16)
|
||||
self.availableImplantsTree.SetImageList(self.availableImplantsImageList)
|
||||
|
||||
availableSizer.Add(self.availableImplantsTree, 1, wx.EXPAND)
|
||||
|
||||
buttonSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
pmainSizer.Add(buttonSizer, 0, wx.TOP, 5)
|
||||
|
||||
self.btnAdd = GenBitmapButton(self, wx.ID_ADD, BitmapLoader.getBitmap("fit_add_small", "gui"), style = wx.BORDER_NONE)
|
||||
buttonSizer.Add(self.btnAdd, 0)
|
||||
self.btnRemove = GenBitmapButton(self, wx.ID_REMOVE, BitmapLoader.getBitmap("fit_delete_small", "gui"), style = wx.BORDER_NONE)
|
||||
buttonSizer.Add(self.btnRemove, 0)
|
||||
|
||||
self.pluggedImplantsTree = AvailableImplantsView(self, style=wx.LC_SINGLE_SEL)
|
||||
|
||||
pmainSizer.Add(self.pluggedImplantsTree, 1, wx.ALL | wx.EXPAND, 5)
|
||||
|
||||
self.SetSizer(pmainSizer)
|
||||
|
||||
# Populate the market tree
|
||||
sMkt = service.Market.getInstance()
|
||||
for mktGrp in sMkt.getImplantTree():
|
||||
iconId = self.addMarketViewImage(sMkt.getIconByMarketGroup(mktGrp))
|
||||
childId = self.availableImplantsTree.AppendItem(root, mktGrp.name, iconId, data=wx.TreeItemData(mktGrp.ID))
|
||||
if sMkt.marketGroupHasTypesCheck(mktGrp) is False:
|
||||
self.availableImplantsTree.AppendItem(childId, "dummy")
|
||||
|
||||
self.availableImplantsTree.SortChildren(self.availableRoot)
|
||||
|
||||
#Bind the event to replace dummies by real data
|
||||
self.availableImplantsTree.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.expandLookup)
|
||||
|
||||
#Bind add & remove buttons
|
||||
self.btnAdd.Bind(wx.EVT_BUTTON, self.addImplant)
|
||||
self.btnRemove.Bind(wx.EVT_BUTTON, self.removeImplant)
|
||||
|
||||
#Bind the change of a character*
|
||||
self.Parent.Parent.Bind(GE.CHAR_CHANGED, self.charChanged)
|
||||
self.Enable(False)
|
||||
self.Layout()
|
||||
|
||||
def update(self, implants):
|
||||
self.implants = implants[:]
|
||||
self.implants.sort(key=lambda i: int(i.getModifiedItemAttr("implantness")))
|
||||
self.pluggedImplantsTree.update(self.implants)
|
||||
|
||||
def charChanged(self, event):
|
||||
sChar = service.Character.getInstance()
|
||||
charID = self.Parent.Parent.getActiveCharacter()
|
||||
name = sChar.getCharName(charID)
|
||||
if name == "All 0" or name == "All 5":
|
||||
self.Enable(False)
|
||||
else:
|
||||
self.Enable(True)
|
||||
|
||||
self.update(sChar.getImplants(charID))
|
||||
event.Skip()
|
||||
|
||||
def expandLookup(self, event):
|
||||
tree = self.availableImplantsTree
|
||||
root = event.Item
|
||||
child, cookie = tree.GetFirstChild(root)
|
||||
text = tree.GetItemText(child)
|
||||
if text == "dummy" or text == "itemdummy":
|
||||
sMkt = service.Market.getInstance()
|
||||
#A DUMMY! Keeeel!!! EBUL DUMMY MUST DIAF!
|
||||
tree.Delete(child)
|
||||
|
||||
if text == "dummy":
|
||||
#Add 'real stoof!' instead
|
||||
for id, name, iconFile, more in sMkt.getChildren(tree.GetPyData(root)):
|
||||
iconId = self.addMarketViewImage(iconFile)
|
||||
childId = tree.AppendItem(root, name, iconId, data=wx.TreeItemData(id))
|
||||
if more:
|
||||
tree.AppendItem(childId, "dummy")
|
||||
else:
|
||||
tree.AppendItem(childId, "itemdummy")
|
||||
|
||||
if text == "itemdummy":
|
||||
sMkt = service.Market.getInstance()
|
||||
data, usedMetas = sMkt.getVariations(tree.GetPyData(root))
|
||||
for item in data:
|
||||
id = item.ID
|
||||
name = item.name
|
||||
iconFile = item.icon.iconFile
|
||||
iconId = self.addMarketViewImage(iconFile)
|
||||
tree.AppendItem(root, name, iconId, data=wx.TreeItemData(id))
|
||||
|
||||
tree.SortChildren(root)
|
||||
|
||||
def addImplant(self, event):
|
||||
root = self.availableImplantsTree.GetSelection()
|
||||
|
||||
if not root.IsOk():
|
||||
return
|
||||
|
||||
nchilds = self.availableImplantsTree.GetChildrenCount(root)
|
||||
sChar = service.Character.getInstance()
|
||||
charID = self.Parent.Parent.getActiveCharacter()
|
||||
if nchilds == 0:
|
||||
itemID = self.availableImplantsTree.GetPyData(root)
|
||||
sChar.addImplant(charID, itemID)
|
||||
self.update(sChar.getImplants(charID))
|
||||
|
||||
def removeImplant(self, event):
|
||||
pos = self.pluggedImplantsTree.GetFirstSelected()
|
||||
if pos != -1:
|
||||
sChar = service.Character.getInstance()
|
||||
charID = self.Parent.Parent.getActiveCharacter()
|
||||
sChar.removeImplant(charID, self.implants[pos].slot)
|
||||
self.update(sChar.getImplants(charID))
|
||||
|
||||
class AvailableImplantsView(d.Display):
|
||||
DEFAULT_COLS = ["Base Name",
|
||||
"attr:implantness"]
|
||||
|
||||
def __init__(self, parent, style):
|
||||
d.Display.__init__(self, parent, style=style)
|
||||
|
||||
class APIView (wx.Panel):
|
||||
def __init__(self, parent):
|
||||
wx.Panel.__init__ (self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(500, 300), style=wx.TAB_TRAVERSAL)
|
||||
self.Parent.Parent.Bind(GE.CHAR_CHANGED, self.charChanged)
|
||||
self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
|
||||
|
||||
self.apiUrlCreatePredefined = u"https://community.eveonline.com/support/api-key/CreatePredefined?accessMask=8"
|
||||
self.apiUrlKeyList = u"https://community.eveonline.com/support/api-key/"
|
||||
|
||||
pmainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
hintSizer = wx.BoxSizer( wx.HORIZONTAL )
|
||||
hintSizer.AddStretchSpacer()
|
||||
self.stDisabledTip = wx.StaticText( self, wx.ID_ANY, u"You cannot add API Details for All 0 and All 5 characters.\n"
|
||||
u"Please select another character or make a new one.", style=wx.ALIGN_CENTER )
|
||||
self.stDisabledTip.Wrap( -1 )
|
||||
hintSizer.Add( self.stDisabledTip, 0, wx.TOP | wx.BOTTOM, 10 )
|
||||
self.stDisabledTip.Hide()
|
||||
hintSizer.AddStretchSpacer()
|
||||
pmainSizer.Add(hintSizer, 0, wx.EXPAND, 5)
|
||||
|
||||
|
||||
fgSizerInput = wx.FlexGridSizer(3, 2, 0, 0)
|
||||
fgSizerInput.AddGrowableCol(1)
|
||||
fgSizerInput.SetFlexibleDirection(wx.BOTH)
|
||||
fgSizerInput.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED)
|
||||
|
||||
self.m_staticIDText = wx.StaticText(self, wx.ID_ANY, u"keyID:", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.m_staticIDText.Wrap(-1)
|
||||
fgSizerInput.Add(self.m_staticIDText, 0, wx.ALL | wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
|
||||
self.inputID = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
fgSizerInput.Add(self.inputID, 1, wx.ALL | wx.EXPAND, 5)
|
||||
|
||||
self.m_staticKeyText = wx.StaticText(self, wx.ID_ANY, u"vCode:", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.m_staticKeyText.Wrap(-1)
|
||||
fgSizerInput.Add(self.m_staticKeyText, 0, wx.ALL | wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
|
||||
self.inputKey = wx.TextCtrl(self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
fgSizerInput.Add(self.inputKey, 0, wx.ALL | wx.EXPAND, 5)
|
||||
|
||||
self.m_staticCharText = wx.StaticText(self, wx.ID_ANY, u"Character:", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.m_staticCharText.Wrap(-1)
|
||||
fgSizerInput.Add(self.m_staticCharText, 0, wx.ALL | wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
|
||||
self.charChoice = wx.Choice(self, wx.ID_ANY, style=0)
|
||||
self.charChoice.Append("No Selection", 0)
|
||||
fgSizerInput.Add(self.charChoice, 1, wx.ALL | wx.EXPAND, 5)
|
||||
|
||||
self.charChoice.Enable(False)
|
||||
|
||||
pmainSizer.Add(fgSizerInput, 0, wx.EXPAND, 5)
|
||||
|
||||
btnSizer = wx.BoxSizer( wx.HORIZONTAL )
|
||||
btnSizer.AddStretchSpacer()
|
||||
|
||||
self.btnFetchCharList = wx.Button(self, wx.ID_ANY, u"Get Characters")
|
||||
btnSizer.Add(self.btnFetchCharList, 0, wx.ALL, 2)
|
||||
self.btnFetchCharList.Bind(wx.EVT_BUTTON, self.fetchCharList)
|
||||
|
||||
self.btnFetchSkills = wx.Button(self, wx.ID_ANY, u"Fetch Skills")
|
||||
btnSizer.Add(self.btnFetchSkills, 0, wx.ALL, 2)
|
||||
self.btnFetchSkills.Bind(wx.EVT_BUTTON, self.fetchSkills)
|
||||
self.btnFetchSkills.Enable(False)
|
||||
|
||||
btnSizer.AddStretchSpacer()
|
||||
pmainSizer.Add(btnSizer, 0, wx.EXPAND, 5)
|
||||
|
||||
self.stStatus = wx.StaticText(self, wx.ID_ANY, wx.EmptyString)
|
||||
pmainSizer.Add(self.stStatus, 0, wx.ALL, 5)
|
||||
|
||||
pmainSizer.AddStretchSpacer()
|
||||
self.stAPITip = wx.StaticText( self, wx.ID_ANY, u"You can create a pre-defined key here (only CharacterSheet is required):", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.stAPITip.Wrap( -1 )
|
||||
|
||||
pmainSizer.Add( self.stAPITip, 0, wx.ALL, 2 )
|
||||
|
||||
self.hlEveAPI = wx.HyperlinkCtrl( self, wx.ID_ANY, self.apiUrlCreatePredefined, self.apiUrlCreatePredefined, wx.DefaultPosition, wx.DefaultSize, wx.HL_DEFAULT_STYLE )
|
||||
pmainSizer.Add( self.hlEveAPI, 0, wx.ALL, 2 )
|
||||
|
||||
self.stAPITip2 = wx.StaticText( self, wx.ID_ANY, u"Or, you can choose an existing key from:", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.stAPITip2.Wrap( -1 )
|
||||
pmainSizer.Add( self.stAPITip2, 0, wx.ALL, 2 )
|
||||
|
||||
self.hlEveAPI2 = wx.HyperlinkCtrl( self, wx.ID_ANY, self.apiUrlKeyList, self.apiUrlKeyList, wx.DefaultPosition, wx.DefaultSize, wx.HL_DEFAULT_STYLE )
|
||||
pmainSizer.Add( self.hlEveAPI2, 0, wx.ALL, 2 )
|
||||
|
||||
self.SetSizer(pmainSizer)
|
||||
self.Layout()
|
||||
self.charChanged(None)
|
||||
|
||||
def charChanged(self, event):
|
||||
sChar = service.Character.getInstance()
|
||||
ID, key, char, chars = sChar.getApiDetails(self.Parent.Parent.getActiveCharacter())
|
||||
self.inputID.SetValue(str(ID))
|
||||
self.inputKey.SetValue(key)
|
||||
|
||||
self.charChoice.Clear()
|
||||
|
||||
if chars:
|
||||
for charName in chars:
|
||||
i = self.charChoice.Append(charName)
|
||||
self.charChoice.SetStringSelection(char)
|
||||
self.charChoice.Enable(True)
|
||||
self.btnFetchSkills.Enable(True)
|
||||
else:
|
||||
self.charChoice.Append("No characters...", 0)
|
||||
self.charChoice.SetSelection(0)
|
||||
self.charChoice.Enable(False)
|
||||
self.btnFetchSkills.Enable(False)
|
||||
|
||||
|
||||
if event is not None:
|
||||
event.Skip()
|
||||
|
||||
def fetchCharList(self, event):
|
||||
self.stStatus.SetLabel("")
|
||||
if self.inputID.GetLineText(0) == "" or self.inputKey.GetLineText(0) == "":
|
||||
self.stStatus.SetLabel("Invalid keyID or vCode!")
|
||||
return
|
||||
|
||||
sChar = service.Character.getInstance()
|
||||
try:
|
||||
list = sChar.apiCharList(self.Parent.Parent.getActiveCharacter(), self.inputID.GetLineText(0), self.inputKey.GetLineText(0))
|
||||
except service.network.AuthenticationError, e:
|
||||
self.stStatus.SetLabel("Authentication failure. Please check keyID and vCode combination.")
|
||||
except service.network.TimeoutError, e:
|
||||
self.stStatus.SetLabel("Request timed out. Please check network connectivity and/or proxy settings.")
|
||||
except Exception, e:
|
||||
self.stStatus.SetLabel("Error:\n%s"%e.message)
|
||||
else:
|
||||
self.charChoice.Clear()
|
||||
for charName in list:
|
||||
i = self.charChoice.Append(charName)
|
||||
|
||||
self.btnFetchSkills.Enable(True)
|
||||
self.charChoice.Enable(True)
|
||||
|
||||
self.Layout()
|
||||
|
||||
self.charChoice.SetSelection(0)
|
||||
|
||||
def fetchSkills(self, event):
|
||||
charName = self.charChoice.GetString(self.charChoice.GetSelection())
|
||||
if charName:
|
||||
try:
|
||||
sChar = service.Character.getInstance()
|
||||
sChar.apiFetch(self.Parent.Parent.getActiveCharacter(), charName)
|
||||
self.stStatus.SetLabel("Successfully fetched %s\'s skills from EVE API." % charName)
|
||||
except Exception, e:
|
||||
self.stStatus.SetLabel("Unable to retrieve %s\'s skills. Error message:\n%s" % (charName, e))
|
||||
|
||||
class SaveCharacterAs(wx.Dialog):
|
||||
|
||||
def __init__(self, parent, charID):
|
||||
wx.Dialog.__init__(self, parent, title="Save Character As...", size=wx.Size(300, 60))
|
||||
self.charID = charID
|
||||
self.parent = parent
|
||||
sChar = service.Character.getInstance()
|
||||
name = sChar.getCharName(charID)
|
||||
bSizer1 = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
self.input = wx.TextCtrl(self, wx.ID_ANY, name, style=wx.TE_PROCESS_ENTER)
|
||||
|
||||
bSizer1.Add(self.input, 1, wx.ALL, 5)
|
||||
self.input.Bind(wx.EVT_TEXT_ENTER, self.change)
|
||||
self.button = wx.Button(self, wx.ID_OK, u"Save")
|
||||
bSizer1.Add(self.button, 0, wx.ALL, 5)
|
||||
|
||||
self.SetSizer(bSizer1)
|
||||
self.Layout()
|
||||
self.Centre(wx.BOTH)
|
||||
self.button.Bind(wx.EVT_BUTTON, self.change)
|
||||
|
||||
def change(self, event):
|
||||
sChar = service.Character.getInstance()
|
||||
sChar.saveCharacterAs(self.charID, self.input.GetLineText(0))
|
||||
wx.PostEvent(self.parent, GE.CharListUpdated())
|
||||
|
||||
event.Skip()
|
||||
self.Close()
|
||||
|
||||
@@ -43,15 +43,10 @@ class GangView ( ScrolledPanel ):
|
||||
self.helpText = wx.StaticText( self, wx.ID_ANY, help, wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE )
|
||||
helpSizer.Add( self.helpText, 1, wx.ALL, 5 )
|
||||
|
||||
self.FitDNDPopupMenu = wx.Menu()
|
||||
|
||||
self.options = ["Fleet", "Wing", "Squad"]
|
||||
|
||||
self.fleet = {}
|
||||
for id, option in enumerate(self.options):
|
||||
item = self.FitDNDPopupMenu.Append(-1, option)
|
||||
# We bind it to the mainFrame because it may be called from either this class or from FitItem via shipBrowser
|
||||
self.mainFrame.Bind(wx.EVT_MENU, self.OnPopupItemSelected, item)
|
||||
|
||||
# set content for each commander
|
||||
self.fleet[id] = {}
|
||||
@@ -61,6 +56,8 @@ class GangView ( ScrolledPanel ):
|
||||
self.fleet[id]['chChar'] = wx.Choice( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, [] )
|
||||
self.fleet[id]['fitSizer'] = wx.BoxSizer( wx.VERTICAL )
|
||||
|
||||
self.FitDNDPopupMenu = self.buildBoostermenu()
|
||||
|
||||
contentFGSizer = wx.FlexGridSizer( 5, 3, 0, 0 )
|
||||
contentFGSizer.AddGrowableCol( 1 )
|
||||
contentFGSizer.SetFlexibleDirection( wx.BOTH )
|
||||
@@ -130,6 +127,15 @@ class GangView ( ScrolledPanel ):
|
||||
self.RefreshBoosterFits()
|
||||
self.RefreshCharacterList()
|
||||
|
||||
def buildBoostermenu(self):
|
||||
menu = wx.Menu()
|
||||
|
||||
for id, option in enumerate(self.options):
|
||||
item = menu.Append(-1, option)
|
||||
# We bind it to the mainFrame because it may be called from either this class or from FitItem via shipBrowser
|
||||
self.mainFrame.Bind(wx.EVT_MENU, self.OnPopupItemSelected, item)
|
||||
return menu
|
||||
|
||||
def OnEnterWindow(self, event):
|
||||
obj = event.GetEventObject()
|
||||
obj.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
|
||||
@@ -371,7 +377,7 @@ class GangView ( ScrolledPanel ):
|
||||
def OnPopupItemSelected(self, event):
|
||||
''' Fired when booster popup item is selected '''
|
||||
# Get menu selection ID via self.options
|
||||
menuItem = self.FitDNDPopupMenu.FindItemById(event.GetId())
|
||||
menuItem = event.EventObject.FindItemById(event.GetId())
|
||||
type = self.options.index(menuItem.GetText())
|
||||
|
||||
if self.draggedFitID:
|
||||
|
||||
@@ -361,6 +361,9 @@ class ItemParams (wx.Panel):
|
||||
else:
|
||||
attrName = name
|
||||
|
||||
if info and config.debug:
|
||||
attrName += " ({})".format(info.ID)
|
||||
|
||||
if info:
|
||||
if info.icon is not None:
|
||||
iconFile = info.icon.iconFile
|
||||
@@ -376,7 +379,7 @@ class ItemParams (wx.Panel):
|
||||
attrIcon = self.imageList.Add(BitmapLoader.getBitmap("07_15", "icons"))
|
||||
|
||||
|
||||
index = self.paramList.InsertImageStringItem(sys.maxint, attrName,attrIcon)
|
||||
index = self.paramList.InsertImageStringItem(sys.maxint, attrName, attrIcon)
|
||||
idNameMap[idCount] = attrName
|
||||
self.paramList.SetItemData(index, idCount)
|
||||
idCount += 1
|
||||
@@ -499,6 +502,8 @@ class ItemEffects (wx.Panel):
|
||||
|
||||
self.effectList.InsertColumn(0,"Name")
|
||||
self.effectList.InsertColumn(1,"Implemented")
|
||||
if config.debug:
|
||||
self.effectList.InsertColumn(2,"ID")
|
||||
|
||||
#self.effectList.SetColumnWidth(0,385)
|
||||
|
||||
@@ -519,6 +524,8 @@ class ItemEffects (wx.Panel):
|
||||
implemented = "Erroneous"
|
||||
|
||||
self.effectList.SetStringItem(index, 1, implemented)
|
||||
if config.debug:
|
||||
self.effectList.SetStringItem(index, 2, str(effects[name].ID))
|
||||
|
||||
self.effectList.RefreshRows()
|
||||
self.Layout()
|
||||
|
||||
@@ -24,6 +24,8 @@ import sqlalchemy
|
||||
import wx
|
||||
import time
|
||||
|
||||
from codecs import open
|
||||
|
||||
from wx._core import PyDeadObjectError
|
||||
from wx.lib.wordwrap import wordwrap
|
||||
|
||||
@@ -114,8 +116,8 @@ class MainFrame(wx.Frame):
|
||||
def getInstance(cls):
|
||||
return cls.__instance if cls.__instance is not None else MainFrame()
|
||||
|
||||
def __init__(self):
|
||||
self.title="pyfa %s%s - Python Fitting Assistant"%(config.version, "" if config.tag.lower() != 'git' else " (git)")
|
||||
def __init__(self, title):
|
||||
self.title=title
|
||||
wx.Frame.__init__(self, None, wx.ID_ANY, self.title)
|
||||
|
||||
MainFrame.__instance = self
|
||||
@@ -324,6 +326,7 @@ class MainFrame(wx.Frame):
|
||||
|
||||
def ShowAboutBox(self, evt):
|
||||
import eos.config
|
||||
v = sys.version_info
|
||||
info = wx.AboutDialogInfo()
|
||||
info.Name = "pyfa"
|
||||
info.Version = gui.aboutData.versionString
|
||||
@@ -334,14 +337,14 @@ class MainFrame(wx.Frame):
|
||||
"\n\nLicenses:\n\t" +
|
||||
"\n\t".join(gui.aboutData.licenses) +
|
||||
"\n\nEVE Data: \t" + eos.config.gamedata_version +
|
||||
"\nPython: \t" + sys.version +
|
||||
"\nPython: \t\t" + '{}.{}.{}'.format(v.major, v.minor, v.micro) +
|
||||
"\nwxPython: \t" + wx.__version__ +
|
||||
"\nSQLAlchemy: \t" + sqlalchemy.__version__,
|
||||
700, wx.ClientDC(self))
|
||||
500, wx.ClientDC(self))
|
||||
if "__WXGTK__" in wx.PlatformInfo:
|
||||
forumUrl = "http://forums.eveonline.com/default.aspx?g=posts&t=247609"
|
||||
forumUrl = "http://forums.eveonline.com/default.aspx?g=posts&t=466425"
|
||||
else:
|
||||
forumUrl = "http://forums.eveonline.com/default.aspx?g=posts&t=247609"
|
||||
forumUrl = "http://forums.eveonline.com/default.aspx?g=posts&t=466425"
|
||||
info.WebSite = (forumUrl, "pyfa thread at EVE Online forum")
|
||||
wx.AboutBox(info)
|
||||
|
||||
@@ -385,7 +388,7 @@ class MainFrame(wx.Frame):
|
||||
print "oops, invalid fit format %d" % format
|
||||
dlg.Destroy()
|
||||
return
|
||||
file = open(path, "w")
|
||||
file = open(path, "w", encoding="utf-8")
|
||||
file.write(output)
|
||||
file.close()
|
||||
dlg.Destroy()
|
||||
@@ -395,10 +398,10 @@ class MainFrame(wx.Frame):
|
||||
dlg.ShowModal()
|
||||
|
||||
def goWiki(self, event):
|
||||
webbrowser.open('https://github.com/DarkFenX/Pyfa/wiki')
|
||||
webbrowser.open('https://github.com/pyfa-org/Pyfa/wiki')
|
||||
|
||||
def goForums(self, event):
|
||||
webbrowser.open('https://forums.eveonline.com/default.aspx?g=posts&t=247609')
|
||||
webbrowser.open('https://forums.eveonline.com/default.aspx?g=posts&t=466425')
|
||||
|
||||
def registerMenu(self):
|
||||
menuBar = self.GetMenuBar()
|
||||
@@ -784,7 +787,7 @@ class MainFrame(wx.Frame):
|
||||
else:
|
||||
self.progressDialog.Update(info)
|
||||
|
||||
def fileImportCallback(self, info, fits=None):
|
||||
def fileImportCallback(self, action, data=None):
|
||||
"""
|
||||
While importing fits from file, the logic calls back to this function to
|
||||
update progress bar to show activity. XML files can contain multiple
|
||||
@@ -792,18 +795,28 @@ class MainFrame(wx.Frame):
|
||||
a single ship. When iterating through the files, we update the message
|
||||
when we start a new file, and then Pulse the progress bar with every fit
|
||||
that is processed.
|
||||
|
||||
action : a flag that lets us know how to deal with :data
|
||||
None: Pulse the progress bar
|
||||
1: Replace message with data
|
||||
other: Close dialog and handle based on :action (-1 open fits, -2 display error)
|
||||
"""
|
||||
|
||||
if info == -1:
|
||||
self.closeProgressDialog()
|
||||
self._openAfterImport(fits)
|
||||
elif info != self.progressDialog.message and info is not None:
|
||||
# New message, overwrite cached message and update
|
||||
self.progressDialog.message = info
|
||||
self.progressDialog.Pulse(info)
|
||||
else:
|
||||
# Simply Pulse() if we don't have anything else to do
|
||||
if action is None:
|
||||
self.progressDialog.Pulse()
|
||||
elif action == 1 and data != self.progressDialog.message:
|
||||
self.progressDialog.message = data
|
||||
self.progressDialog.Pulse(data)
|
||||
else:
|
||||
self.closeProgressDialog()
|
||||
if action == -1:
|
||||
self._openAfterImport(data)
|
||||
elif action == -2:
|
||||
dlg = wx.MessageDialog(self,
|
||||
"The following error was generated\n\n%s\n\nBe aware that already processed fits were not saved"%data,
|
||||
"Import Error", wx.OK | wx.ICON_ERROR)
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
return
|
||||
|
||||
def _openAfterImport(self, fits):
|
||||
if len(fits) > 0:
|
||||
|
||||
@@ -49,6 +49,10 @@ class MainMenuBar(wx.MenuBar):
|
||||
self.attrEditorId = wx.NewId()
|
||||
self.toggleOverridesId = wx.NewId()
|
||||
|
||||
if 'wxMac' in wx.PlatformInfo and wx.VERSION >= (3,0):
|
||||
wx.ID_COPY = wx.NewId()
|
||||
wx.ID_PASTE = wx.NewId()
|
||||
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
wx.MenuBar.__init__(self)
|
||||
|
||||
@@ -77,10 +81,8 @@ class MainMenuBar(wx.MenuBar):
|
||||
#editMenu.Append(wx.ID_UNDO)
|
||||
#editMenu.Append(wx.ID_REDO)
|
||||
|
||||
copyText = "&To Clipboard" + ("\tCTRL+C" if 'wxMSW' in wx.PlatformInfo else "")
|
||||
pasteText = "&From Clipboard" + ("\tCTRL+V" if 'wxMSW' in wx.PlatformInfo else "")
|
||||
editMenu.Append(wx.ID_COPY, copyText, "Export a fit to the clipboard")
|
||||
editMenu.Append(wx.ID_PASTE, pasteText, "Import a fit from the clipboard")
|
||||
editMenu.Append(wx.ID_COPY, "To Clipboard\tCTRL+C", "Export a fit to the clipboard")
|
||||
editMenu.Append(wx.ID_PASTE, "From Clipboard\tCTRL+V", "Import a fit from the clipboard")
|
||||
editMenu.AppendSeparator()
|
||||
editMenu.Append(self.saveCharId, "Save Character")
|
||||
editMenu.Append(self.saveCharAsId, "Save Character As...")
|
||||
@@ -106,7 +108,8 @@ class MainMenuBar(wx.MenuBar):
|
||||
graphFrameItem.SetBitmap(BitmapLoader.getBitmap("graphs_small", "gui"))
|
||||
windowMenu.AppendItem(graphFrameItem)
|
||||
|
||||
preferencesItem = wx.MenuItem(windowMenu, wx.ID_PREFERENCES, "Preferences\tCTRL+P")
|
||||
preferencesShortCut = "CTRL+," if 'wxMac' in wx.PlatformInfo else "CTRL+P"
|
||||
preferencesItem = wx.MenuItem(windowMenu, wx.ID_PREFERENCES, "Preferences\t"+preferencesShortCut)
|
||||
preferencesItem.SetBitmap(BitmapLoader.getBitmap("preferences_small", "gui"))
|
||||
windowMenu.AppendItem(preferencesItem)
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
##
|
||||
## Author: Darriele - HomeWorld
|
||||
##
|
||||
## Project home: http://github.com/DarkFenX/Pyfa - pyfa project
|
||||
## Project home: https://github.com/pyfa-org/Pyfa - pyfa project
|
||||
## Some portions of code are based on
|
||||
## AGW:pycollapsiblepane generic implementation of wx.CollapsiblePane
|
||||
## AGW:pycollapsiblepane credits ( from the original source file used ):
|
||||
|
||||
@@ -20,6 +20,8 @@ import gui.utils.drawUtils as drawUtils
|
||||
import gui.utils.animEffects as animEffects
|
||||
import gui.utils.fonts as fonts
|
||||
|
||||
from service import fit
|
||||
|
||||
class PyGauge(wx.PyWindow):
|
||||
"""
|
||||
This class provides a visual alternative for `wx.Gauge`. It currently
|
||||
@@ -174,10 +176,15 @@ class PyGauge(wx.PyWindow):
|
||||
return self._range
|
||||
|
||||
def Animate(self):
|
||||
if not self._timer:
|
||||
self._timer = wx.Timer(self, self._timerId)
|
||||
self._animStep = 0
|
||||
self._timer.Start(self._period)
|
||||
sFit = fit.Fit.getInstance()
|
||||
if sFit.serviceFittingOptions["enableGaugeAnimation"]:
|
||||
if not self._timer:
|
||||
self._timer = wx.Timer(self, self._timerId)
|
||||
self._animStep = 0
|
||||
self._timer.Start(self._period)
|
||||
else:
|
||||
self._animValue = self._percentage
|
||||
self.Refresh()
|
||||
|
||||
def SetRange(self, range, reinit = False):
|
||||
"""
|
||||
|
||||
@@ -1536,13 +1536,12 @@ class FitItem(SFItem.SFBrowserItem):
|
||||
menu = wx.Menu()
|
||||
toggleItem = menu.Append(wx.ID_ANY, "Booster Fit", kind=wx.ITEM_CHECK)
|
||||
menu.Check(toggleItem.GetId(), self.fitBooster)
|
||||
|
||||
self.Bind(wx.EVT_MENU, self.OnToggleBooster, toggleItem)
|
||||
|
||||
if self.mainFrame.getActiveFit():
|
||||
# If there is an active fit, get menu for setting individual boosters
|
||||
menu.AppendSeparator()
|
||||
boosterMenu = self.mainFrame.additionsPane.gangPage.FitDNDPopupMenu
|
||||
boosterMenu = self.mainFrame.additionsPane.gangPage.buildBoostermenu()
|
||||
menu.AppendSubMenu(boosterMenu, 'Set Booster')
|
||||
|
||||
self.PopupMenu(menu, pos)
|
||||
|
||||
@@ -116,5 +116,5 @@ class UpdateDialog(wx.Dialog):
|
||||
self.UpdateSettings.set('version', None)
|
||||
|
||||
def OnDownload(self, e):
|
||||
wx.LaunchDefaultBrowser('https://github.com/DarkFenX/Pyfa/releases/tag/'+self.releaseInfo['tag_name'])
|
||||
wx.LaunchDefaultBrowser('https://github.com/pyfa-org/Pyfa/releases/tag/'+self.releaseInfo['tag_name'])
|
||||
self.OnClose(e)
|
||||
|
||||
Reference in New Issue
Block a user