Compare commits
207 Commits
v2.9.1
...
v2.9.3dev1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44a7e53b9e | ||
|
|
b35bdd4e33 | ||
|
|
7f52f6fe44 | ||
|
|
34e49da0c1 | ||
|
|
5132698974 | ||
|
|
832cebcaaf | ||
|
|
4eaccd1eed | ||
|
|
5245f289a5 | ||
|
|
672aed44f2 | ||
|
|
8c890cf9a5 | ||
|
|
8f9a95db93 | ||
|
|
5a056e6d47 | ||
|
|
b121085271 | ||
|
|
b3ef55cb7f | ||
|
|
bbc8fd0f97 | ||
|
|
b11a576922 | ||
|
|
7375258b9f | ||
|
|
c447cf06d7 | ||
|
|
a7dcf1ace6 | ||
|
|
bd3d81e2f8 | ||
|
|
732b7a5ab9 | ||
|
|
3c16600c53 | ||
|
|
d0921ba9ec | ||
|
|
8ec840740b | ||
|
|
580ff1c435 | ||
|
|
d68296bfd7 | ||
|
|
c520b5e4f5 | ||
|
|
2da85888be | ||
|
|
bdd4a8cfb7 | ||
|
|
dbef3b8c84 | ||
|
|
63a6d746e8 | ||
|
|
7b8d9f8dbe | ||
|
|
7aa73e4b2f | ||
|
|
33883c562a | ||
|
|
36c17dde8d | ||
|
|
5a9fd188f0 | ||
|
|
4b65662c9f | ||
|
|
cd3d1a9557 | ||
|
|
9f63b0b412 | ||
|
|
9249ef24b3 | ||
|
|
63a599ca85 | ||
|
|
fa2bceaff9 | ||
|
|
e9dffeadf6 | ||
|
|
161c4629cf | ||
|
|
951ffcd35a | ||
|
|
ba21ebe058 | ||
|
|
f8c2604fb2 | ||
|
|
966763aaa4 | ||
|
|
4eb8973c31 | ||
|
|
72fe52e560 | ||
|
|
e346239174 | ||
|
|
dd27a26fa9 | ||
|
|
162b115c91 | ||
|
|
99f4ed6b33 | ||
|
|
53252241e1 | ||
|
|
698328e335 | ||
|
|
dece788f66 | ||
|
|
958fbac582 | ||
|
|
99d72956e8 | ||
|
|
eb601e991a | ||
|
|
cb7f0052c4 | ||
|
|
8b75b5f184 | ||
|
|
bf5935e033 | ||
|
|
67e80deed9 | ||
|
|
e39f9ffecf | ||
|
|
e865c9a399 | ||
|
|
a919510d07 | ||
|
|
bd86d3289f | ||
|
|
c8ff644b63 | ||
|
|
6703a08976 | ||
|
|
3d70d9e37c | ||
|
|
ef62d5cf97 | ||
|
|
caf5f33c80 | ||
|
|
29c29469c6 | ||
|
|
7b564f1f53 | ||
|
|
f280955ac3 | ||
|
|
e09fce8411 | ||
|
|
5777103d21 | ||
|
|
8671b20790 | ||
|
|
dc30b3ed1d | ||
|
|
07a9f77287 | ||
|
|
9d58ceb14d | ||
|
|
71c421702c | ||
|
|
989f12453d | ||
|
|
b7d6892d9f | ||
|
|
cfb351a751 | ||
|
|
dde1e7990d | ||
|
|
6e4ec54ac6 | ||
|
|
81da217a09 | ||
|
|
2d1613d8bc | ||
|
|
ccc2e6ece3 | ||
|
|
1206e95cfb | ||
|
|
921ccd3be9 | ||
|
|
178e3a3d56 | ||
|
|
5d255547e4 | ||
|
|
bd148b8792 | ||
|
|
b88ebdcfc0 | ||
|
|
3a26815d18 | ||
|
|
b70fcd9659 | ||
|
|
71aa557770 | ||
|
|
d35bf6514f | ||
|
|
abe015bee3 | ||
|
|
929520091f | ||
|
|
d4847112a9 | ||
|
|
4e2c3a3fcc | ||
|
|
91e6d89022 | ||
|
|
b9a71c08b7 | ||
|
|
070dd62e6d | ||
|
|
b404abca41 | ||
|
|
99f00b25a1 | ||
|
|
45936b5b98 | ||
|
|
b1aac9f56d | ||
|
|
13f370ceb9 | ||
|
|
b5a4f97cb5 | ||
|
|
0679a0af0f | ||
|
|
53fe3242b9 | ||
|
|
6615bed1cd | ||
|
|
ad0c7a7a9d | ||
|
|
87ba6a9af0 | ||
|
|
5c44df7f21 | ||
|
|
24bc675319 | ||
|
|
be2e0b5de4 | ||
|
|
e4481e8fb4 | ||
|
|
19b1eb161b | ||
|
|
30ed1ac81d | ||
|
|
b4288e17e5 | ||
|
|
c03d000c45 | ||
|
|
881ec8b5b4 | ||
|
|
71d5b28b75 | ||
|
|
a15fdc3b23 | ||
|
|
55cd33e653 | ||
|
|
af0b2b9f1b | ||
|
|
983641d1d5 | ||
|
|
4ab21e92bf | ||
|
|
413f00a475 | ||
|
|
bde2043294 | ||
|
|
d45857f1fc | ||
|
|
8a19bf78ce | ||
|
|
d523722988 | ||
|
|
031cb6fcfb | ||
|
|
72fc560241 | ||
|
|
1d7be66eb1 | ||
|
|
5d32a31dc3 | ||
|
|
4821bd1c72 | ||
|
|
6694caafa0 | ||
|
|
7b71c16cec | ||
|
|
df6e7b5772 | ||
|
|
7abc14eb7f | ||
|
|
4d21fa517a | ||
|
|
f2a82c31c4 | ||
|
|
337973965a | ||
|
|
f0b3aafd54 | ||
|
|
f6b97859aa | ||
|
|
1064a90a1c | ||
|
|
4c736de598 | ||
|
|
8d0ad26159 | ||
|
|
3efa07d821 | ||
|
|
44240c1d37 | ||
|
|
9eaeb60af7 | ||
|
|
cecb8f69a3 | ||
|
|
d402735c8b | ||
|
|
327ad78eb8 | ||
|
|
edc1ef0e38 | ||
|
|
c6bfd0bc05 | ||
|
|
3badab0353 | ||
|
|
8ca5b34c14 | ||
|
|
417ffd396c | ||
|
|
ccb0732f7d | ||
|
|
a994f55011 | ||
|
|
c2d309430e | ||
|
|
c3e1ec2760 | ||
|
|
8c40489049 | ||
|
|
051800bc16 | ||
|
|
d1a3e5c0e8 | ||
|
|
48d795676f | ||
|
|
3fec9ba173 | ||
|
|
264208b42e | ||
|
|
62e8da6ff2 | ||
|
|
e3f21cf700 | ||
|
|
fbc34224bc | ||
|
|
93cd3b97fa | ||
|
|
fda83bcb49 | ||
|
|
85b046a640 | ||
|
|
1177575f77 | ||
|
|
fc4a10efe3 | ||
|
|
f541b4329e | ||
|
|
7ba1a4c78f | ||
|
|
0675ed9a73 | ||
|
|
68a13a6bb8 | ||
|
|
61ef7c3487 | ||
|
|
a5bb16c460 | ||
|
|
e694ced86c | ||
|
|
babc2d1e42 | ||
|
|
8e717b19d9 | ||
|
|
dbca0f9dea | ||
|
|
7380244cd9 | ||
|
|
5b7c777d6b | ||
|
|
2fb9d3479f | ||
|
|
21f095250d | ||
|
|
270376e09c | ||
|
|
1ed71c6580 | ||
|
|
febc98045c | ||
|
|
72ecc62732 | ||
|
|
9e1681d3f9 | ||
|
|
0471ffa924 | ||
|
|
4269a00428 | ||
|
|
440b2caa8d |
@@ -24,7 +24,7 @@ $ brew install Caskroom/cask/pyfa
|
||||
### Linux Distro-specific Packages
|
||||
The following is a list of pyfa packages available for certain distributions. Please note that these packages are maintained by third-parties and are not evaluated by the pyfa developers.
|
||||
|
||||
* Debian/Ubuntu/derivitives: https://github.com/AdamMajer/Pyfa/releases
|
||||
* Debian/Ubuntu/derivatives: https://github.com/AdamMajer/Pyfa/releases
|
||||
* Arch: https://aur.archlinux.org/packages/pyfa/
|
||||
* openSUSE: https://build.opensuse.org/package/show/home:rmk2/pyfa
|
||||
* FreeBSD: http://www.freshports.org/games/pyfa/ (see [#484](https://github.com/pyfa-org/Pyfa/issues/484) for instructions)
|
||||
@@ -53,6 +53,10 @@ pyfa is licensed under the GNU GPL v3.0, see LICENSE
|
||||
* [TweetFleet Slack](https://www.fuzzwork.co.uk/tweetfleet-slack-invites/): @blitzmann
|
||||
* [Gitter chat](https://gitter.im/pyfa-org/Pyfa): @ blitzmann
|
||||
* Email: sable.blitzmann@gmail.com
|
||||
* Kadesh / DarkPhoenix
|
||||
* GitHub: @DarkFenX
|
||||
* EVE: Kadesh Priestess
|
||||
* Email: phoenix@mail.ru
|
||||
|
||||
## CCP Copyright Notice
|
||||
EVE Online, the EVE logo, EVE and all associated logos and designs are the intellectual property of CCP hf. All artwork, screenshots, characters, vehicles, storylines, world facts or other recognizable features of the intellectual property relating to these trademarks are likewise the intellectual property of CCP hf. EVE Online and the EVE logo are the registered trademarks of CCP hf. All rights are reserved worldwide. All other trademarks are the property of their respective owners. CCP hf. has granted permission to pyfa to use EVE Online and all associated logos and designs for promotional and information purposes on its website but does not endorse, and is not in any way affiliated with, pyfa. CCP is in no way responsible for the content on or functioning of this program, nor can it be liable for any damage arising from the use of this program.
|
||||
|
||||
@@ -29,7 +29,8 @@ added_files = [
|
||||
|
||||
|
||||
import_these = [
|
||||
'numpy.core._dtype_ctypes' # https://github.com/pyinstaller/pyinstaller/issues/3982
|
||||
'numpy.core._dtype_ctypes', # https://github.com/pyinstaller/pyinstaller/issues/3982
|
||||
'sqlalchemy.ext.baked' # windows build doesn't launch without if when using sqlalchemy 1.3.x
|
||||
]
|
||||
|
||||
icon = os.path.join(os.getcwd(), "dist_assets", "mac", "pyfa.icns")
|
||||
@@ -86,4 +87,4 @@ app = BUNDLE(
|
||||
'CFBundleDisplayName': 'pyfa',
|
||||
'CFBundleIdentifier': 'org.pyfaorg.pyfa',
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@@ -17,7 +17,7 @@ added_files = [
|
||||
('../../imgs/gui/*.gif', 'imgs/gui'),
|
||||
('../../imgs/icons/*.png', 'imgs/icons'),
|
||||
('../../imgs/renders/*.png', 'imgs/renders'),
|
||||
('../../service/jargon/*.yaml', 'service/jargon'),
|
||||
('../../service/jargon/*.yaml', 'service/jargon'),
|
||||
('../../dist_assets/win/pyfa.ico', '.'),
|
||||
('../../dist_assets/win/pyfa.exe.manifest', '.'),
|
||||
('../../dist_assets/win/Microsoft.VC90.CRT.manifest', '.'),
|
||||
@@ -29,7 +29,8 @@ added_files = [
|
||||
]
|
||||
|
||||
import_these = [
|
||||
'numpy.core._dtype_ctypes' # https://github.com/pyinstaller/pyinstaller/issues/3982
|
||||
'numpy.core._dtype_ctypes', # https://github.com/pyinstaller/pyinstaller/issues/3982
|
||||
'sqlalchemy.ext.baked' # windows build doesn't launch without if when using sqlalchemy 1.3.x
|
||||
]
|
||||
|
||||
# Walk directories that do dynamic importing
|
||||
|
||||
@@ -93,3 +93,11 @@ class SpoolType(IntEnum):
|
||||
SCALE = 0 # [0..1]
|
||||
TIME = 1 # Expressed via time in seconds since spool up started
|
||||
CYCLES = 2 # Expressed in amount of cycles since spool up started
|
||||
|
||||
|
||||
@unique
|
||||
class FitSystemSecurity(IntEnum):
|
||||
HISEC = 0
|
||||
LOWSEC = 1
|
||||
NULLSEC = 2
|
||||
WSPACE = 3
|
||||
|
||||
15
eos/db/migrations/upgrade31.py
Normal file
15
eos/db/migrations/upgrade31.py
Normal file
@@ -0,0 +1,15 @@
|
||||
"""
|
||||
Migration 31
|
||||
|
||||
- added fit system security column
|
||||
"""
|
||||
|
||||
|
||||
import sqlalchemy
|
||||
|
||||
|
||||
def upgrade(saveddata_engine):
|
||||
try:
|
||||
saveddata_engine.execute("SELECT systemSecurity FROM fits LIMIT 1")
|
||||
except sqlalchemy.exc.DatabaseError:
|
||||
saveddata_engine.execute("ALTER TABLE fits ADD COLUMN systemSecurity INT")
|
||||
@@ -44,6 +44,7 @@ from eos.saveddata.module import Module
|
||||
from eos.saveddata.targetResists import TargetResists
|
||||
from eos.saveddata.user import User
|
||||
|
||||
|
||||
fits_table = Table("fits", saveddata_meta,
|
||||
Column("ID", Integer, primary_key=True),
|
||||
Column("ownerID", ForeignKey("users.ID"), nullable=True, index=True),
|
||||
@@ -59,7 +60,8 @@ fits_table = Table("fits", saveddata_meta,
|
||||
Column("notes", String, nullable=True),
|
||||
Column("ignoreRestrictions", Boolean, default=0),
|
||||
Column("created", DateTime, nullable=True, default=datetime.datetime.now),
|
||||
Column("modified", DateTime, nullable=True, default=datetime.datetime.now, onupdate=datetime.datetime.now)
|
||||
Column("modified", DateTime, nullable=True, default=datetime.datetime.now, onupdate=datetime.datetime.now),
|
||||
Column("systemSecurity", Integer, nullable=True)
|
||||
)
|
||||
|
||||
projectedFits_table = Table("projectedFits", saveddata_meta,
|
||||
|
||||
@@ -267,7 +267,7 @@ class HandledImplantList(HandledList):
|
||||
HandledList.insert(self, idx, implant)
|
||||
self.remove(implant)
|
||||
raise HandledListActionError(implant)
|
||||
HandledList.append(self, implant)
|
||||
HandledList.insert(self, idx, implant)
|
||||
|
||||
def makeRoom(self, implant):
|
||||
# if needed, remove booster that was occupying slot
|
||||
@@ -308,7 +308,7 @@ class HandledBoosterList(HandledList):
|
||||
HandledList.insert(self, idx, booster)
|
||||
self.remove(booster)
|
||||
raise HandledListActionError(booster)
|
||||
HandledList.append(self, booster)
|
||||
HandledList.insert(self, idx, booster)
|
||||
|
||||
def makeRoom(self, booster):
|
||||
# if needed, remove booster that was occupying slot
|
||||
|
||||
383
eos/effects.py
383
eos/effects.py
@@ -19,7 +19,7 @@
|
||||
|
||||
|
||||
import eos.config
|
||||
from eos.const import FittingModuleState
|
||||
from eos.const import FittingModuleState, FitSystemSecurity
|
||||
from eos.utils.spoolSupport import SpoolType, SpoolOptions, calculateSpoolup, resolveSpoolOptions
|
||||
|
||||
|
||||
@@ -6739,7 +6739,7 @@ class Effect2302(BaseEffect):
|
||||
damageControl
|
||||
|
||||
Used by:
|
||||
Modules from group: Damage Control (22 of 27)
|
||||
Modules from group: Damage Control (24 of 29)
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
@@ -9050,7 +9050,7 @@ class Effect3001(BaseEffect):
|
||||
|
||||
Used by:
|
||||
Modules from group: Missile Launcher Torpedo (22 of 22)
|
||||
Items from market group: Ship Equipment > Turrets & Bays (429 of 883)
|
||||
Items from market group: Ship Equipment > Turrets & Bays (429 of 888)
|
||||
Module: Interdiction Sphere Launcher I
|
||||
"""
|
||||
|
||||
@@ -9113,7 +9113,7 @@ class Effect3025(BaseEffect):
|
||||
Used by:
|
||||
Modules from group: Energy Weapon (101 of 214)
|
||||
Modules from group: Hybrid Weapon (105 of 221)
|
||||
Modules from group: Precursor Weapon (15 of 15)
|
||||
Modules from group: Precursor Weapon (18 of 18)
|
||||
Modules from group: Projectile Weapon (99 of 165)
|
||||
"""
|
||||
|
||||
@@ -10027,16 +10027,16 @@ class Effect3380(BaseEffect):
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, module, context):
|
||||
|
||||
if 'projected' in context:
|
||||
fit.ship.increaseItemAttr('warpScrambleStatus', module.getModifiedItemAttr('warpScrambleStrength'))
|
||||
if module.charge is not None and module.charge.ID == 45010:
|
||||
for mod in fit.modules:
|
||||
if not mod.isEmpty and mod.item.requiresSkill('High Speed Maneuvering') and mod.state > FittingModuleState.ONLINE:
|
||||
mod.state = FittingModuleState.ONLINE
|
||||
if not mod.isEmpty and mod.item.requiresSkill('Micro Jump Drive Operation') and mod.state > FittingModuleState.ONLINE:
|
||||
mod.state = FittingModuleState.ONLINE
|
||||
if module.charge is not None:
|
||||
if module.charge.ID in (29003, 45010):
|
||||
fit.ship.increaseItemAttr('warpScrambleStatus', module.getModifiedItemAttr('warpScrambleStrength'))
|
||||
if module.charge.ID == 45010:
|
||||
fit.modules.filteredItemIncrease(
|
||||
lambda mod: mod.item.requiresSkill('High Speed Maneuvering') or mod.item.requiresSkill('Micro Jump Drive Operation'),
|
||||
'activationBlocked', 1)
|
||||
else:
|
||||
fit.ship.forceItemAttr('disallowAssistance', 1)
|
||||
if module.charge is None:
|
||||
fit.ship.boostItemAttr('mass', module.getModifiedItemAttr('massBonusPercentage'))
|
||||
fit.ship.boostItemAttr('signatureRadius', module.getModifiedItemAttr('signatureRadiusBonus'))
|
||||
@@ -10045,8 +10045,6 @@ class Effect3380(BaseEffect):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == 'Propulsion Module',
|
||||
'speedFactor', module.getModifiedItemAttr('speedFactorBonus'))
|
||||
|
||||
fit.ship.forceItemAttr('disallowAssistance', 1)
|
||||
|
||||
|
||||
class Effect3392(BaseEffect):
|
||||
"""
|
||||
@@ -16287,9 +16285,9 @@ class Effect4902(BaseEffect):
|
||||
MWDSignatureRadiusRoleBonus
|
||||
|
||||
Used by:
|
||||
Ships from group: Assault Frigate (8 of 12)
|
||||
Ships from group: Command Destroyer (4 of 4)
|
||||
Ships from group: Heavy Assault Cruiser (8 of 11)
|
||||
Ships from group: Assault Frigate (9 of 13)
|
||||
Ships from group: Command Destroyer (4 of 5)
|
||||
Ships from group: Heavy Assault Cruiser (9 of 12)
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
@@ -23394,16 +23392,9 @@ class Effect5934(BaseEffect):
|
||||
return
|
||||
|
||||
fit.ship.increaseItemAttr('warpScrambleStatus', module.getModifiedItemAttr('warpScrambleStrength'))
|
||||
|
||||
# this is such a dirty hack
|
||||
for mod in fit.modules:
|
||||
if not mod.isEmpty and mod.state > FittingModuleState.ONLINE and (
|
||||
mod.item.requiresSkill('Micro Jump Drive Operation') or
|
||||
mod.item.requiresSkill('High Speed Maneuvering')
|
||||
):
|
||||
mod.state = FittingModuleState.ONLINE
|
||||
if not mod.isEmpty and mod.item.requiresSkill('Micro Jump Drive Operation') and mod.state > FittingModuleState.ONLINE:
|
||||
mod.state = FittingModuleState.ONLINE
|
||||
fit.modules.filteredItemIncrease(
|
||||
lambda mod: mod.item.requiresSkill('High Speed Maneuvering') or mod.item.requiresSkill('Micro Jump Drive Operation'),
|
||||
'activationBlocked', module.getModifiedItemAttr('activationBlockedStrenght'))
|
||||
|
||||
|
||||
class Effect5938(BaseEffect):
|
||||
@@ -25239,7 +25230,7 @@ class Effect6214(BaseEffect):
|
||||
roleBonusCDLinksPGReduction
|
||||
|
||||
Used by:
|
||||
Ships from group: Command Destroyer (4 of 4)
|
||||
Ships from group: Command Destroyer (5 of 5)
|
||||
Ship: Porpoise
|
||||
"""
|
||||
|
||||
@@ -25292,12 +25283,9 @@ class Effect6222(BaseEffect):
|
||||
def handler(fit, module, context):
|
||||
if 'projected' in context:
|
||||
fit.ship.increaseItemAttr('warpScrambleStatus', module.getModifiedItemAttr('warpScrambleStrength'))
|
||||
if module.charge is not None and module.charge.ID == 47336:
|
||||
for mod in fit.modules:
|
||||
if not mod.isEmpty and mod.item.requiresSkill('High Speed Maneuvering') and mod.state > FittingModuleState.ONLINE:
|
||||
mod.state = FittingModuleState.ONLINE
|
||||
if not mod.isEmpty and mod.item.requiresSkill('Micro Jump Drive Operation') and mod.state > FittingModuleState.ONLINE:
|
||||
mod.state = FittingModuleState.ONLINE
|
||||
fit.modules.filteredItemIncrease(
|
||||
lambda mod: mod.item.requiresSkill('High Speed Maneuvering') or mod.item.requiresSkill('Micro Jump Drive Operation'),
|
||||
'activationBlocked', module.getModifiedItemAttr('activationBlockedStrenght'))
|
||||
|
||||
|
||||
class Effect6230(BaseEffect):
|
||||
@@ -25824,8 +25812,7 @@ class Effect6315(BaseEffect):
|
||||
eliteBonusCommandDestroyerSkirmish1
|
||||
|
||||
Used by:
|
||||
Ship: Bifrost
|
||||
Ship: Magus
|
||||
Ships from group: Command Destroyer (3 of 5)
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
@@ -25874,7 +25861,7 @@ class Effect6317(BaseEffect):
|
||||
eliteBonusCommandDestroyerMJFGspool2
|
||||
|
||||
Used by:
|
||||
Ships from group: Command Destroyer (4 of 4)
|
||||
Ships from group: Command Destroyer (5 of 5)
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
@@ -26147,8 +26134,7 @@ class Effect6334(BaseEffect):
|
||||
eliteBonusCommandDestroyerInfo1
|
||||
|
||||
Used by:
|
||||
Ship: Pontifex
|
||||
Ship: Stork
|
||||
Ships from group: Command Destroyer (3 of 5)
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
@@ -28908,7 +28894,7 @@ class Effect6581(BaseEffect):
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, src, context):
|
||||
# Remote effect bonuses (duration / amount / range / fallout)
|
||||
# Remote effect bonuses (duration / amount / range / falloff)
|
||||
for skill, amtAttr, stack in (
|
||||
('Capital Remote Armor Repair Systems', 'armorDamageAmount', True),
|
||||
('Capital Shield Emission Systems', 'shieldBonus', True),
|
||||
@@ -28924,14 +28910,15 @@ class Effect6581(BaseEffect):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill(skill), 'falloffEffectiveness',
|
||||
src.getModifiedItemAttr('siegeRemoteLogisticsRangeBonus'), stackingPenalties=True)
|
||||
|
||||
# Local armor/shield rep effects (duration / amoutn)
|
||||
# Local armor/shield rep effects (duration / amount)
|
||||
for skill, amtAttr in (
|
||||
('Capital Shield Operation', 'shieldBonus'),
|
||||
('Capital Repair Systems', 'armorDamageAmount')):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill(skill), 'duration',
|
||||
src.getModifiedItemAttr('siegeLocalLogisticsDurationBonus'))
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill(skill), amtAttr,
|
||||
src.getModifiedItemAttr('siegeLocalLogisticsAmountBonus'))
|
||||
src.getModifiedItemAttr('siegeLocalLogisticsAmountBonus'),
|
||||
stackingPenalties=True)
|
||||
|
||||
# Speed bonus
|
||||
fit.ship.boostItemAttr('maxVelocity', src.getModifiedItemAttr('speedFactor'), stackingPenalties=True)
|
||||
@@ -30521,7 +30508,14 @@ class Effect6672(BaseEffect):
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, module, context):
|
||||
secModifier = module.getModifiedItemAttr('securityModifier')
|
||||
secMap = {
|
||||
FitSystemSecurity.HISEC: 'hiSecModifier',
|
||||
FitSystemSecurity.LOWSEC: 'lowSecModifier',
|
||||
FitSystemSecurity.NULLSEC: 'nullSecModifier',
|
||||
FitSystemSecurity.WSPACE: 'nullSecModifier'}
|
||||
fitSec = fit.getSystemSecurity()
|
||||
attrName = secMap[fitSec]
|
||||
secModifier = module.getModifiedItemAttr(attrName)
|
||||
module.multiplyItemAttr('structureRigDoomsdayDamageLossTargetBonus', secModifier)
|
||||
module.multiplyItemAttr('structureRigScanResBonus', secModifier)
|
||||
module.multiplyItemAttr('structureRigPDRangeBonus', secModifier)
|
||||
@@ -32257,7 +32251,7 @@ class Effect6845(BaseEffect):
|
||||
shipBonusCommandDestroyerRole1DefenderBonus
|
||||
|
||||
Used by:
|
||||
Ships from group: Command Destroyer (4 of 4)
|
||||
Ships from group: Command Destroyer (4 of 5)
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
@@ -33806,10 +33800,10 @@ class Effect6994(BaseEffect):
|
||||
|
||||
class Effect6995(BaseEffect):
|
||||
"""
|
||||
targetABCAttack
|
||||
targetDisintegratorAttack
|
||||
|
||||
Used by:
|
||||
Modules from group: Precursor Weapon (15 of 15)
|
||||
Modules from group: Precursor Weapon (18 of 18)
|
||||
"""
|
||||
|
||||
type = 'active'
|
||||
@@ -33973,6 +33967,7 @@ class Effect7012(BaseEffect):
|
||||
|
||||
Used by:
|
||||
Variations of module: Assault Damage Control I (5 of 5)
|
||||
Module: Abyssal Assault Damage Control
|
||||
"""
|
||||
|
||||
runTime = 'early'
|
||||
@@ -34149,6 +34144,7 @@ class Effect7026(BaseEffect):
|
||||
@staticmethod
|
||||
def handler(fit, src, context, *args, **kwargs):
|
||||
src.boostItemAttr('maxRange', src.getModifiedChargeAttr('warpScrambleRangeBonus'))
|
||||
src.forceItemAttr('activationBlockedStrenght', src.getModifiedChargeAttr('activationBlockedStrenght'))
|
||||
|
||||
|
||||
class Effect7027(BaseEffect):
|
||||
@@ -34856,7 +34852,7 @@ class Effect7077(BaseEffect):
|
||||
disintegratorWeaponDamageMultiply
|
||||
|
||||
Used by:
|
||||
Modules from group: Entropic Radiation Sink (4 of 4)
|
||||
Modules from group: Entropic Radiation Sink (6 of 6)
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
@@ -34873,7 +34869,7 @@ class Effect7078(BaseEffect):
|
||||
disintegratorWeaponSpeedMultiply
|
||||
|
||||
Used by:
|
||||
Modules from group: Entropic Radiation Sink (4 of 4)
|
||||
Modules from group: Entropic Radiation Sink (6 of 6)
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
@@ -34922,8 +34918,8 @@ class Effect7085(BaseEffect):
|
||||
shipbonusPCTDamagePC1
|
||||
|
||||
Used by:
|
||||
Variations of ship: Vedmak (2 of 2)
|
||||
Ship: Tiamat
|
||||
Ship: Vedmak
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
@@ -34939,8 +34935,8 @@ class Effect7086(BaseEffect):
|
||||
shipbonusPCTTrackingPC2
|
||||
|
||||
Used by:
|
||||
Variations of ship: Vedmak (2 of 2)
|
||||
Ship: Tiamat
|
||||
Ship: Vedmak
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
@@ -34956,7 +34952,6 @@ class Effect7087(BaseEffect):
|
||||
shipbonusPCTOptimalPF2
|
||||
|
||||
Used by:
|
||||
Ship: Damavik
|
||||
Ship: Hydra
|
||||
"""
|
||||
|
||||
@@ -34973,7 +34968,7 @@ class Effect7088(BaseEffect):
|
||||
shipbonusPCTDamagePF1
|
||||
|
||||
Used by:
|
||||
Ship: Damavik
|
||||
Variations of ship: Damavik (2 of 2)
|
||||
Ship: Hydra
|
||||
"""
|
||||
|
||||
@@ -35005,13 +35000,13 @@ class Effect7092(BaseEffect):
|
||||
shipBonusRemoteRepCapNeedRoleBonus2
|
||||
|
||||
Used by:
|
||||
Ship: Damavik
|
||||
Variations of ship: Damavik (2 of 2)
|
||||
Variations of ship: Kikimora (2 of 2)
|
||||
Variations of ship: Vedmak (2 of 2)
|
||||
Ship: Drekavac
|
||||
Ship: Hydra
|
||||
Ship: Kikimora
|
||||
Ship: Leshak
|
||||
Ship: Tiamat
|
||||
Ship: Vedmak
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
@@ -35027,14 +35022,14 @@ class Effect7093(BaseEffect):
|
||||
shipBonusSmartbombCapNeedRoleBonus2
|
||||
|
||||
Used by:
|
||||
Variations of ship: Damavik (2 of 2)
|
||||
Variations of ship: Kikimora (2 of 2)
|
||||
Variations of ship: Rodiva (2 of 2)
|
||||
Ship: Damavik
|
||||
Variations of ship: Vedmak (2 of 2)
|
||||
Ship: Drekavac
|
||||
Ship: Hydra
|
||||
Ship: Kikimora
|
||||
Ship: Leshak
|
||||
Ship: Tiamat
|
||||
Ship: Vedmak
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
@@ -35050,13 +35045,13 @@ class Effect7094(BaseEffect):
|
||||
shipBonusRemoteRepMaxRangeRoleBonus1
|
||||
|
||||
Used by:
|
||||
Ship: Damavik
|
||||
Variations of ship: Damavik (2 of 2)
|
||||
Variations of ship: Kikimora (2 of 2)
|
||||
Variations of ship: Vedmak (2 of 2)
|
||||
Ship: Drekavac
|
||||
Ship: Hydra
|
||||
Ship: Kikimora
|
||||
Ship: Leshak
|
||||
Ship: Tiamat
|
||||
Ship: Vedmak
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
@@ -35088,7 +35083,7 @@ class Effect7111(BaseEffect):
|
||||
systemSmallPrecursorTurretDamage
|
||||
|
||||
Used by:
|
||||
Celestials named like: Wolf Rayet Effect Beacon Class (5 of 6)
|
||||
Celestials named like: Wolf Rayet Effect Beacon Class (6 of 6)
|
||||
"""
|
||||
|
||||
runTime = 'early'
|
||||
@@ -35106,13 +35101,13 @@ class Effect7112(BaseEffect):
|
||||
shipBonusNeutCapNeedRoleBonus2
|
||||
|
||||
Used by:
|
||||
Ship: Damavik
|
||||
Variations of ship: Damavik (2 of 2)
|
||||
Variations of ship: Kikimora (2 of 2)
|
||||
Variations of ship: Vedmak (2 of 2)
|
||||
Ship: Drekavac
|
||||
Ship: Hydra
|
||||
Ship: Kikimora
|
||||
Ship: Leshak
|
||||
Ship: Tiamat
|
||||
Ship: Vedmak
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
@@ -35218,7 +35213,7 @@ class Effect7154(BaseEffect):
|
||||
shipBonusPD1DisintegratorDamage
|
||||
|
||||
Used by:
|
||||
Ship: Kikimora
|
||||
Variations of ship: Kikimora (2 of 2)
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
@@ -35252,7 +35247,7 @@ class Effect7156(BaseEffect):
|
||||
smallDisintegratorMaxRangeBonus
|
||||
|
||||
Used by:
|
||||
Ship: Kikimora
|
||||
Variations of ship: Kikimora (2 of 2)
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
@@ -35268,7 +35263,7 @@ class Effect7157(BaseEffect):
|
||||
shipBonusPD2DisintegratorMaxRange
|
||||
|
||||
Used by:
|
||||
Ship: Kikimora
|
||||
Variations of ship: Kikimora (2 of 2)
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
@@ -35624,3 +35619,255 @@ class Effect7186(BaseEffect):
|
||||
def handler(fit, ship, context):
|
||||
fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill('Medium Drone Operation'),
|
||||
'armorHP', ship.getModifiedItemAttr('shipBonusRole8'))
|
||||
|
||||
|
||||
class Effect7193(BaseEffect):
|
||||
"""
|
||||
systemMiningCycleTimeBonus
|
||||
|
||||
Used by:
|
||||
Celestials named like: Invasion Effects (3 of 3)
|
||||
"""
|
||||
|
||||
runTime = 'early'
|
||||
type = ('projected', 'passive')
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, beacon, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill('Mining'),
|
||||
'duration', beacon.getModifiedItemAttr('miningDurationMultiplier'),
|
||||
stackingPenalties=True)
|
||||
|
||||
fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill('Mining'),
|
||||
'duration', beacon.getModifiedItemAttr('miningDurationMultiplier'),
|
||||
stackingPenalties=True)
|
||||
|
||||
|
||||
class Effect7194(BaseEffect):
|
||||
"""
|
||||
systemHullHPBonusPercent
|
||||
|
||||
Used by:
|
||||
Celestials named like: Invasion Effects (3 of 3)
|
||||
"""
|
||||
|
||||
runTime = 'early'
|
||||
type = ('projected', 'passive')
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, beacon, context):
|
||||
fit.ship.boostItemAttr('hp', beacon.getModifiedItemAttr('hullHpBonus'), stackingPenalties=True)
|
||||
|
||||
|
||||
class Effect7195(BaseEffect):
|
||||
"""
|
||||
systemAgilityBonusPercent
|
||||
|
||||
Used by:
|
||||
Celestials named like: Invasion Effects (3 of 3)
|
||||
"""
|
||||
|
||||
runTime = 'early'
|
||||
type = ('projected', 'passive')
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, beacon, context):
|
||||
fit.ship.boostItemAttr('agility', beacon.getModifiedItemAttr('agilityBonus'), stackingPenalties=True)
|
||||
|
||||
|
||||
class Effect7202(BaseEffect):
|
||||
"""
|
||||
systemDroneSpeedBonusPercent
|
||||
|
||||
Used by:
|
||||
Celestials named like: Invasion Effects (3 of 3)
|
||||
"""
|
||||
|
||||
runTime = 'early'
|
||||
type = ('projected', 'passive')
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, beacon, context):
|
||||
fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill('Drones'),
|
||||
'maxVelocity', beacon.getModifiedItemAttr('droneMaxVelocityBonus'),
|
||||
stackingPenalties=True)
|
||||
|
||||
|
||||
class Effect7203(BaseEffect):
|
||||
"""
|
||||
systemDroneDamageBonusPercent
|
||||
|
||||
Used by:
|
||||
Celestials named like: Invasion Effects (3 of 3)
|
||||
"""
|
||||
|
||||
runTime = 'early'
|
||||
type = ('projected', 'passive')
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, beacon, context):
|
||||
fit.drones.filteredItemBoost(lambda drone: drone.item.requiresSkill('Drones'),
|
||||
'damageMultiplier', beacon.getModifiedItemAttr('droneDamageBonus'),
|
||||
stackingPenalties=True)
|
||||
|
||||
|
||||
class Effect7204(BaseEffect):
|
||||
"""
|
||||
shipArmorEMResistancePF2
|
||||
|
||||
Used by:
|
||||
Variations of ship: Damavik (2 of 2)
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, ship, context):
|
||||
fit.ship.boostItemAttr('armorEmDamageResonance', ship.getModifiedItemAttr('shipBonusPF2'), skill='Precursor Frigate')
|
||||
|
||||
|
||||
class Effect7205(BaseEffect):
|
||||
"""
|
||||
shipArmorKinResistancePF2
|
||||
|
||||
Used by:
|
||||
Variations of ship: Damavik (2 of 2)
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, ship, context):
|
||||
fit.ship.boostItemAttr('armorKineticDamageResonance', ship.getModifiedItemAttr('shipBonusPF2'), skill='Precursor Frigate')
|
||||
|
||||
|
||||
class Effect7206(BaseEffect):
|
||||
"""
|
||||
shipArmorThermResistancePF2
|
||||
|
||||
Used by:
|
||||
Variations of ship: Damavik (2 of 2)
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, ship, context):
|
||||
fit.ship.boostItemAttr('armorThermalDamageResonance', ship.getModifiedItemAttr('shipBonusPF2'), skill='Precursor Frigate')
|
||||
|
||||
|
||||
class Effect7207(BaseEffect):
|
||||
"""
|
||||
shipArmorExpResistancePF2
|
||||
|
||||
Used by:
|
||||
Variations of ship: Damavik (2 of 2)
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, ship, context):
|
||||
fit.ship.boostItemAttr('armorExplosiveDamageResonance', ship.getModifiedItemAttr('shipBonusPF2'), skill='Precursor Frigate')
|
||||
|
||||
|
||||
class Effect7210(BaseEffect):
|
||||
"""
|
||||
shipBonusCommandDestroyerRole2DefenderBonus
|
||||
|
||||
Used by:
|
||||
Ship: Draugur
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, ship, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill('Defender Missiles'),
|
||||
'moduleReactivationDelay', ship.getModifiedItemAttr('shipBonusRole2'))
|
||||
|
||||
|
||||
class Effect7211(BaseEffect):
|
||||
"""
|
||||
shipDmgMultiMaxEliteHeavyGunship1
|
||||
|
||||
Used by:
|
||||
Ship: Ikitursa
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, ship, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill('Medium Precursor Weapon'),
|
||||
'damageMultiplierBonusMax', ship.getModifiedItemAttr('eliteBonusHeavyGunship1'),
|
||||
skill='Heavy Assault Cruisers')
|
||||
|
||||
|
||||
class Effect7216(BaseEffect):
|
||||
"""
|
||||
shipDmgMultiMaxEliteGunship1
|
||||
|
||||
Used by:
|
||||
Ship: Nergal
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, ship, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.requiresSkill('Small Precursor Weapon'),
|
||||
'damageMultiplierBonusMax', ship.getModifiedItemAttr('eliteBonusGunship1'),
|
||||
skill='Assault Frigates')
|
||||
|
||||
|
||||
class Effect7217(BaseEffect):
|
||||
"""
|
||||
shipNosNeutSmartPowerReductionEliteGunship2
|
||||
|
||||
Used by:
|
||||
Ship: Nergal
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, ship, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == 'Energy Neutralizer',
|
||||
'power', ship.getModifiedItemAttr('eliteBonusGunship2'),
|
||||
skill='Assault Frigates')
|
||||
|
||||
|
||||
class Effect7219(BaseEffect):
|
||||
"""
|
||||
shipSmartBombPowerReductionEliteGunship2
|
||||
|
||||
Used by:
|
||||
Ship: Ikitursa
|
||||
Ship: Nergal
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, ship, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == 'Smart Bomb',
|
||||
'power', ship.getModifiedItemAttr('eliteBonusGunship2'),
|
||||
skill='Assault Frigates')
|
||||
|
||||
|
||||
class Effect7222(BaseEffect):
|
||||
"""
|
||||
shipNeutPowerReductionEliteHeavyGunship2
|
||||
|
||||
Used by:
|
||||
Ship: Ikitursa
|
||||
"""
|
||||
|
||||
type = 'passive'
|
||||
|
||||
@staticmethod
|
||||
def handler(fit, ship, context):
|
||||
fit.modules.filteredItemBoost(lambda mod: mod.item.group.name == 'Energy Neutralizer',
|
||||
'power', ship.getModifiedItemAttr('eliteBonusHeavyGunship2'),
|
||||
skill='Heavy Assault Cruisers')
|
||||
|
||||
@@ -250,6 +250,17 @@ class Item(EqBase):
|
||||
|
||||
return self.__attributes
|
||||
|
||||
@property
|
||||
def attribsWithOverrides(self):
|
||||
overrides = self.overrides
|
||||
attribs = {}
|
||||
for aname, attr in self.attributes.items():
|
||||
if aname in overrides:
|
||||
attribs[aname] = overrides[aname]
|
||||
else:
|
||||
attribs[aname] = attr
|
||||
return attribs
|
||||
|
||||
def getAttribute(self, key, default=None):
|
||||
if key in self.attributes:
|
||||
return self.attributes[key].value
|
||||
@@ -479,7 +490,7 @@ class Item(EqBase):
|
||||
|
||||
@property
|
||||
def isModule(self):
|
||||
return self.category.name == 'Module'
|
||||
return self.category.name in ('Module', 'Structure Module')
|
||||
|
||||
@property
|
||||
def isSubsystem(self):
|
||||
|
||||
@@ -218,13 +218,13 @@ class ModifiedAttributeDict(collections.MutableMapping):
|
||||
if attrInfo is None:
|
||||
cappingId = cappingAttrKeyCache[key] = None
|
||||
else:
|
||||
# see GH issue #620
|
||||
cappingId = cappingAttrKeyCache[key] = attrInfo.maxAttributeID
|
||||
cappingId = attrInfo.maxAttributeID
|
||||
if cappingId is None:
|
||||
cappingKey = None
|
||||
else:
|
||||
cappingAttrInfo = getAttributeInfo(cappingId)
|
||||
cappingKey = None if cappingAttrInfo is None else cappingAttrInfo.name
|
||||
cappingAttrKeyCache[key] = cappingKey
|
||||
|
||||
if cappingKey:
|
||||
cappingValue = self.original.get(cappingKey, self.__calculateValue(cappingKey))
|
||||
@@ -238,7 +238,7 @@ class ModifiedAttributeDict(collections.MutableMapping):
|
||||
if force is not None:
|
||||
if cappingValue is not None:
|
||||
force = min(force, cappingValue)
|
||||
if key in (50, 30, 48, 11):
|
||||
if key in ("cpu", "power", "cpuOutput", "powerOutput"):
|
||||
force = round(force, 2)
|
||||
return force
|
||||
# Grab our values if they're there, otherwise we'll take default values
|
||||
@@ -259,11 +259,7 @@ class ModifiedAttributeDict(collections.MutableMapping):
|
||||
dv = attrInfo.defaultValue
|
||||
default = defaultValuesCache[key] = dv if dv is not None else 0.0
|
||||
|
||||
val = self.__intermediary.get(key,
|
||||
self.__preAssigns.get(key,
|
||||
self.getOriginal(key, default)
|
||||
)
|
||||
)
|
||||
val = self.__intermediary.get(key, self.__preAssigns.get(key, self.getOriginal(key, default)))
|
||||
|
||||
# We'll do stuff in the following order:
|
||||
# preIncrease > multiplier > stacking penalized multipliers > postIncrease
|
||||
@@ -293,7 +289,7 @@ class ModifiedAttributeDict(collections.MutableMapping):
|
||||
# Cap value if we have cap defined
|
||||
if cappingValue is not None:
|
||||
val = min(val, cappingValue)
|
||||
if key in (50, 30, 48, 11):
|
||||
if key in ("cpu", "power", "cpuOutput", "powerOutput"):
|
||||
val = round(val, 2)
|
||||
return val
|
||||
|
||||
|
||||
@@ -17,26 +17,27 @@
|
||||
# along with eos. If not, see <http://www.gnu.org/licenses/>.
|
||||
# ===============================================================================
|
||||
|
||||
import datetime
|
||||
import time
|
||||
from copy import deepcopy
|
||||
from itertools import chain
|
||||
from math import sqrt, log, asinh
|
||||
import datetime
|
||||
|
||||
from sqlalchemy.orm import validates, reconstructor
|
||||
from logbook import Logger
|
||||
from math import asinh, log, sqrt
|
||||
from sqlalchemy.orm import reconstructor, validates
|
||||
|
||||
import eos.db
|
||||
from eos import capSim
|
||||
from eos.effectHandlerHelpers import HandledModuleList, HandledDroneCargoList, HandledImplantList, HandledBoosterList, HandledProjectedDroneList, HandledProjectedModList
|
||||
from eos.const import ImplantLocation, CalcType, FittingSlot
|
||||
from eos.saveddata.ship import Ship
|
||||
from eos.saveddata.drone import Drone
|
||||
from eos.const import CalcType, FitSystemSecurity, FittingHardpoint, FittingModuleState, FittingSlot, ImplantLocation
|
||||
from eos.effectHandlerHelpers import (
|
||||
HandledBoosterList, HandledDroneCargoList, HandledImplantList,
|
||||
HandledModuleList, HandledProjectedDroneList, HandledProjectedModList)
|
||||
from eos.saveddata.character import Character
|
||||
from eos.saveddata.citadel import Citadel
|
||||
from eos.const import FittingModuleState, FittingHardpoint
|
||||
from eos.saveddata.module import Module
|
||||
from eos.saveddata.ship import Ship
|
||||
from eos.utils.stats import DmgTypes
|
||||
from logbook import Logger
|
||||
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
@@ -924,8 +925,10 @@ class Fit(object):
|
||||
recalc. Figure out a way to keep track of any changes to slot layout and call this automatically
|
||||
"""
|
||||
if self.ship is None:
|
||||
return
|
||||
return {}
|
||||
|
||||
# Look for any dummies of that type to remove
|
||||
posToRemove = {}
|
||||
for slotType in (FittingSlot.LOW.value, FittingSlot.MED.value, FittingSlot.HIGH.value, FittingSlot.RIG.value, FittingSlot.SUBSYSTEM.value, FittingSlot.SERVICE.value):
|
||||
amount = self.getSlotsFree(slotType, True)
|
||||
if amount > 0:
|
||||
@@ -933,16 +936,17 @@ class Fit(object):
|
||||
self.modules.append(Module.buildEmpty(slotType))
|
||||
|
||||
if amount < 0:
|
||||
# Look for any dummies of that type to remove
|
||||
toRemove = []
|
||||
for mod in self.modules:
|
||||
if mod.isEmpty and mod.slot == slotType:
|
||||
toRemove.append(mod)
|
||||
pos = self.modules.index(mod)
|
||||
posToRemove[pos] = slotType
|
||||
amount += 1
|
||||
if amount == 0:
|
||||
break
|
||||
for mod in toRemove:
|
||||
self.modules.remove(mod)
|
||||
for pos in sorted(posToRemove, reverse=True):
|
||||
mod = self.modules[pos]
|
||||
self.modules.remove(mod)
|
||||
return posToRemove
|
||||
|
||||
def unfill(self):
|
||||
for i in range(len(self.modules) - 1, -1, -1):
|
||||
@@ -1507,6 +1511,28 @@ class Fit(object):
|
||||
|
||||
return True
|
||||
|
||||
def getReleaseLimitForDrone(self, item):
|
||||
if not item.isDrone:
|
||||
return 0
|
||||
bw = round(self.ship.getModifiedItemAttr("droneBandwidth"))
|
||||
volume = round(item.attribsWithOverrides['volume'].value)
|
||||
return int(bw / volume)
|
||||
|
||||
def getStoreLimitForDrone(self, item):
|
||||
if not item.isDrone:
|
||||
return 0
|
||||
bayTotal = round(self.ship.getModifiedItemAttr("droneCapacity"))
|
||||
bayUsed = round(self.droneBayUsed)
|
||||
volume = item.attribsWithOverrides['volume'].value
|
||||
return int((bayTotal - bayUsed) / volume)
|
||||
|
||||
def getSystemSecurity(self):
|
||||
secstatus = self.systemSecurity
|
||||
# Default to nullsec
|
||||
if secstatus is None:
|
||||
secstatus = FitSystemSecurity.NULLSEC
|
||||
return secstatus
|
||||
|
||||
def __deepcopy__(self, memo=None):
|
||||
fitCopy = Fit()
|
||||
# Character and owner are not copied
|
||||
@@ -1518,6 +1544,7 @@ class Fit(object):
|
||||
fitCopy.damagePattern = self.damagePattern
|
||||
fitCopy.targetResists = self.targetResists
|
||||
fitCopy.implantLocation = self.implantLocation
|
||||
fitCopy.systemSecurity = self.systemSecurity
|
||||
fitCopy.notes = self.notes
|
||||
|
||||
toCopy = (
|
||||
|
||||
@@ -550,6 +550,8 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
if not fits and fit.ignoreRestrictions:
|
||||
self.restrictionOverridden = True
|
||||
fits = True
|
||||
elif fits and fit.ignoreRestrictions:
|
||||
self.restrictionOverridden = False
|
||||
|
||||
return fits
|
||||
|
||||
@@ -567,6 +569,8 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
if self.slot == FittingSlot.SUBSYSTEM:
|
||||
subSlot = self.getModifiedItemAttr("subSystemSlot")
|
||||
for mod in fit.modules:
|
||||
if mod is self:
|
||||
continue
|
||||
if mod.getModifiedItemAttr("subSystemSlot") == subSlot:
|
||||
return False
|
||||
|
||||
@@ -601,7 +605,7 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
# Check if we're within bounds
|
||||
if state < -1 or state > 2:
|
||||
return False
|
||||
elif state >= FittingModuleState.ACTIVE and not self.item.isType("active"):
|
||||
elif state >= FittingModuleState.ACTIVE and (not self.item.isType("active") or self.getModifiedItemAttr('activationBlocked') > 0):
|
||||
return False
|
||||
elif state == FittingModuleState.OVERHEATED and not self.item.isType("overheat"):
|
||||
return False
|
||||
@@ -771,28 +775,26 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
context = ("module",)
|
||||
projected = False
|
||||
|
||||
# if gang:
|
||||
# context += ("commandRun",)
|
||||
|
||||
if self.charge is not None:
|
||||
# fix for #82 and it's regression #106
|
||||
if not projected or (self.projected and not forceProjected) or gang:
|
||||
for effect in self.charge.effects.values():
|
||||
if effect.runTime == runTime and \
|
||||
effect.activeByDefault and \
|
||||
(effect.isType("offline") or
|
||||
(effect.isType("passive") and self.state >= FittingModuleState.ONLINE) or
|
||||
(effect.isType("active") and self.state >= FittingModuleState.ACTIVE)) and \
|
||||
(not gang or (gang and effect.isType("gang"))):
|
||||
|
||||
chargeContext = ("moduleCharge",)
|
||||
# For gang effects, we pass in the effect itself as an argument. However, to avoid going through
|
||||
# all the effect files and defining this argument, do a simple try/catch here and be done with it.
|
||||
if (
|
||||
effect.runTime == runTime and
|
||||
effect.activeByDefault and (
|
||||
effect.isType("offline") or
|
||||
(effect.isType("passive") and self.state >= FittingModuleState.ONLINE) or
|
||||
(effect.isType("active") and self.state >= FittingModuleState.ACTIVE)) and
|
||||
(not gang or (gang and effect.isType("gang")))
|
||||
):
|
||||
contexts = ("moduleCharge",)
|
||||
# For gang effects, we pass in the effect itself as an argument. However, to avoid going through all
|
||||
# the effect definitions and defining this argument, do a simple try/catch here and be done with it.
|
||||
# @todo: possibly fix this
|
||||
try:
|
||||
effect.handler(fit, self, chargeContext, effect=effect)
|
||||
effect.handler(fit, self, contexts, effect=effect)
|
||||
except:
|
||||
effect.handler(fit, self, chargeContext)
|
||||
effect.handler(fit, self, contexts)
|
||||
|
||||
if self.item:
|
||||
if self.state >= FittingModuleState.OVERHEATED:
|
||||
@@ -894,7 +896,6 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
|
||||
@staticmethod
|
||||
def getProposedState(mod, click, proposedState=None):
|
||||
# todo: instead of passing in module, make this a instanced function.
|
||||
pyfalog.debug("Get proposed state for module.")
|
||||
if mod.slot == FittingSlot.SUBSYSTEM or mod.isEmpty:
|
||||
return FittingModuleState.ONLINE
|
||||
@@ -914,13 +915,12 @@ class Module(HandledItem, HandledCharge, ItemAttrShortcut, ChargeAttrShortcut):
|
||||
state = FittingModuleState.OFFLINE
|
||||
else:
|
||||
state = transitionMap[currState]
|
||||
if not mod.isValidState(state):
|
||||
state = -1
|
||||
# If passive module tries to transition into online and fails,
|
||||
# put it to passive instead
|
||||
if not mod.isValidState(state) and currState == FittingModuleState.ONLINE:
|
||||
state = FittingModuleState.OFFLINE
|
||||
|
||||
if mod.isValidState(state):
|
||||
return state
|
||||
else:
|
||||
return currState
|
||||
return mod.getMaxState(proposedState=state)
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
item = self.item
|
||||
|
||||
@@ -34,6 +34,7 @@ from gui.toggle_panel import TogglePanel
|
||||
|
||||
|
||||
class AdditionsPane(TogglePanel):
|
||||
|
||||
def __init__(self, parent):
|
||||
|
||||
TogglePanel.__init__(self, parent, force_layout=1)
|
||||
@@ -86,8 +87,8 @@ class AdditionsPane(TogglePanel):
|
||||
|
||||
PANES = ["Drones", "Fighters", "Cargo", "Implants", "Boosters", "Projected", "Command", "Notes"]
|
||||
|
||||
def select(self, name):
|
||||
self.notebook.SetSelection(self.PANES.index(name))
|
||||
def select(self, name, focus=True):
|
||||
self.notebook.SetSelection(self.PANES.index(name), focus=focus)
|
||||
|
||||
def getName(self, idx):
|
||||
return self.PANES[idx]
|
||||
|
||||
@@ -50,8 +50,11 @@ class BitmapLoader(object):
|
||||
|
||||
@classmethod
|
||||
def getStaticBitmap(cls, name, parent, location):
|
||||
bitmap = cls.getBitmap(name or 0, location)
|
||||
if bitmap is None:
|
||||
return None
|
||||
static = wx.StaticBitmap(parent)
|
||||
static.SetBitmap(cls.getBitmap(name or 0, location))
|
||||
static.SetBitmap(bitmap)
|
||||
return static
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -48,6 +48,7 @@ class BoosterViewDrop(wx.DropTarget):
|
||||
|
||||
|
||||
class BoosterView(d.Display):
|
||||
|
||||
DEFAULT_COLS = [
|
||||
"State",
|
||||
"attr:boosterness",
|
||||
@@ -58,14 +59,14 @@ class BoosterView(d.Display):
|
||||
]
|
||||
|
||||
def __init__(self, parent):
|
||||
d.Display.__init__(self, parent, style=wx.LC_SINGLE_SEL | wx.BORDER_NONE)
|
||||
d.Display.__init__(self, parent, style=wx.BORDER_NONE)
|
||||
|
||||
self.lastFitId = None
|
||||
|
||||
self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged)
|
||||
self.mainFrame.Bind(ITEM_SELECTED, self.addItem)
|
||||
|
||||
self.Bind(wx.EVT_LEFT_DCLICK, self.removeItem)
|
||||
self.Bind(wx.EVT_LEFT_DCLICK, self.onLeftDoubleClick)
|
||||
self.Bind(wx.EVT_LEFT_DOWN, self.click)
|
||||
self.Bind(wx.EVT_KEY_UP, self.kbEvent)
|
||||
|
||||
@@ -87,11 +88,14 @@ class BoosterView(d.Display):
|
||||
|
||||
def kbEvent(self, event):
|
||||
keycode = event.GetKeyCode()
|
||||
if keycode in (wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE):
|
||||
row = self.GetFirstSelected()
|
||||
if row != -1:
|
||||
self.removeBooster(self.boosters[self.GetItemData(row)])
|
||||
|
||||
mstate = wx.GetMouseState()
|
||||
if keycode == wx.WXK_ESCAPE and mstate.GetModifiers() == wx.MOD_NONE:
|
||||
self.unselectAll()
|
||||
elif keycode == 65 and mstate.GetModifiers() == wx.MOD_CONTROL:
|
||||
self.selectAll()
|
||||
elif keycode in (wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE) and mstate.GetModifiers() == wx.MOD_NONE:
|
||||
boosters = self.getSelectedBoosters()
|
||||
self.removeBoosters(boosters)
|
||||
event.Skip()
|
||||
|
||||
def fitChanged(self, event):
|
||||
@@ -120,7 +124,7 @@ class BoosterView(d.Display):
|
||||
if item != -1:
|
||||
self.EnsureVisible(item)
|
||||
|
||||
self.deselectItems()
|
||||
self.unselectAll()
|
||||
|
||||
self.update(self.boosters)
|
||||
event.Skip()
|
||||
@@ -143,32 +147,78 @@ class BoosterView(d.Display):
|
||||
self.mainFrame.additionsPane.select('Boosters')
|
||||
event.Skip()
|
||||
|
||||
def removeItem(self, event):
|
||||
def onLeftDoubleClick(self, event):
|
||||
row, _ = self.HitTest(event.Position)
|
||||
if row != -1:
|
||||
col = self.getColumn(event.Position)
|
||||
if col != self.getColIndex(State):
|
||||
self.removeBooster(self.boosters[self.GetItemData(row)])
|
||||
try:
|
||||
booster = self.boosters[row]
|
||||
except IndexError:
|
||||
return
|
||||
self.removeBoosters([booster])
|
||||
|
||||
def removeBooster(self, booster):
|
||||
def removeBoosters(self, boosters):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveBoosterCommand(fitID=fitID, position=self.original.index(booster)))
|
||||
positions = []
|
||||
for booster in boosters:
|
||||
if booster in self.original:
|
||||
positions.append(self.original.index(booster))
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveBoostersCommand(fitID=fitID, positions=positions))
|
||||
|
||||
def click(self, event):
|
||||
event.Skip()
|
||||
row, _ = self.HitTest(event.Position)
|
||||
if row != -1:
|
||||
mainRow, _ = self.HitTest(event.Position)
|
||||
if mainRow != -1:
|
||||
col = self.getColumn(event.Position)
|
||||
if col == self.getColIndex(State):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
booster = self.boosters[self.GetItemData(row)]
|
||||
self.mainFrame.command.Submit(cmd.GuiToggleBoosterStateCommand(fitID=fitID, position=self.original.index(booster)))
|
||||
try:
|
||||
mainBooster = self.boosters[mainRow]
|
||||
except IndexError:
|
||||
return
|
||||
if mainBooster in self.original:
|
||||
mainPosition = self.original.index(mainBooster)
|
||||
positions = []
|
||||
for row in self.getSelectedRows():
|
||||
try:
|
||||
booster = self.boosters[row]
|
||||
except IndexError:
|
||||
continue
|
||||
if booster in self.original:
|
||||
positions.append(self.original.index(booster))
|
||||
if mainPosition not in positions:
|
||||
positions = [mainPosition]
|
||||
self.mainFrame.command.Submit(cmd.GuiToggleBoosterStatesCommand(
|
||||
fitID=fitID,
|
||||
mainPosition=mainPosition,
|
||||
positions=positions))
|
||||
return
|
||||
event.Skip()
|
||||
|
||||
def spawnMenu(self, event):
|
||||
sel = self.GetFirstSelected()
|
||||
if sel != -1:
|
||||
booster = self.boosters[sel]
|
||||
srcContext = "boosterItem"
|
||||
itemContext = "Booster"
|
||||
menu = ContextMenu.getMenu((booster,), (srcContext, itemContext))
|
||||
selection = self.getSelectedBoosters()
|
||||
clickedPos = self.getRowByAbs(event.Position)
|
||||
mainBooster = None
|
||||
if clickedPos != -1:
|
||||
try:
|
||||
booster = self.boosters[clickedPos]
|
||||
except IndexError:
|
||||
pass
|
||||
else:
|
||||
if booster in self.original:
|
||||
mainBooster = booster
|
||||
sourceContext = "boosterItem"
|
||||
itemContext = None if mainBooster is None else "Booster"
|
||||
menu = ContextMenu.getMenu(mainBooster, selection, (sourceContext, itemContext))
|
||||
if menu:
|
||||
self.PopupMenu(menu)
|
||||
|
||||
def getSelectedBoosters(self):
|
||||
boosters = []
|
||||
for row in self.getSelectedRows():
|
||||
try:
|
||||
booster = self.boosters[row]
|
||||
except IndexError:
|
||||
continue
|
||||
boosters.append(booster)
|
||||
return boosters
|
||||
|
||||
@@ -19,14 +19,14 @@
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
|
||||
import gui.display as d
|
||||
from gui.builtinViewColumns.state import State
|
||||
from gui.contextMenu import ContextMenu
|
||||
import gui.fitCommands as cmd
|
||||
import gui.globalEvents as GE
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.utils.staticHelpers import DragDropHelper
|
||||
from service.fit import Fit
|
||||
from service.market import Market
|
||||
import gui.fitCommands as cmd
|
||||
|
||||
|
||||
class CargoViewDrop(wx.DropTarget):
|
||||
@@ -53,12 +53,12 @@ class CargoView(d.Display):
|
||||
"Price"]
|
||||
|
||||
def __init__(self, parent):
|
||||
d.Display.__init__(self, parent, style=wx.LC_SINGLE_SEL | wx.BORDER_NONE)
|
||||
d.Display.__init__(self, parent, style=wx.BORDER_NONE)
|
||||
|
||||
self.lastFitId = None
|
||||
|
||||
self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged)
|
||||
self.Bind(wx.EVT_LEFT_DCLICK, self.removeItem)
|
||||
self.Bind(wx.EVT_LEFT_DCLICK, self.onLeftDoubleClick)
|
||||
self.Bind(wx.EVT_KEY_UP, self.kbEvent)
|
||||
|
||||
self.SetDropTarget(CargoViewDrop(self.handleListDrag))
|
||||
@@ -78,18 +78,25 @@ class CargoView(d.Display):
|
||||
if data[0] == "fitting":
|
||||
self.swapModule(x, y, int(data[1]))
|
||||
elif data[0] == "market":
|
||||
fit = self.mainFrame.getActiveFit()
|
||||
if fit:
|
||||
self.mainFrame.command.Submit(cmd.GuiAddCargoCommand(fit, int(data[1]), 1))
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
if fitID:
|
||||
self.mainFrame.command.Submit(cmd.GuiAddCargoCommand(
|
||||
fitID=fitID, itemID=int(data[1]), amount=1))
|
||||
|
||||
def startDrag(self, event):
|
||||
row = event.GetIndex()
|
||||
|
||||
if row != -1:
|
||||
data = wx.TextDataObject()
|
||||
dataStr = "cargo:{}".format(self.cargo[row].itemID)
|
||||
try:
|
||||
dataStr = "cargo:{}".format(self.cargo[row].itemID)
|
||||
except IndexError:
|
||||
return
|
||||
data.SetText(dataStr)
|
||||
|
||||
self.unselectAll()
|
||||
self.Select(row, True)
|
||||
|
||||
dropSource = wx.DropSource(self)
|
||||
dropSource.SetData(data)
|
||||
DragDropHelper.data = dataStr
|
||||
@@ -97,12 +104,14 @@ class CargoView(d.Display):
|
||||
|
||||
def kbEvent(self, event):
|
||||
keycode = event.GetKeyCode()
|
||||
if keycode in (wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE):
|
||||
row = self.GetFirstSelected()
|
||||
if row != -1:
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
cargo = self.cargo[self.GetItemData(row)]
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveCargoCommand(fitID=fitID, itemID=cargo.itemID))
|
||||
mstate = wx.GetMouseState()
|
||||
if keycode == wx.WXK_ESCAPE and mstate.GetModifiers() == wx.MOD_NONE:
|
||||
self.unselectAll()
|
||||
elif keycode == 65 and mstate.GetModifiers() == wx.MOD_CONTROL:
|
||||
self.selectAll()
|
||||
elif keycode in (wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE) and mstate.GetModifiers() == wx.MOD_NONE:
|
||||
cargos = self.getSelectedCargos()
|
||||
self.removeCargos(cargos)
|
||||
event.Skip()
|
||||
|
||||
def swapModule(self, x, y, modIdx):
|
||||
@@ -111,11 +120,19 @@ class CargoView(d.Display):
|
||||
fit = sFit.getFit(self.mainFrame.getActiveFit())
|
||||
dstRow, _ = self.HitTest((x, y))
|
||||
|
||||
if dstRow > -1:
|
||||
try:
|
||||
dstCargoItemID = getattr(self.cargo[dstRow], 'itemID', None)
|
||||
except IndexError:
|
||||
dstCargoItemID = None
|
||||
else:
|
||||
dstCargoItemID = None
|
||||
|
||||
self.mainFrame.command.Submit(cmd.GuiLocalModuleToCargoCommand(
|
||||
fitID=self.mainFrame.getActiveFit(),
|
||||
modPosition=fit.modules[modIdx].modPosition,
|
||||
cargoItemID=self.cargo[dstRow].itemID if dstRow > -1 else None,
|
||||
copy=wx.GetMouseState().CmdDown()))
|
||||
modPosition=modIdx,
|
||||
cargoItemID=dstCargoItemID,
|
||||
copy=wx.GetMouseState().GetModifiers() == wx.MOD_CONTROL))
|
||||
|
||||
def fitChanged(self, event):
|
||||
sFit = Fit.getInstance()
|
||||
@@ -143,28 +160,53 @@ class CargoView(d.Display):
|
||||
if item != -1:
|
||||
self.EnsureVisible(item)
|
||||
|
||||
self.deselectItems()
|
||||
self.unselectAll()
|
||||
|
||||
self.populate(self.cargo)
|
||||
self.refresh(self.cargo)
|
||||
event.Skip()
|
||||
|
||||
def removeItem(self, event):
|
||||
def onLeftDoubleClick(self, event):
|
||||
row, _ = self.HitTest(event.Position)
|
||||
if row != -1:
|
||||
col = self.getColumn(event.Position)
|
||||
if col != self.getColIndex(State):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
cargo = self.cargo[self.GetItemData(row)]
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveCargoCommand(fitID, cargo.itemID))
|
||||
try:
|
||||
cargo = self.cargo[row]
|
||||
except IndexError:
|
||||
return
|
||||
self.removeCargos([cargo])
|
||||
|
||||
def removeCargos(self, cargos):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
itemIDs = []
|
||||
for cargo in cargos:
|
||||
if cargo in self.original:
|
||||
itemIDs.append(cargo.itemID)
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveCargosCommand(fitID=fitID, itemIDs=itemIDs))
|
||||
|
||||
def spawnMenu(self, event):
|
||||
sel = self.GetFirstSelected()
|
||||
if sel != -1:
|
||||
cargo = self.cargo[sel]
|
||||
sMkt = Market.getInstance()
|
||||
sourceContext = "cargoItem"
|
||||
itemContext = sMkt.getCategoryByItem(cargo.item).name
|
||||
|
||||
menu = ContextMenu.getMenu((cargo,), (sourceContext, itemContext))
|
||||
selection = self.getSelectedCargos()
|
||||
clickedPos = self.getRowByAbs(event.Position)
|
||||
mainCargo = None
|
||||
if clickedPos != -1:
|
||||
try:
|
||||
cargo = self.cargo[clickedPos]
|
||||
except IndexError:
|
||||
pass
|
||||
else:
|
||||
if cargo in self.original:
|
||||
mainCargo = cargo
|
||||
sourceContext = "cargoItem"
|
||||
itemContext = None if mainCargo is None else Market.getInstance().getCategoryByItem(mainCargo.item).name
|
||||
menu = ContextMenu.getMenu(mainCargo, selection, (sourceContext, itemContext))
|
||||
if menu:
|
||||
self.PopupMenu(menu)
|
||||
|
||||
def getSelectedCargos(self):
|
||||
cargos = []
|
||||
for row in self.getSelectedRows():
|
||||
try:
|
||||
cargo = self.cargo[row]
|
||||
except IndexError:
|
||||
continue
|
||||
cargos.append(cargo)
|
||||
return cargos
|
||||
|
||||
@@ -22,24 +22,25 @@ import wx
|
||||
|
||||
import gui.builtinAdditionPanes.droneView
|
||||
import gui.display as d
|
||||
import gui.fitCommands as cmd
|
||||
import gui.globalEvents as GE
|
||||
from gui.builtinShipBrowser.events import EVT_FIT_REMOVED
|
||||
from eos.saveddata.drone import Drone as es_Drone
|
||||
from gui.builtinContextMenus.commandFitAdd import AddCommandFit
|
||||
from gui.builtinShipBrowser.events import EVT_FIT_REMOVED
|
||||
from gui.builtinViewColumns.state import State
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.utils.staticHelpers import DragDropHelper
|
||||
from service.fit import Fit
|
||||
import gui.fitCommands as cmd
|
||||
|
||||
|
||||
class DummyItem(object):
|
||||
class DummyItem:
|
||||
|
||||
def __init__(self, txt):
|
||||
self.name = txt
|
||||
self.iconID = None
|
||||
|
||||
|
||||
class DummyEntry(object):
|
||||
class DummyEntry:
|
||||
|
||||
def __init__(self, txt):
|
||||
self.item = DummyItem(txt)
|
||||
|
||||
@@ -61,10 +62,11 @@ class CommandViewDrop(wx.DropTarget):
|
||||
|
||||
|
||||
class CommandView(d.Display):
|
||||
|
||||
DEFAULT_COLS = ["State", "Base Name"]
|
||||
|
||||
def __init__(self, parent):
|
||||
d.Display.__init__(self, parent, style=wx.LC_SINGLE_SEL | wx.BORDER_NONE)
|
||||
d.Display.__init__(self, parent, style=wx.BORDER_NONE)
|
||||
|
||||
self.lastFitId = None
|
||||
|
||||
@@ -72,14 +74,13 @@ class CommandView(d.Display):
|
||||
self.mainFrame.Bind(EVT_FIT_REMOVED, AddCommandFit.populateFits)
|
||||
self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged)
|
||||
self.Bind(wx.EVT_LEFT_DOWN, self.click)
|
||||
self.Bind(wx.EVT_LEFT_DCLICK, self.remove)
|
||||
self.Bind(wx.EVT_LEFT_DCLICK, self.onLeftDoubleClick)
|
||||
self.Bind(wx.EVT_KEY_UP, self.kbEvent)
|
||||
|
||||
self.droneView = gui.builtinAdditionPanes.droneView.DroneView
|
||||
|
||||
self.Bind(wx.EVT_RIGHT_UP, self.spawnMenu)
|
||||
self.Bind(wx.EVT_CONTEXT_MENU, self.spawnMenu)
|
||||
|
||||
self.Bind(wx.EVT_LIST_BEGIN_DRAG, self.startDrag)
|
||||
self.SetDropTarget(CommandViewDrop(self.handleListDrag))
|
||||
|
||||
@staticmethod
|
||||
@@ -95,30 +96,22 @@ class CommandView(d.Display):
|
||||
|
||||
def kbEvent(self, event):
|
||||
keycode = event.GetKeyCode()
|
||||
if keycode == wx.WXK_DELETE or keycode == wx.WXK_NUMPAD_DELETE:
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
row = self.GetFirstSelected()
|
||||
if row != -1:
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveCommandFitCommand(fitID, self.get(row).ID))
|
||||
mstate = wx.GetMouseState()
|
||||
if keycode == wx.WXK_ESCAPE and mstate.GetModifiers() == wx.MOD_NONE:
|
||||
self.unselectAll()
|
||||
elif keycode == 65 and mstate.GetModifiers() == wx.MOD_CONTROL:
|
||||
self.selectAll()
|
||||
elif keycode in (wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE) and mstate.GetModifiers() == wx.MOD_NONE:
|
||||
commandFits = self.getSelectedCommandFits()
|
||||
self.removeCommandFits(commandFits)
|
||||
event.Skip()
|
||||
|
||||
def handleDrag(self, type, fitID):
|
||||
# Those are drags coming from pyfa sources, NOT builtin wx drags
|
||||
if type == "fit":
|
||||
activeFit = self.mainFrame.getActiveFit()
|
||||
if activeFit:
|
||||
self.mainFrame.command.Submit(cmd.GuiAddCommandFitCommand(activeFit, fitID))
|
||||
|
||||
def startDrag(self, event):
|
||||
row = event.GetIndex()
|
||||
if row != -1 and isinstance(self.get(row), es_Drone):
|
||||
data = wx.TextDataObject()
|
||||
dataStr = "command:" + str(self.GetItemData(row))
|
||||
data.SetText(dataStr)
|
||||
|
||||
dropSource = wx.DropSource(self)
|
||||
dropSource.SetData(data)
|
||||
DragDropHelper.data = dataStr
|
||||
dropSource.DoDragDrop()
|
||||
self.mainFrame.command.Submit(cmd.GuiAddCommandFitCommand(fitID=activeFit, commandFitID=fitID))
|
||||
|
||||
@staticmethod
|
||||
def fitSort(fit):
|
||||
@@ -153,9 +146,8 @@ class CommandView(d.Display):
|
||||
if item != -1:
|
||||
self.EnsureVisible(item)
|
||||
|
||||
self.deselectItems()
|
||||
self.unselectAll()
|
||||
|
||||
# todo: verify
|
||||
if not stuff:
|
||||
stuff = [DummyEntry("Drag a fit to this area")]
|
||||
|
||||
@@ -163,52 +155,68 @@ class CommandView(d.Display):
|
||||
|
||||
event.Skip()
|
||||
|
||||
def get(self, row):
|
||||
if row == -1:
|
||||
return None
|
||||
|
||||
numFits = len(self.fits)
|
||||
|
||||
if numFits == 0:
|
||||
return None
|
||||
|
||||
return self.fits[row]
|
||||
|
||||
def click(self, event):
|
||||
event.Skip()
|
||||
row, _ = self.HitTest(event.Position)
|
||||
if row != -1:
|
||||
item = self.get(row)
|
||||
mainRow, _ = self.HitTest(event.Position)
|
||||
if mainRow != -1:
|
||||
col = self.getColumn(event.Position)
|
||||
if col == self.getColIndex(State):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
self.mainFrame.command.Submit(cmd.GuiToggleCommandFitStateCommand(fitID, item.ID))
|
||||
try:
|
||||
mainCommandFitID = self.fits[mainRow].ID
|
||||
except IndexError:
|
||||
return
|
||||
commandFitIDs = []
|
||||
for commandFit in self.getSelectedCommandFits():
|
||||
commandFitIDs.append(commandFit.ID)
|
||||
if mainCommandFitID not in commandFitIDs:
|
||||
commandFitIDs = [mainCommandFitID]
|
||||
self.mainFrame.command.Submit(cmd.GuiToggleCommandFitStatesCommand(
|
||||
fitID=fitID,
|
||||
mainCommandFitID=mainCommandFitID,
|
||||
commandFitIDs=commandFitIDs))
|
||||
return
|
||||
event.Skip()
|
||||
|
||||
def spawnMenu(self, event):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
if fitID is None:
|
||||
return
|
||||
|
||||
sel = self.GetFirstSelected()
|
||||
context = ()
|
||||
item = self.get(sel)
|
||||
|
||||
if item is not None:
|
||||
fitSrcContext = "commandFit"
|
||||
fitItemContext = item.name
|
||||
context = ((fitSrcContext, fitItemContext),)
|
||||
|
||||
context += (("commandView",),)
|
||||
menu = ContextMenu.getMenu((item,) if item is not None else [], *context)
|
||||
if menu is not None:
|
||||
selection = self.getSelectedCommandFits()
|
||||
clickedPos = self.getRowByAbs(event.Position)
|
||||
mainCommandFit = None
|
||||
if clickedPos != -1:
|
||||
try:
|
||||
mainCommandFit = self.fits[clickedPos]
|
||||
except IndexError:
|
||||
pass
|
||||
contexts = []
|
||||
if mainCommandFit is not None:
|
||||
contexts.append(('commandFit', 'Command Fit'))
|
||||
contexts.append(('commandView',))
|
||||
menu = ContextMenu.getMenu(mainCommandFit, selection, *contexts)
|
||||
if menu:
|
||||
self.PopupMenu(menu)
|
||||
|
||||
def remove(self, event):
|
||||
def onLeftDoubleClick(self, event):
|
||||
row, _ = self.HitTest(event.Position)
|
||||
if row != -1:
|
||||
col = self.getColumn(event.Position)
|
||||
if col != self.getColIndex(State):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
thing = self.get(row)
|
||||
if thing: # thing doesn't exist if it's the dummy value
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveCommandFitCommand(fitID, thing.ID))
|
||||
try:
|
||||
commandFit = self.fits[row]
|
||||
except IndexError:
|
||||
return
|
||||
self.removeCommandFits([commandFit])
|
||||
|
||||
def removeCommandFits(self, commandFits):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
commandFitIDs = []
|
||||
for commandFit in commandFits:
|
||||
if commandFit in self.fits:
|
||||
commandFitIDs.append(commandFit.ID)
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveCommandFitsCommand(fitID=fitID, commandFitIDs=commandFitIDs))
|
||||
|
||||
def getSelectedCommandFits(self):
|
||||
commandFits = []
|
||||
for row in self.getSelectedRows():
|
||||
try:
|
||||
commandFit = self.fits[row]
|
||||
except IndexError:
|
||||
continue
|
||||
commandFits.append(commandFit)
|
||||
return commandFits
|
||||
|
||||
@@ -33,6 +33,7 @@ from gui.utils.staticHelpers import DragDropHelper
|
||||
from service.fit import Fit
|
||||
from service.market import Market
|
||||
import gui.fitCommands as cmd
|
||||
from gui.fitCommands.helpers import droneStackLimit
|
||||
|
||||
|
||||
class DroneViewDrop(wx.DropTarget):
|
||||
@@ -64,7 +65,7 @@ class DroneView(Display):
|
||||
]
|
||||
|
||||
def __init__(self, parent):
|
||||
Display.__init__(self, parent, style=wx.LC_SINGLE_SEL | wx.BORDER_NONE)
|
||||
Display.__init__(self, parent, style=wx.BORDER_NONE)
|
||||
|
||||
self.lastFitId = None
|
||||
|
||||
@@ -75,7 +76,7 @@ class DroneView(Display):
|
||||
|
||||
self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged)
|
||||
self.mainFrame.Bind(ITEM_SELECTED, self.addItem)
|
||||
self.Bind(wx.EVT_LEFT_DCLICK, self.removeItem)
|
||||
self.Bind(wx.EVT_LEFT_DCLICK, self.onLeftDoubleClick)
|
||||
self.Bind(wx.EVT_LEFT_DOWN, self.click)
|
||||
self.Bind(wx.EVT_KEY_UP, self.kbEvent)
|
||||
self.Bind(wx.EVT_MOTION, self.OnMouseMove)
|
||||
@@ -101,7 +102,10 @@ class DroneView(Display):
|
||||
self.hoveredRow = row
|
||||
self.hoveredColumn = col
|
||||
if row != -1 and col != -1 and col < len(self.DEFAULT_COLS):
|
||||
mod = self.drones[self.GetItemData(row)]
|
||||
try:
|
||||
mod = self.drones[row]
|
||||
except IndexError:
|
||||
return
|
||||
if self.DEFAULT_COLS[col] == "Miscellanea":
|
||||
tooltip = self.activeColumns[col].getToolTip(mod)
|
||||
if tooltip is not None:
|
||||
@@ -116,17 +120,22 @@ class DroneView(Display):
|
||||
|
||||
def kbEvent(self, event):
|
||||
keycode = event.GetKeyCode()
|
||||
if keycode == wx.WXK_DELETE or keycode == wx.WXK_NUMPAD_DELETE:
|
||||
row = self.GetFirstSelected()
|
||||
if row != -1:
|
||||
drone = self.drones[self.GetItemData(row)]
|
||||
self.removeDroneStack(drone)
|
||||
|
||||
mstate = wx.GetMouseState()
|
||||
if keycode == wx.WXK_ESCAPE and mstate.GetModifiers() == wx.MOD_NONE:
|
||||
self.unselectAll()
|
||||
elif keycode == 65 and mstate.GetModifiers() == wx.MOD_CONTROL:
|
||||
self.selectAll()
|
||||
elif keycode in (wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE) and mstate.GetModifiers() == wx.MOD_NONE:
|
||||
drones = self.getSelectedDrones()
|
||||
self.removeDroneStacks(drones)
|
||||
event.Skip()
|
||||
|
||||
def startDrag(self, event):
|
||||
row = event.GetIndex()
|
||||
if row != -1:
|
||||
self.unselectAll()
|
||||
self.Select(row, True)
|
||||
|
||||
data = wx.TextDataObject()
|
||||
dataStr = "drone:" + str(row)
|
||||
data.SetText(dataStr)
|
||||
@@ -146,19 +155,36 @@ class DroneView(Display):
|
||||
"""
|
||||
if data[0] == "drone":
|
||||
srcRow = int(data[1])
|
||||
dstRow, _ = self.HitTest((x, y))
|
||||
if srcRow != -1 and dstRow != -1:
|
||||
self._merge(srcRow, dstRow)
|
||||
if srcRow != -1:
|
||||
if wx.GetMouseState().GetModifiers() == wx.MOD_CONTROL:
|
||||
try:
|
||||
srcDrone = self.drones[srcRow]
|
||||
except IndexError:
|
||||
return
|
||||
if srcDrone not in self.original:
|
||||
return
|
||||
self.mainFrame.command.Submit(cmd.GuiCloneLocalDroneCommand(
|
||||
fitID=self.mainFrame.getActiveFit(),
|
||||
position=self.original.index(srcDrone)))
|
||||
else:
|
||||
dstRow, _ = self.HitTest((x, y))
|
||||
if dstRow != -1:
|
||||
self._merge(srcRow, dstRow)
|
||||
elif data[0] == "market":
|
||||
wx.PostEvent(self.mainFrame, ItemSelected(itemID=int(data[1])))
|
||||
|
||||
def _merge(self, srcRow, dstRow):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
self.mainFrame.command.Submit(cmd.GuiMergeLocalDroneStacksCommand(
|
||||
fitID=fitID,
|
||||
srcPosition=fit.drones.index(self.drones[srcRow]),
|
||||
dstPosition=fit.drones.index(self.drones[dstRow])))
|
||||
try:
|
||||
srcDrone = self.drones[srcRow]
|
||||
dstDrone = self.drones[dstRow]
|
||||
except IndexError:
|
||||
return
|
||||
if srcDrone in self.original and dstDrone in self.original:
|
||||
srcPosition = self.original.index(srcDrone)
|
||||
dstPosition = self.original.index(dstDrone)
|
||||
self.mainFrame.command.Submit(cmd.GuiMergeLocalDroneStacksCommand(
|
||||
fitID=fitID, srcPosition=srcPosition, dstPosition=dstPosition))
|
||||
|
||||
DRONE_ORDER = ('Light Scout Drones', 'Medium Scout Drones',
|
||||
'Heavy Attack Drones', 'Sentry Drones', 'Combat Utility Drones',
|
||||
@@ -199,7 +225,7 @@ class DroneView(Display):
|
||||
if item != -1:
|
||||
self.EnsureVisible(item)
|
||||
|
||||
self.deselectItems()
|
||||
self.unselectAll()
|
||||
|
||||
self.update(self.drones)
|
||||
event.Skip()
|
||||
@@ -216,44 +242,94 @@ class DroneView(Display):
|
||||
event.Skip()
|
||||
return
|
||||
|
||||
if self.mainFrame.command.Submit(cmd.GuiAddLocalDroneCommand(fitID=fitID, itemID=event.itemID, amount=1)):
|
||||
amount = droneStackLimit(fit, event.itemID) if wx.GetMouseState().GetModifiers() == wx.MOD_ALT else 1
|
||||
if self.mainFrame.command.Submit(cmd.GuiAddLocalDroneCommand(fitID=fitID, itemID=event.itemID, amount=amount)):
|
||||
self.mainFrame.additionsPane.select('Drones')
|
||||
|
||||
event.Skip()
|
||||
|
||||
def removeItem(self, event):
|
||||
def onLeftDoubleClick(self, event):
|
||||
row, _ = self.HitTest(event.Position)
|
||||
if row != -1:
|
||||
col = self.getColumn(event.Position)
|
||||
if col != self.getColIndex(State):
|
||||
drone = self.drones[self.GetItemData(row)]
|
||||
self.removeDrone(drone)
|
||||
try:
|
||||
drone = self.drones[row]
|
||||
except IndexError:
|
||||
return
|
||||
if wx.GetMouseState().GetModifiers() == wx.MOD_ALT:
|
||||
self.removeDroneStacks([drone])
|
||||
else:
|
||||
self.removeDrone(drone)
|
||||
|
||||
def removeDrone(self, drone):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveLocalDroneCommand(fitID, self.original.index(drone), 1))
|
||||
if drone in self.original:
|
||||
position = self.original.index(drone)
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveLocalDronesCommand(
|
||||
fitID=fitID, positions=[position], amount=1))
|
||||
|
||||
def removeDroneStack(self, drone):
|
||||
def removeDroneStacks(self, drones):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveLocalDroneCommand(fitID, self.original.index(drone), math.inf))
|
||||
positions = []
|
||||
for drone in drones:
|
||||
if drone in self.original:
|
||||
positions.append(self.original.index(drone))
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveLocalDronesCommand(
|
||||
fitID=fitID, positions=positions, amount=math.inf))
|
||||
|
||||
def click(self, event):
|
||||
event.Skip()
|
||||
row, _ = self.HitTest(event.Position)
|
||||
if row != -1:
|
||||
mainRow, _ = self.HitTest(event.Position)
|
||||
if mainRow != -1:
|
||||
col = self.getColumn(event.Position)
|
||||
if col == self.getColIndex(State):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
drone = self.drones[row]
|
||||
self.mainFrame.command.Submit(cmd.GuiToggleLocalDroneStateCommand(fitID, self.original.index(drone)))
|
||||
try:
|
||||
mainDrone = self.drones[mainRow]
|
||||
except IndexError:
|
||||
return
|
||||
if mainDrone in self.original:
|
||||
mainPosition = self.original.index(mainDrone)
|
||||
positions = []
|
||||
for row in self.getSelectedRows():
|
||||
try:
|
||||
drone = self.drones[row]
|
||||
except IndexError:
|
||||
continue
|
||||
if drone in self.original:
|
||||
positions.append(self.original.index(drone))
|
||||
if mainPosition not in positions:
|
||||
positions = [mainPosition]
|
||||
self.mainFrame.command.Submit(cmd.GuiToggleLocalDroneStatesCommand(
|
||||
fitID=self.mainFrame.getActiveFit(),
|
||||
mainPosition=mainPosition,
|
||||
positions=positions))
|
||||
return
|
||||
event.Skip()
|
||||
|
||||
def spawnMenu(self, event):
|
||||
sel = self.GetFirstSelected()
|
||||
if sel != -1:
|
||||
drone = self.drones[sel]
|
||||
|
||||
sMkt = Market.getInstance()
|
||||
sourceContext = "droneItem"
|
||||
itemContext = sMkt.getCategoryByItem(drone.item).name
|
||||
menu = ContextMenu.getMenu((drone,), (sourceContext, itemContext))
|
||||
clickedPos = self.getRowByAbs(event.Position)
|
||||
mainDrone = None
|
||||
if clickedPos != -1:
|
||||
try:
|
||||
drone = self.drones[clickedPos]
|
||||
except IndexError:
|
||||
pass
|
||||
else:
|
||||
if drone in self.original:
|
||||
mainDrone = drone
|
||||
selection = self.getSelectedDrones()
|
||||
sourceContext = "droneItem"
|
||||
itemContext = None if mainDrone is None else Market.getInstance().getCategoryByItem(mainDrone.item).name
|
||||
menu = ContextMenu.getMenu(mainDrone, selection, (sourceContext, itemContext))
|
||||
if menu:
|
||||
self.PopupMenu(menu)
|
||||
|
||||
def getSelectedDrones(self):
|
||||
drones = []
|
||||
for row in self.getSelectedRows():
|
||||
try:
|
||||
drone = self.drones[row]
|
||||
except IndexError:
|
||||
continue
|
||||
drones.append(drone)
|
||||
return drones
|
||||
|
||||
@@ -20,17 +20,18 @@
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
|
||||
import gui.globalEvents as GE
|
||||
from gui.builtinMarketBrowser.events import ItemSelected, ITEM_SELECTED
|
||||
import gui.mainFrame
|
||||
import gui.display as d
|
||||
from gui.builtinViewColumns.state import State
|
||||
import gui.fitCommands as cmd
|
||||
import gui.globalEvents as GE
|
||||
import gui.mainFrame
|
||||
from eos.const import FittingSlot
|
||||
from gui.builtinMarketBrowser.events import ItemSelected, ITEM_SELECTED
|
||||
from gui.builtinViewColumns.state import State
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.fitCommands.helpers import getSimilarFighters
|
||||
from gui.utils.staticHelpers import DragDropHelper
|
||||
from service.fit import Fit
|
||||
from service.market import Market
|
||||
import gui.fitCommands as cmd
|
||||
|
||||
|
||||
class FighterViewDrop(wx.DropTarget):
|
||||
@@ -50,6 +51,7 @@ class FighterViewDrop(wx.DropTarget):
|
||||
|
||||
|
||||
class FighterView(wx.Panel):
|
||||
|
||||
def __init__(self, parent):
|
||||
wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, style=wx.TAB_TRAVERSAL)
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
@@ -115,6 +117,7 @@ class FighterView(wx.Panel):
|
||||
|
||||
|
||||
class FighterDisplay(d.Display):
|
||||
|
||||
DEFAULT_COLS = ["State",
|
||||
# "Base Icon",
|
||||
"Base Name",
|
||||
@@ -127,7 +130,7 @@ class FighterDisplay(d.Display):
|
||||
]
|
||||
|
||||
def __init__(self, parent):
|
||||
d.Display.__init__(self, parent, style=wx.LC_SINGLE_SEL | wx.BORDER_NONE)
|
||||
d.Display.__init__(self, parent, style=wx.BORDER_NONE)
|
||||
|
||||
self.lastFitId = None
|
||||
|
||||
@@ -136,7 +139,7 @@ class FighterDisplay(d.Display):
|
||||
|
||||
self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged)
|
||||
self.mainFrame.Bind(ITEM_SELECTED, self.addItem)
|
||||
self.Bind(wx.EVT_LEFT_DCLICK, self.removeItem)
|
||||
self.Bind(wx.EVT_LEFT_DCLICK, self.onLeftDoubleClick)
|
||||
self.Bind(wx.EVT_LEFT_DOWN, self.click)
|
||||
self.Bind(wx.EVT_KEY_UP, self.kbEvent)
|
||||
self.Bind(wx.EVT_MOTION, self.OnMouseMove)
|
||||
@@ -162,7 +165,10 @@ class FighterDisplay(d.Display):
|
||||
self.hoveredRow = row
|
||||
self.hoveredColumn = col
|
||||
if row != -1 and col != -1 and col < len(self.DEFAULT_COLS):
|
||||
mod = self.fighters[self.GetItemData(row)]
|
||||
try:
|
||||
mod = self.fighters[row]
|
||||
except IndexError:
|
||||
return
|
||||
if self.DEFAULT_COLS[col] == "Miscellanea":
|
||||
tooltip = self.activeColumns[col].getToolTip(mod)
|
||||
if tooltip is not None:
|
||||
@@ -177,17 +183,22 @@ class FighterDisplay(d.Display):
|
||||
|
||||
def kbEvent(self, event):
|
||||
keycode = event.GetKeyCode()
|
||||
if keycode == wx.WXK_DELETE or keycode == wx.WXK_NUMPAD_DELETE:
|
||||
row = self.GetFirstSelected()
|
||||
if row != -1:
|
||||
fighter = self.fighters[self.GetItemData(row)]
|
||||
self.removeFighter(fighter)
|
||||
|
||||
mstate = wx.GetMouseState()
|
||||
if keycode == wx.WXK_ESCAPE and mstate.GetModifiers() == wx.MOD_NONE:
|
||||
self.unselectAll()
|
||||
elif keycode == 65 and mstate.GetModifiers() == wx.MOD_CONTROL:
|
||||
self.selectAll()
|
||||
elif keycode in (wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE) and mstate.GetModifiers() == wx.MOD_NONE:
|
||||
fighters = self.getSelectedFighters()
|
||||
self.removeFighters(fighters)
|
||||
event.Skip()
|
||||
|
||||
def startDrag(self, event):
|
||||
row = event.GetIndex()
|
||||
if row != -1:
|
||||
self.unselectAll()
|
||||
self.Select(row, True)
|
||||
|
||||
data = wx.TextDataObject()
|
||||
dataStr = "fighter:" + str(row)
|
||||
data.SetText(dataStr)
|
||||
@@ -217,12 +228,18 @@ class FighterDisplay(d.Display):
|
||||
def _merge(src, dst):
|
||||
return
|
||||
|
||||
FIGHTER_ORDER = ('Heavy Fighter', 'Light Fighter', 'Support Fighter')
|
||||
FIGHTER_ORDER = ('Light Fighter', 'Heavy Fighter', 'Support Fighter')
|
||||
|
||||
def fighterKey(self, fighter):
|
||||
sMkt = Market.getInstance()
|
||||
groupName = sMkt.getGroupByItem(fighter.item).name
|
||||
return (self.FIGHTER_ORDER.index(groupName), fighter.item.name)
|
||||
groupName = Market.getInstance().getGroupByItem(fighter.item).name
|
||||
orderPos = self.FIGHTER_ORDER.index(groupName)
|
||||
# Sort support fighters by name, ignore their abilities
|
||||
if groupName == 'Support Fighter':
|
||||
abilityEffectIDs = ()
|
||||
# Group up fighters from various roles
|
||||
else:
|
||||
abilityEffectIDs = sorted(a.effectID for a in fighter.abilities)
|
||||
return orderPos, abilityEffectIDs, fighter.item.name
|
||||
|
||||
def fitChanged(self, event):
|
||||
sFit = Fit.getInstance()
|
||||
@@ -251,7 +268,7 @@ class FighterDisplay(d.Display):
|
||||
if item != -1:
|
||||
self.EnsureVisible(item)
|
||||
|
||||
self.deselectItems()
|
||||
self.unselectAll()
|
||||
|
||||
self.update(self.fighters)
|
||||
event.Skip()
|
||||
@@ -268,35 +285,87 @@ class FighterDisplay(d.Display):
|
||||
|
||||
event.Skip()
|
||||
|
||||
def removeItem(self, event):
|
||||
def onLeftDoubleClick(self, event):
|
||||
row, _ = self.HitTest(event.Position)
|
||||
if row != -1:
|
||||
col = self.getColumn(event.Position)
|
||||
if col != self.getColIndex(State):
|
||||
fighter = self.fighters[self.GetItemData(row)]
|
||||
self.removeFighter(fighter)
|
||||
mstate = wx.GetMouseState()
|
||||
try:
|
||||
fighter = self.fighters[row]
|
||||
except IndexError:
|
||||
return
|
||||
if mstate.GetModifiers() == wx.MOD_ALT:
|
||||
fighters = getSimilarFighters(self.original, fighter)
|
||||
else:
|
||||
fighters = [fighter]
|
||||
self.removeFighters(fighters)
|
||||
|
||||
def removeFighter(self, fighter):
|
||||
def removeFighters(self, fighters):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveLocalFighterCommand(fitID, self.original.index(fighter)))
|
||||
positions = []
|
||||
for fighter in fighters:
|
||||
if fighter in self.original:
|
||||
positions.append(self.original.index(fighter))
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveLocalFightersCommand(fitID=fitID, positions=positions))
|
||||
|
||||
def click(self, event):
|
||||
event.Skip()
|
||||
row, _ = self.HitTest(event.Position)
|
||||
if row != -1:
|
||||
mainRow, _ = self.HitTest(event.Position)
|
||||
if mainRow != -1:
|
||||
col = self.getColumn(event.Position)
|
||||
if col == self.getColIndex(State):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fighter = self.fighters[row]
|
||||
self.mainFrame.command.Submit(cmd.GuiToggleLocalFighterStateCommand(fitID, self.original.index(fighter)))
|
||||
try:
|
||||
mainFighter = self.fighters[mainRow]
|
||||
except IndexError:
|
||||
return
|
||||
if mainFighter in self.original:
|
||||
mainPosition = self.original.index(mainFighter)
|
||||
positions = []
|
||||
if event.GetModifiers() == wx.MOD_ALT:
|
||||
for fighter in getSimilarFighters(self.original, mainFighter):
|
||||
positions.append(self.original.index(fighter))
|
||||
else:
|
||||
for row in self.getSelectedRows():
|
||||
try:
|
||||
fighter = self.fighters[row]
|
||||
except IndexError:
|
||||
continue
|
||||
if fighter in self.original:
|
||||
positions.append(self.original.index(fighter))
|
||||
if mainPosition not in positions:
|
||||
positions = [mainPosition]
|
||||
self.mainFrame.command.Submit(cmd.GuiToggleLocalFighterStatesCommand(
|
||||
fitID=fitID,
|
||||
mainPosition=mainPosition,
|
||||
positions=positions))
|
||||
return
|
||||
event.Skip()
|
||||
|
||||
def spawnMenu(self, event):
|
||||
sel = self.GetFirstSelected()
|
||||
if sel != -1:
|
||||
fighter = self.fighters[sel]
|
||||
|
||||
sMkt = Market.getInstance()
|
||||
sourceContext = "fighterItem"
|
||||
itemContext = sMkt.getCategoryByItem(fighter.item).name
|
||||
menu = ContextMenu.getMenu((fighter,), (sourceContext, itemContext))
|
||||
selection = self.getSelectedFighters()
|
||||
clickedPos = self.getRowByAbs(event.Position)
|
||||
mainFighter = None
|
||||
if clickedPos != -1:
|
||||
try:
|
||||
fighter = self.fighters[clickedPos]
|
||||
except IndexError:
|
||||
pass
|
||||
else:
|
||||
if fighter in self.original:
|
||||
mainFighter = fighter
|
||||
sourceContext = "fighterItem"
|
||||
itemContext = None if mainFighter is None else Market.getInstance().getCategoryByItem(mainFighter.item).name
|
||||
menu = ContextMenu.getMenu(mainFighter, selection, (sourceContext, itemContext))
|
||||
if menu:
|
||||
self.PopupMenu(menu)
|
||||
|
||||
def getSelectedFighters(self):
|
||||
fighters = []
|
||||
for row in self.getSelectedRows():
|
||||
try:
|
||||
fighter = self.fighters[row]
|
||||
except IndexError:
|
||||
continue
|
||||
fighters.append(fighter)
|
||||
return fighters
|
||||
|
||||
@@ -19,17 +19,18 @@
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
|
||||
import gui.display as d
|
||||
from gui.builtinMarketBrowser.events import ITEM_SELECTED
|
||||
import gui.mainFrame
|
||||
from gui.builtinViewColumns.state import State
|
||||
from gui.utils.staticHelpers import DragDropHelper
|
||||
from gui.contextMenu import ContextMenu
|
||||
import gui.fitCommands as cmd
|
||||
import gui.globalEvents as GE
|
||||
import gui.mainFrame
|
||||
from eos.const import ImplantLocation
|
||||
from gui.builtinMarketBrowser.events import ITEM_SELECTED
|
||||
from gui.builtinViewColumns.state import State
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.utils.staticHelpers import DragDropHelper
|
||||
from service.fit import Fit
|
||||
from service.market import Market
|
||||
import gui.fitCommands as cmd
|
||||
|
||||
|
||||
class ImplantViewDrop(wx.DropTarget):
|
||||
@@ -49,6 +50,7 @@ class ImplantViewDrop(wx.DropTarget):
|
||||
|
||||
|
||||
class ImplantView(wx.Panel):
|
||||
|
||||
def __init__(self, parent):
|
||||
wx.Panel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, style=wx.TAB_TRAVERSAL)
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
@@ -99,6 +101,7 @@ class ImplantView(wx.Panel):
|
||||
|
||||
|
||||
class ImplantDisplay(d.Display):
|
||||
|
||||
DEFAULT_COLS = [
|
||||
"State",
|
||||
"attr:implantness",
|
||||
@@ -108,13 +111,13 @@ class ImplantDisplay(d.Display):
|
||||
]
|
||||
|
||||
def __init__(self, parent):
|
||||
d.Display.__init__(self, parent, style=wx.LC_SINGLE_SEL | wx.BORDER_NONE)
|
||||
d.Display.__init__(self, parent, style=wx.BORDER_NONE)
|
||||
|
||||
self.lastFitId = None
|
||||
|
||||
self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged)
|
||||
self.mainFrame.Bind(ITEM_SELECTED, self.addItem)
|
||||
self.Bind(wx.EVT_LEFT_DCLICK, self.removeItem)
|
||||
self.Bind(wx.EVT_LEFT_DCLICK, self.onLeftDoubleClick)
|
||||
self.Bind(wx.EVT_LEFT_DOWN, self.click)
|
||||
self.Bind(wx.EVT_KEY_UP, self.kbEvent)
|
||||
self.SetDropTarget(ImplantViewDrop(self.handleListDrag))
|
||||
@@ -132,15 +135,20 @@ class ImplantDisplay(d.Display):
|
||||
"""
|
||||
|
||||
if data[0] == "market":
|
||||
if self.mainFrame.command.Submit(cmd.GuiAddImplantCommand(self.mainFrame.getActiveFit(), int(data[1]))):
|
||||
if self.mainFrame.command.Submit(cmd.GuiAddImplantCommand(
|
||||
fitID=self.mainFrame.getActiveFit(), itemID=int(data[1]))):
|
||||
self.mainFrame.additionsPane.select("Implants")
|
||||
|
||||
def kbEvent(self, event):
|
||||
keycode = event.GetKeyCode()
|
||||
if keycode in (wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE):
|
||||
row = self.GetFirstSelected()
|
||||
if row != -1:
|
||||
self.removeImplant(self.implants[self.GetItemData(row)])
|
||||
mstate = wx.GetMouseState()
|
||||
if keycode == wx.WXK_ESCAPE and mstate.GetModifiers() == wx.MOD_NONE:
|
||||
self.unselectAll()
|
||||
elif keycode == 65 and mstate.GetModifiers() == wx.MOD_CONTROL:
|
||||
self.selectAll()
|
||||
elif keycode in (wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE) and mstate.GetModifiers() == wx.MOD_NONE:
|
||||
implants = self.getSelectedImplants()
|
||||
self.removeImplants(implants)
|
||||
event.Skip()
|
||||
|
||||
def fitChanged(self, event):
|
||||
@@ -169,7 +177,7 @@ class ImplantDisplay(d.Display):
|
||||
if item != -1:
|
||||
self.EnsureVisible(item)
|
||||
|
||||
self.deselectItems()
|
||||
self.unselectAll()
|
||||
|
||||
self.update(self.implants)
|
||||
event.Skip()
|
||||
@@ -187,67 +195,94 @@ class ImplantDisplay(d.Display):
|
||||
event.Skip()
|
||||
return
|
||||
|
||||
self.mainFrame.command.Submit(cmd.GuiAddImplantCommand(fitID, event.itemID))
|
||||
self.mainFrame.command.Submit(cmd.GuiAddImplantCommand(
|
||||
fitID=fitID, itemID=event.itemID))
|
||||
# Select in any case - as we might've added implant which has been there already and command failed
|
||||
self.mainFrame.additionsPane.select('Implants')
|
||||
|
||||
event.Skip()
|
||||
|
||||
def removeItem(self, event):
|
||||
# Character implants can't be changed here...
|
||||
if self.Parent.source == ImplantLocation.CHARACTER:
|
||||
return
|
||||
|
||||
def onLeftDoubleClick(self, event):
|
||||
row, _ = self.HitTest(event.Position)
|
||||
if row != -1:
|
||||
col = self.getColumn(event.Position)
|
||||
if col != self.getColIndex(State):
|
||||
self.removeImplant(self.implants[self.GetItemData(row)])
|
||||
try:
|
||||
implant = self.implants[row]
|
||||
except IndexError:
|
||||
return
|
||||
self.removeImplants([implant])
|
||||
|
||||
def removeImplant(self, implant):
|
||||
def removeImplants(self, implants):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
sFit = Fit.getInstance()
|
||||
fit = sFit.getFit(fitID)
|
||||
if fit.implantLocation == ImplantLocation.FIT:
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveImplantCommand(fitID, self.original.index(implant)))
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
if fit.implantLocation != ImplantLocation.FIT:
|
||||
return
|
||||
positions = []
|
||||
for implant in implants:
|
||||
if implant in self.original:
|
||||
positions.append(self.original.index(implant))
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveImplantsCommand(fitID=fitID, positions=positions))
|
||||
|
||||
def click(self, event):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
if fit.implantLocation == ImplantLocation.FIT:
|
||||
mainRow, _ = self.HitTest(event.Position)
|
||||
if mainRow != -1:
|
||||
col = self.getColumn(event.Position)
|
||||
if col == self.getColIndex(State):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
try:
|
||||
mainImplant = self.implants[mainRow]
|
||||
except IndexError:
|
||||
return
|
||||
if mainImplant in self.original:
|
||||
mainPosition = self.original.index(mainImplant)
|
||||
positions = []
|
||||
for row in self.getSelectedRows():
|
||||
try:
|
||||
implant = self.implants[row]
|
||||
except IndexError:
|
||||
continue
|
||||
if implant in self.original:
|
||||
positions.append(self.original.index(implant))
|
||||
if mainPosition not in positions:
|
||||
positions = [mainPosition]
|
||||
self.mainFrame.command.Submit(cmd.GuiToggleImplantStatesCommand(
|
||||
fitID=fitID,
|
||||
mainPosition=mainPosition,
|
||||
positions=positions))
|
||||
return
|
||||
event.Skip()
|
||||
|
||||
# Character implants can't be changed here...
|
||||
if self.Parent.source == ImplantLocation.CHARACTER:
|
||||
return
|
||||
|
||||
row, _ = self.HitTest(event.Position)
|
||||
if row != -1:
|
||||
col = self.getColumn(event.Position)
|
||||
if col == self.getColIndex(State):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
implant = self.implants[self.GetItemData(row)]
|
||||
self.mainFrame.command.Submit(cmd.GuiToggleImplantStateCommand(fitID=fitID, position=self.original.index(implant)))
|
||||
|
||||
def spawnMenu(self, event):
|
||||
sel = self.GetFirstSelected()
|
||||
menu = None
|
||||
|
||||
sFit = Fit.getInstance()
|
||||
fit = sFit.getFit(self.mainFrame.getActiveFit())
|
||||
|
||||
if not fit:
|
||||
return
|
||||
|
||||
if sel != -1:
|
||||
implant = self.implants[sel]
|
||||
sMkt = Market.getInstance()
|
||||
sourceContext = "implantItem" if fit.implantSource == ImplantLocation.FIT else "implantItemChar"
|
||||
itemContext = sMkt.getCategoryByItem(implant.item).name
|
||||
fullContext = ((sourceContext, itemContext), ("implantView",))
|
||||
menu = ContextMenu.getMenu((implant,), *fullContext)
|
||||
elif sel == -1 and fit.implantSource == ImplantLocation.FIT:
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
if fitID is None:
|
||||
return
|
||||
context = ("implantView",)
|
||||
menu = ContextMenu.getMenu([], context)
|
||||
if menu is not None:
|
||||
selection = self.getSelectedImplants()
|
||||
clickedPos = self.getRowByAbs(event.Position)
|
||||
mainImplant = None
|
||||
if clickedPos != -1:
|
||||
try:
|
||||
implant = self.implants[clickedPos]
|
||||
except IndexError:
|
||||
pass
|
||||
else:
|
||||
if implant in self.original:
|
||||
mainImplant = implant
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
sourceContext1 = "implantItem" if fit.implantSource == ImplantLocation.FIT else "implantItemChar"
|
||||
sourceContext2 = "implantView" if fit.implantSource == ImplantLocation.FIT else "implantViewChar"
|
||||
itemContext = None if mainImplant is None else Market.getInstance().getCategoryByItem(mainImplant.item).name
|
||||
menu = ContextMenu.getMenu(mainImplant, selection, (sourceContext1, itemContext), (sourceContext2, itemContext))
|
||||
if menu:
|
||||
self.PopupMenu(menu)
|
||||
|
||||
def getSelectedImplants(self):
|
||||
implants = []
|
||||
for row in self.getSelectedRows():
|
||||
try:
|
||||
implant = self.implants[row]
|
||||
except IndexError:
|
||||
continue
|
||||
implants.append(implant)
|
||||
return implants
|
||||
|
||||
@@ -25,17 +25,19 @@ from logbook import Logger
|
||||
|
||||
import gui.builtinAdditionPanes.droneView
|
||||
import gui.display as d
|
||||
import gui.fitCommands as cmd
|
||||
import gui.globalEvents as GE
|
||||
from eos.saveddata.drone import Drone as es_Drone
|
||||
from eos.saveddata.fighter import Fighter as es_Fighter
|
||||
from eos.saveddata.fit import Fit as es_Fit
|
||||
from eos.saveddata.module import Module as es_Module
|
||||
from eos.saveddata.drone import Drone as EosDrone
|
||||
from eos.saveddata.fighter import Fighter as EosFighter
|
||||
from eos.saveddata.fit import Fit as EosFit
|
||||
from eos.saveddata.module import Module as EosModule
|
||||
from gui.builtinViewColumns.state import State
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.fitCommands.helpers import getSimilarFighters, getSimilarModPositions
|
||||
from gui.utils.staticHelpers import DragDropHelper
|
||||
from service.fit import Fit
|
||||
from service.market import Market
|
||||
import gui.fitCommands as cmd
|
||||
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
@@ -68,28 +70,27 @@ class ProjectedViewDrop(wx.DropTarget):
|
||||
|
||||
|
||||
class ProjectedView(d.Display):
|
||||
DEFAULT_COLS = ["State",
|
||||
"Ammo Icon",
|
||||
"Base Icon",
|
||||
"Base Name",
|
||||
"Ammo"]
|
||||
DEFAULT_COLS = ['State',
|
||||
'Ammo Icon',
|
||||
'Base Icon',
|
||||
'Base Name',
|
||||
'Ammo']
|
||||
|
||||
def __init__(self, parent):
|
||||
d.Display.__init__(self, parent, style=wx.LC_SINGLE_SEL | wx.BORDER_NONE)
|
||||
d.Display.__init__(self, parent, style=wx.BORDER_NONE)
|
||||
|
||||
self.lastFitId = None
|
||||
|
||||
self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged)
|
||||
self.Bind(wx.EVT_LEFT_DOWN, self.click)
|
||||
self.Bind(wx.EVT_RIGHT_DOWN, self.click)
|
||||
self.Bind(wx.EVT_LEFT_DCLICK, self.remove)
|
||||
self.Bind(wx.EVT_LEFT_DCLICK, self.onLeftDoubleClick)
|
||||
self.Bind(wx.EVT_KEY_UP, self.kbEvent)
|
||||
|
||||
self.droneView = gui.builtinAdditionPanes.droneView.DroneView
|
||||
|
||||
self.Bind(wx.EVT_CONTEXT_MENU, self.spawnMenu)
|
||||
|
||||
self.Bind(wx.EVT_LIST_BEGIN_DRAG, self.startDrag)
|
||||
self.SetDropTarget(ProjectedViewDrop(self.handleListDrag))
|
||||
|
||||
def handleListDrag(self, x, y, data):
|
||||
@@ -109,7 +110,7 @@ class ProjectedView(d.Display):
|
||||
fitID=fitID, itemID=fit.modules[int(data[1])].itemID))
|
||||
elif data[0] == 'market':
|
||||
itemID = int(data[1])
|
||||
category = Market.getInstance().getItem(itemID, eager=("group.category")).category.name
|
||||
category = Market.getInstance().getItem(itemID, eager=('group.category')).category.name
|
||||
if category == 'Module':
|
||||
self.mainFrame.command.Submit(cmd.GuiAddProjectedModuleCommand(fitID=fitID, itemID=itemID))
|
||||
elif category == 'Drone':
|
||||
@@ -119,42 +120,25 @@ class ProjectedView(d.Display):
|
||||
|
||||
def kbEvent(self, event):
|
||||
keycode = event.GetKeyCode()
|
||||
if keycode in (wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE):
|
||||
row = self.GetFirstSelected()
|
||||
if row != -1:
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
thing = self.get(row)
|
||||
if isinstance(thing, es_Fit):
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedFitCommand(
|
||||
fitID=fitID, projectedFitID=thing.ID))
|
||||
elif isinstance(thing, es_Module):
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedModuleCommand(
|
||||
fitID=fitID, position=Fit.getInstance().getFit(fitID).projectedModules.index(thing)))
|
||||
elif isinstance(thing, es_Drone):
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedDroneCommand(
|
||||
fitID=fitID, itemID=thing.itemID, amount=math.inf))
|
||||
elif isinstance(thing, es_Fighter):
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedFighterCommand(
|
||||
fitID=fitID, position=Fit.getInstance().getFit(fitID).projectedFighters.index(thing)))
|
||||
mstate = wx.GetMouseState()
|
||||
if keycode == wx.WXK_ESCAPE and mstate.GetModifiers() == wx.MOD_NONE:
|
||||
self.unselectAll()
|
||||
elif keycode == 65 and mstate.GetModifiers() == wx.MOD_CONTROL:
|
||||
self.selectAll()
|
||||
elif keycode in (wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE) and mstate.GetModifiers() == wx.MOD_NONE:
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedItemsCommand(
|
||||
fitID=self.mainFrame.getActiveFit(),
|
||||
items=self.getSelectedProjectors(),
|
||||
amount=math.inf))
|
||||
event.Skip()
|
||||
|
||||
def handleDrag(self, type, fitID):
|
||||
# Those are drags coming from pyfa sources, NOT builtin wx drags
|
||||
if type == "fit":
|
||||
if type == 'fit':
|
||||
activeFit = self.mainFrame.getActiveFit()
|
||||
if activeFit:
|
||||
self.mainFrame.command.Submit(cmd.GuiAddProjectedFitCommand(fitID=activeFit, projectedFitID=fitID))
|
||||
|
||||
def startDrag(self, event):
|
||||
row = event.GetIndex()
|
||||
if row != -1 and isinstance(self.get(row), es_Drone):
|
||||
data = wx.TextDataObject()
|
||||
dataStr = "projected:" + str(self.GetItemData(row))
|
||||
data.SetText(dataStr)
|
||||
|
||||
dropSource = wx.DropSource(self)
|
||||
dropSource.SetData(data)
|
||||
DragDropHelper.data = dataStr
|
||||
dropSource.DoDragDrop()
|
||||
self.mainFrame.command.Submit(cmd.GuiAddProjectedFitCommand(
|
||||
fitID=activeFit, projectedFitID=fitID, amount=1))
|
||||
|
||||
@staticmethod
|
||||
def moduleSort(module):
|
||||
@@ -179,7 +163,7 @@ class ProjectedView(d.Display):
|
||||
def fitChanged(self, event):
|
||||
sFit = Fit.getInstance()
|
||||
fit = sFit.getFit(event.fitID)
|
||||
# pyfalog.debug("ProjectedView::fitChanged: {}", repr(fit))
|
||||
# pyfalog.debug('ProjectedView::fitChanged: {}', repr(fit))
|
||||
|
||||
self.Parent.Parent.DisablePage(self, not fit or fit.isStructure)
|
||||
|
||||
@@ -192,10 +176,13 @@ class ProjectedView(d.Display):
|
||||
|
||||
stuff = []
|
||||
if fit is not None:
|
||||
# pyfalog.debug(" Collecting list of stuff to display in ProjectedView")
|
||||
self.originalFits = fit.projectedFits
|
||||
self.fits = fit.projectedFits[:]
|
||||
self.originalModules = fit.projectedModules
|
||||
self.modules = fit.projectedModules[:]
|
||||
self.originalDrones = fit.projectedDrones
|
||||
self.drones = fit.projectedDrones[:]
|
||||
self.originalFighters = fit.projectedFighters
|
||||
self.fighters = fit.projectedFighters[:]
|
||||
|
||||
self.fits.sort(key=self.fitSort)
|
||||
@@ -216,10 +203,10 @@ class ProjectedView(d.Display):
|
||||
if item != -1:
|
||||
self.EnsureVisible(item)
|
||||
|
||||
self.deselectItems()
|
||||
self.unselectAll()
|
||||
|
||||
if not stuff:
|
||||
stuff = [DummyEntry("Drag an item or fit, or use right-click menu for wormhole effects")]
|
||||
stuff = [DummyEntry('Drag an item or fit, or use right-click menu for wormhole effects')]
|
||||
|
||||
self.update(stuff)
|
||||
|
||||
@@ -238,101 +225,140 @@ class ProjectedView(d.Display):
|
||||
return None
|
||||
|
||||
if row < numFits:
|
||||
stuff = self.fits[row]
|
||||
fit = self.fits[row]
|
||||
if fit in self.originalFits:
|
||||
return fit
|
||||
elif row - numFits < numMods:
|
||||
stuff = self.modules[row - numFits]
|
||||
mod = self.modules[row - numFits]
|
||||
if mod in self.originalModules:
|
||||
return mod
|
||||
elif row - numFits - numMods < numDrones:
|
||||
stuff = self.drones[row - numFits - numMods]
|
||||
drone = self.drones[row - numFits - numMods]
|
||||
if drone in self.originalDrones:
|
||||
return drone
|
||||
else:
|
||||
stuff = self.fighters[row - numFits - numMods - numDrones]
|
||||
|
||||
return stuff
|
||||
fighter = self.fighters[row - numFits - numMods - numDrones]
|
||||
if fighter in self.originalFighters:
|
||||
return fighter
|
||||
return None
|
||||
|
||||
def click(self, event):
|
||||
event.Skip()
|
||||
row, _ = self.HitTest(event.Position)
|
||||
if row != -1:
|
||||
mainRow, _ = self.HitTest(event.Position)
|
||||
if mainRow != -1:
|
||||
col = self.getColumn(event.Position)
|
||||
if col == self.getColIndex(State):
|
||||
mainItem = self.get(mainRow)
|
||||
if mainItem is None:
|
||||
return
|
||||
selection = self.getSelectedProjectors()
|
||||
if mainItem not in selection:
|
||||
selection = [mainItem]
|
||||
modPressed = wx.GetMouseState().GetModifiers() == wx.MOD_ALT
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
thing = self.get(row)
|
||||
button = event.GetButton()
|
||||
if isinstance(thing, es_Fit) and button != 3:
|
||||
self.mainFrame.command.Submit(cmd.GuiToggleProjectedFitStateCommand(
|
||||
fitID=fitID, projectedFitID=thing.ID))
|
||||
elif isinstance(thing, es_Module):
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeProjectedModuleStateCommand(
|
||||
fitID=fitID,
|
||||
position=Fit.getInstance().getFit(fitID).projectedModules.index(thing),
|
||||
click='right' if button == 3 else 'left'))
|
||||
elif isinstance(thing, es_Drone) and button != 3:
|
||||
self.mainFrame.command.Submit(cmd.GuiToggleProjectedDroneStateCommand(
|
||||
fitID=fitID, itemID=thing.itemID))
|
||||
elif isinstance(thing, es_Fighter) and button != 3:
|
||||
self.mainFrame.command.Submit(cmd.GuiToggleProjectedFighterStateCommand(
|
||||
fitID=fitID, position=Fit.getInstance().getFit(fitID).projectedFighters.index(thing)))
|
||||
if isinstance(mainItem, EosModule) and modPressed:
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
positions = getSimilarModPositions(fit.projectedModules, mainItem)
|
||||
selection = [fit.projectedModules[p] for p in positions]
|
||||
elif isinstance(mainItem, EosFighter) and modPressed:
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
selection = getSimilarFighters(fit.projectedFighters, mainItem)
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeProjectedItemStatesCommand(
|
||||
fitID=fitID,
|
||||
mainItem=mainItem,
|
||||
items=selection,
|
||||
click='right' if event.GetButton() == 3 else 'left'))
|
||||
return
|
||||
event.Skip()
|
||||
|
||||
def spawnMenu(self, event):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
if fitID is None:
|
||||
return
|
||||
|
||||
if self.getColumn(self.ScreenToClient(event.Position)) == self.getColIndex(State):
|
||||
if self.getColumn(self.screenToClientFixed(event.Position)) == self.getColIndex(State):
|
||||
return
|
||||
|
||||
sel = self.GetFirstSelected()
|
||||
context = ()
|
||||
item = self.get(sel)
|
||||
clickedPos = self.getRowByAbs(event.Position)
|
||||
mainItem = self.get(clickedPos)
|
||||
|
||||
if item is not None:
|
||||
contexts = []
|
||||
if mainItem is not None:
|
||||
sMkt = Market.getInstance()
|
||||
|
||||
if isinstance(item, es_Drone):
|
||||
srcContext = "projectedDrone"
|
||||
itemContext = sMkt.getCategoryByItem(item.item).name
|
||||
context = ((srcContext, itemContext),)
|
||||
elif isinstance(item, es_Fighter):
|
||||
srcContext = "projectedFighter"
|
||||
itemContext = sMkt.getCategoryByItem(item.item).name
|
||||
context = ((srcContext, itemContext),)
|
||||
elif isinstance(item, es_Module):
|
||||
modSrcContext = "projectedModule"
|
||||
modItemContext = sMkt.getCategoryByItem(item.item).name
|
||||
if isinstance(mainItem, EosModule):
|
||||
modSrcContext = 'projectedModule'
|
||||
modItemContext = 'Projected Item'
|
||||
modFullContext = (modSrcContext, modItemContext)
|
||||
if item.charge is not None:
|
||||
chgSrcContext = "projectedCharge"
|
||||
chgItemContext = sMkt.getCategoryByItem(item.charge).name
|
||||
chgFullContext = (chgSrcContext, chgItemContext)
|
||||
context = (modFullContext, chgFullContext)
|
||||
else:
|
||||
context = (modFullContext,)
|
||||
contexts.append(modFullContext)
|
||||
if mainItem.charge is not None:
|
||||
chargeSrcContext = 'projectedCharge'
|
||||
chargeItemContext = sMkt.getCategoryByItem(mainItem.charge).name
|
||||
chargeFullContext = (chargeSrcContext, chargeItemContext)
|
||||
contexts.append(chargeFullContext)
|
||||
elif isinstance(mainItem, EosDrone):
|
||||
srcContext = 'projectedDrone'
|
||||
itemContext = 'Projected Item'
|
||||
droneFullContext = (srcContext, itemContext)
|
||||
contexts.append(droneFullContext)
|
||||
elif isinstance(mainItem, EosFighter):
|
||||
srcContext = 'projectedFighter'
|
||||
itemContext = 'Projected Item'
|
||||
fighterFullContext = (srcContext, itemContext)
|
||||
contexts.append(fighterFullContext)
|
||||
else:
|
||||
fitSrcContext = "projectedFit"
|
||||
fitItemContext = item.name
|
||||
context = ((fitSrcContext, fitItemContext),)
|
||||
|
||||
context += (("projected",),)
|
||||
menu = ContextMenu.getMenu((item,) if item is not None else [], *context)
|
||||
fitSrcContext = 'projectedFit'
|
||||
fitItemContext = 'Projected Item'
|
||||
fitFullContext = (fitSrcContext, fitItemContext)
|
||||
contexts.append(fitFullContext)
|
||||
contexts.append(('projected',))
|
||||
|
||||
selection = self.getSelectedProjectors()
|
||||
menu = ContextMenu.getMenu(mainItem, selection, *contexts)
|
||||
if menu is not None:
|
||||
self.PopupMenu(menu)
|
||||
|
||||
def remove(self, event):
|
||||
def onLeftDoubleClick(self, event):
|
||||
row, _ = self.HitTest(event.Position)
|
||||
if row != -1:
|
||||
col = self.getColumn(event.Position)
|
||||
if col != self.getColIndex(State):
|
||||
mainItem = self.get(row)
|
||||
if mainItem is None:
|
||||
return
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
thing = self.get(row)
|
||||
if isinstance(thing, es_Fit):
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedFitCommand(
|
||||
fitID=fitID, projectedFitID=thing.ID))
|
||||
elif isinstance(thing, es_Module):
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedModuleCommand(
|
||||
fitID=fitID, position=Fit.getInstance().getFit(fitID).projectedModules.index(thing)))
|
||||
elif isinstance(thing, es_Drone):
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedDroneCommand(
|
||||
fitID=fitID, itemID=thing.itemID, amount=1))
|
||||
elif isinstance(thing, es_Fighter):
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedFighterCommand(
|
||||
fitID=fitID, position=Fit.getInstance().getFit(fitID).projectedFighters.index(thing)))
|
||||
modPressed = wx.GetMouseState().GetModifiers() == wx.MOD_ALT
|
||||
if isinstance(mainItem, EosFit):
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedItemsCommand(
|
||||
fitID=fitID, items=[mainItem], amount=math.inf if modPressed else 1))
|
||||
elif isinstance(mainItem, EosModule):
|
||||
if modPressed:
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
positions = getSimilarModPositions(fit.projectedModules, mainItem)
|
||||
items = [fit.projectedModules[p] for p in positions]
|
||||
else:
|
||||
items = [mainItem]
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedItemsCommand(
|
||||
fitID=fitID, items=items, amount=1))
|
||||
elif isinstance(mainItem, EosDrone):
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedItemsCommand(
|
||||
fitID=fitID, items=[mainItem], amount=math.inf if modPressed else 1))
|
||||
elif isinstance(mainItem, EosFighter):
|
||||
if modPressed:
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
items = getSimilarFighters(fit.projectedFighters, mainItem)
|
||||
else:
|
||||
items = [mainItem]
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedItemsCommand(
|
||||
fitID=fitID, items=items, amount=1))
|
||||
else:
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedItemsCommand(
|
||||
fitID=fitID, items=[mainItem], amount=math.inf if modPressed else 1))
|
||||
|
||||
def getSelectedProjectors(self):
|
||||
projectors = []
|
||||
for row in self.getSelectedRows():
|
||||
projector = self.get(row)
|
||||
if projector is None:
|
||||
continue
|
||||
projectors.append(projector)
|
||||
return projectors
|
||||
|
||||
@@ -15,16 +15,18 @@ from gui.builtinContextMenus import ( # noqa: E402,F401
|
||||
# Item info
|
||||
itemStats,
|
||||
itemMarketJump,
|
||||
fitSystemSecurity, # Not really an item info but want to keep it here
|
||||
shipJump,
|
||||
# Generic item manipulations
|
||||
itemRemove,
|
||||
moduleMutations,
|
||||
itemAmountChange,
|
||||
droneSplitStack,
|
||||
itemVariationChange,
|
||||
moduleMutations,
|
||||
moduleFill,
|
||||
skillAffectors,
|
||||
# Market stuff
|
||||
itemFill,
|
||||
droneAddStack,
|
||||
cargoAdd,
|
||||
cargoAddAmmo,
|
||||
|
||||
@@ -1,42 +1,44 @@
|
||||
from gui.contextMenu import ContextMenu
|
||||
import gui.mainFrame
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
|
||||
import gui.globalEvents as GE
|
||||
import gui.mainFrame
|
||||
from gui.contextMenu import ContextMenuSingle
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class AmmoToDmgPattern(ContextMenu):
|
||||
class AmmoToDmgPattern(ContextMenuSingle):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
def display(self, srcContext, mainItem):
|
||||
if not self.settings.get('ammoPattern'):
|
||||
return False
|
||||
|
||||
if srcContext not in ("marketItemGroup", "marketItemMisc") or self.mainFrame.getActiveFit() is None:
|
||||
return False
|
||||
|
||||
item = selection[0]
|
||||
if mainItem is None:
|
||||
return False
|
||||
|
||||
for attr in ("emDamage", "thermalDamage", "explosiveDamage", "kineticDamage"):
|
||||
if item.getAttribute(attr) is not None:
|
||||
if mainItem.getAttribute(attr) is not None:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
return "Set {0} as Damage Pattern".format(itmContext if itmContext is not None else "Item")
|
||||
def getText(self, itmContext, mainItem):
|
||||
return "Set {} as Damage Pattern".format(itmContext if itmContext is not None else "Item")
|
||||
|
||||
def activate(self, fullContext, selection, i):
|
||||
item = selection[0]
|
||||
fit = self.mainFrame.getActiveFit()
|
||||
sFit = Fit.getInstance()
|
||||
sFit.setAsPattern(fit, item)
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fit))
|
||||
def activate(self, fullContext, mainItem, i):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
Fit.getInstance().setAsPattern(fitID, mainItem)
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))
|
||||
|
||||
def getBitmap(self, context, selection):
|
||||
def getBitmap(self, context, mainItem):
|
||||
return None
|
||||
|
||||
|
||||
|
||||
@@ -3,24 +3,25 @@ import wx
|
||||
|
||||
import gui.mainFrame
|
||||
from gui import fitCommands as cmd
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuSingle
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class BoosterSideEffect(ContextMenu):
|
||||
class BoosterSideEffects(ContextMenuSingle):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
# if not self.settings.get('fighterAbilities'):
|
||||
# return False
|
||||
|
||||
def display(self, srcContext, mainItem):
|
||||
if self.mainFrame.getActiveFit() is None or srcContext not in "boosterItem":
|
||||
return False
|
||||
|
||||
self.booster = selection[0]
|
||||
if mainItem is None:
|
||||
return False
|
||||
|
||||
self.booster = mainItem
|
||||
|
||||
for effect in self.booster.sideEffects:
|
||||
if effect.effect.isImplemented:
|
||||
@@ -28,19 +29,19 @@ class BoosterSideEffect(ContextMenu):
|
||||
|
||||
return False
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
def getText(self, itmContext, mainItem):
|
||||
return "Side Effects"
|
||||
|
||||
def addEffect(self, menu, ability):
|
||||
label = ability.name
|
||||
id = ContextMenu.nextID()
|
||||
id = ContextMenuSingle.nextID()
|
||||
self.effectIds[id] = ability
|
||||
|
||||
menuItem = wx.MenuItem(menu, id, label, kind=wx.ITEM_CHECK)
|
||||
menu.Bind(wx.EVT_MENU, self.handleMode, menuItem)
|
||||
return menuItem
|
||||
|
||||
def getSubMenu(self, context, selection, rootMenu, i, pitem):
|
||||
def getSubMenu(self, context, mainItem, rootMenu, i, pitem):
|
||||
msw = True if "wxMSW" in wx.PlatformInfo else False
|
||||
self.context = context
|
||||
self.effectIds = {}
|
||||
@@ -58,14 +59,17 @@ class BoosterSideEffect(ContextMenu):
|
||||
|
||||
def handleMode(self, event):
|
||||
effect = self.effectIds[event.Id]
|
||||
if effect is False or effect not in self.booster.sideEffects:
|
||||
booster = self.booster
|
||||
if effect is False or effect not in booster.sideEffects:
|
||||
event.Skip()
|
||||
return
|
||||
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
index = fit.boosters.index(self.booster)
|
||||
self.mainFrame.command.Submit(cmd.GuiToggleBoosterSideEffectStateCommand(fitID, index, effect.effectID))
|
||||
if booster in fit.boosters:
|
||||
index = fit.boosters.index(booster)
|
||||
self.mainFrame.command.Submit(cmd.GuiToggleBoosterSideEffectStateCommand(
|
||||
fitID=fitID, position=index, effectID=effect.effectID))
|
||||
|
||||
|
||||
BoosterSideEffect.register()
|
||||
BoosterSideEffects.register()
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
import gui.fitCommands as cmd
|
||||
import gui.mainFrame
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuSingle
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class AddToCargo(ContextMenu):
|
||||
class AddToCargo(ContextMenuSingle):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
def display(self, srcContext, mainItem):
|
||||
if srcContext not in ("marketItemGroup", "marketItemMisc"):
|
||||
return False
|
||||
|
||||
if mainItem is None:
|
||||
return False
|
||||
|
||||
sFit = Fit.getInstance()
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = sFit.getFit(fitID)
|
||||
@@ -23,16 +27,15 @@ class AddToCargo(ContextMenu):
|
||||
|
||||
return True
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
def getText(self, itmContext, mainItem):
|
||||
return "Add {} to Cargo".format(itmContext)
|
||||
|
||||
def activate(self, fullContext, selection, i):
|
||||
def activate(self, fullContext, mainItem, i):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
|
||||
typeID = int(selection[0].ID)
|
||||
|
||||
self.mainFrame.command.Submit(cmd.GuiAddCargoCommand(fitID, typeID, 1))
|
||||
self.mainFrame.additionsPane.select("Cargo")
|
||||
typeID = int(mainItem.ID)
|
||||
command = cmd.GuiAddCargoCommand(fitID=fitID, itemID=typeID, amount=1)
|
||||
if self.mainFrame.command.Submit(command):
|
||||
self.mainFrame.additionsPane.select("Cargo", focus=False)
|
||||
|
||||
|
||||
AddToCargo.register()
|
||||
|
||||
@@ -1,32 +1,36 @@
|
||||
import gui.fitCommands as cmd
|
||||
import gui.mainFrame
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuSingle
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class AddToCargoAmmo(ContextMenu):
|
||||
class AddToCargoAmmo(ContextMenuSingle):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
def display(self, srcContext, mainItem):
|
||||
if srcContext not in ("marketItemGroup", "marketItemMisc") or self.mainFrame.getActiveFit() is None:
|
||||
return False
|
||||
|
||||
for selected_item in selection:
|
||||
if selected_item.category.ID in (
|
||||
8, # Charge
|
||||
):
|
||||
return True
|
||||
if mainItem is None:
|
||||
return False
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
if mainItem.category.ID != 8:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def getText(self, itmContext, mainItem):
|
||||
return "Add {0} to Cargo (x1000)".format(itmContext)
|
||||
|
||||
def activate(self, fullContext, selection, i):
|
||||
def activate(self, fullContext, mainItem, i):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
typeID = int(selection[0].ID)
|
||||
self.mainFrame.command.Submit(cmd.GuiAddCargoCommand(fitID, typeID, 1000))
|
||||
self.mainFrame.additionsPane.select("Cargo")
|
||||
typeID = int(mainItem.ID)
|
||||
command = cmd.GuiAddCargoCommand(fitID=fitID, itemID=typeID, amount=1000)
|
||||
if self.mainFrame.command.Submit(command):
|
||||
self.mainFrame.additionsPane.select("Cargo", focus=False)
|
||||
|
||||
|
||||
AddToCargoAmmo.register()
|
||||
|
||||
@@ -3,13 +3,14 @@ import wx
|
||||
|
||||
import gui.fitCommands as cmd
|
||||
import gui.mainFrame
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuUnconditional
|
||||
from service.fit import Fit
|
||||
from service.market import Market
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class AddCommandFit(ContextMenu):
|
||||
class AddCommandFit(ContextMenuUnconditional):
|
||||
|
||||
# Get list of items that define a command fit
|
||||
sMkt = Market.getInstance()
|
||||
grp = sMkt.getGroup(1770) # Command burst group
|
||||
@@ -41,24 +42,24 @@ class AddCommandFit(ContextMenu):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
def display(self, srcContext):
|
||||
if self.mainFrame.getActiveFit() is None or len(self.__class__.commandFits) == 0 or srcContext != "commandView":
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
def getText(self, itmContext):
|
||||
return "Command Fits"
|
||||
|
||||
def addFit(self, menu, fit, includeShip=False):
|
||||
label = fit.name if not includeShip else "({}) {}".format(fit.ship.item.name, fit.name)
|
||||
id = ContextMenu.nextID()
|
||||
id = ContextMenuUnconditional.nextID()
|
||||
self.fitMenuItemIds[id] = fit
|
||||
menuItem = wx.MenuItem(menu, id, label)
|
||||
menu.Bind(wx.EVT_MENU, self.handleSelection, menuItem)
|
||||
return menuItem
|
||||
|
||||
def getSubMenu(self, context, selection, rootMenu, i, pitem):
|
||||
def getSubMenu(self, context, rootMenu, i, pitem):
|
||||
msw = True if "wxMSW" in wx.PlatformInfo else False
|
||||
self.context = context
|
||||
self.fitMenuItemIds = {}
|
||||
@@ -79,7 +80,7 @@ class AddCommandFit(ContextMenu):
|
||||
typeDict[shipName].append(fit)
|
||||
|
||||
for ship in sorted(typeDict.keys()):
|
||||
shipItem = wx.MenuItem(sub, ContextMenu.nextID(), ship)
|
||||
shipItem = wx.MenuItem(sub, ContextMenuUnconditional.nextID(), ship)
|
||||
grandSub = wx.Menu()
|
||||
shipItem.SetSubMenu(grandSub)
|
||||
|
||||
@@ -98,7 +99,7 @@ class AddCommandFit(ContextMenu):
|
||||
return
|
||||
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
self.mainFrame.command.Submit(cmd.GuiAddCommandFitCommand(fitID, fit.ID))
|
||||
self.mainFrame.command.Submit(cmd.GuiAddCommandFitCommand(fitID=fitID, commandFitID=fit.ID))
|
||||
|
||||
|
||||
AddCommandFit.populateFits(None)
|
||||
|
||||
@@ -6,25 +6,26 @@ import wx
|
||||
import gui.globalEvents as GE
|
||||
import gui.mainFrame
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuUnconditional
|
||||
from service.damagePattern import DamagePattern as import_DamagePattern
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class ChangeDamagePattern(ContextMenu):
|
||||
class ChangeDamagePattern(ContextMenuUnconditional):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
def display(self, srcContext):
|
||||
return srcContext == "resistancesViewFull"
|
||||
|
||||
@property
|
||||
def enabled(self):
|
||||
return self.mainFrame.getActiveFit() is not None
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
def getText(self, itmContext):
|
||||
sDP = import_DamagePattern.getInstance()
|
||||
sFit = Fit.getInstance()
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
@@ -55,7 +56,7 @@ class ChangeDamagePattern(ContextMenu):
|
||||
return self.m
|
||||
|
||||
def addPattern(self, rootMenu, pattern):
|
||||
id = ContextMenu.nextID()
|
||||
id = ContextMenuUnconditional.nextID()
|
||||
name = getattr(pattern, "_name", pattern.name) if pattern is not None else "No Profile"
|
||||
|
||||
self.patternIds[id] = pattern
|
||||
@@ -76,7 +77,7 @@ class ChangeDamagePattern(ContextMenu):
|
||||
menuItem.SetBitmap(bitmap)
|
||||
return menuItem
|
||||
|
||||
def getSubMenu(self, context, selection, rootMenu, i, pitem):
|
||||
def getSubMenu(self, context, rootMenu, i, pitem):
|
||||
msw = True if "wxMSW" in wx.PlatformInfo else False
|
||||
|
||||
if self.m[i] not in self.subMenus:
|
||||
|
||||
@@ -1,34 +1,50 @@
|
||||
import gui.fitCommands as cmd
|
||||
import gui.mainFrame
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuSingle
|
||||
from gui.fitCommands.helpers import droneStackLimit
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class DroneAddStack(ContextMenu):
|
||||
class DroneAddStack(ContextMenuSingle):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if srcContext not in ('marketItemGroup', 'marketItemMisc') or self.mainFrame.getActiveFit() is None:
|
||||
def display(self, srcContext, mainItem):
|
||||
if srcContext not in ('marketItemGroup', 'marketItemMisc'):
|
||||
return False
|
||||
|
||||
for selected_item in selection:
|
||||
if selected_item.category.ID in (
|
||||
18, # Drones
|
||||
):
|
||||
return True
|
||||
if self.mainFrame.getActiveFit() is None:
|
||||
return False
|
||||
|
||||
return False
|
||||
if mainItem is None:
|
||||
return False
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
return "Add {0} to Drone Bay (x5)".format(itmContext)
|
||||
if mainItem.category.name != 'Drone':
|
||||
return False
|
||||
|
||||
def activate(self, fullContext, selection, i):
|
||||
self.mainFrame.command.Submit(cmd.GuiAddLocalDroneCommand(
|
||||
fitID=self.mainFrame.getActiveFit(), itemID=int(selection[0].ID), amount=5))
|
||||
self.mainFrame.additionsPane.select('Drones')
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
amount = droneStackLimit(fit, mainItem)
|
||||
if amount < 1:
|
||||
return False
|
||||
|
||||
self.amount = amount
|
||||
return True
|
||||
|
||||
def getText(self, itmContext, mainItem):
|
||||
return 'Add {} to Drone Bay{}'.format(
|
||||
itmContext, '' if self.amount == 1 else ' (x{})'.format(self.amount))
|
||||
|
||||
def activate(self, fullContext, mainItem, i):
|
||||
command = cmd.GuiAddLocalDroneCommand(
|
||||
fitID=self.mainFrame.getActiveFit(),
|
||||
itemID=int(mainItem.ID),
|
||||
amount=self.amount)
|
||||
if self.mainFrame.command.Submit(command):
|
||||
self.mainFrame.additionsPane.select('Drones', focus=False)
|
||||
|
||||
|
||||
DroneAddStack.register()
|
||||
|
||||
@@ -5,26 +5,31 @@ import wx
|
||||
|
||||
import gui.fitCommands as cmd
|
||||
import gui.mainFrame
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuSingle
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class DroneSplitStack(ContextMenu):
|
||||
class DroneSplitStack(ContextMenuSingle):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
return srcContext == "droneItem" and selection[0].amount > 1
|
||||
def display(self, srcContext, mainItem):
|
||||
if srcContext != "droneItem":
|
||||
return False
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
return "Split {0} Stack".format(itmContext)
|
||||
if mainItem is None:
|
||||
return False
|
||||
|
||||
def activate(self, fullContext, selection, i):
|
||||
srcContext = fullContext[0]
|
||||
drone = selection[0]
|
||||
dlg = DroneStackSplit(self.mainFrame, drone.amount)
|
||||
return mainItem.amount > 1
|
||||
|
||||
def getText(self, itmContext, mainItem):
|
||||
return "Split {} Stack".format(itmContext)
|
||||
|
||||
def activate(self, fullContext, mainItem, i):
|
||||
dlg = DroneStackSplit(self.mainFrame, mainItem.amount)
|
||||
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
|
||||
@@ -35,10 +40,10 @@ class DroneSplitStack(ContextMenu):
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
cleanInput = re.sub(r'[^0-9.]', '', dlg.input.GetLineText(0).strip())
|
||||
|
||||
self.mainFrame.command.Submit(cmd.GuiSplitLocalDroneStackCommand(
|
||||
fitID=fitID,
|
||||
position=fit.drones.index(drone),
|
||||
amount=int(cleanInput)))
|
||||
if mainItem in fit.drones:
|
||||
position = fit.drones.index(mainItem)
|
||||
self.mainFrame.command.Submit(cmd.GuiSplitLocalDroneStackCommand(
|
||||
fitID=fitID, position=position, amount=int(cleanInput)))
|
||||
|
||||
|
||||
DroneSplitStack.register()
|
||||
|
||||
@@ -6,12 +6,12 @@ import wx
|
||||
|
||||
import gui.fitCommands as cmd
|
||||
import gui.mainFrame
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuUnconditional
|
||||
from service.market import Market
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class AddEnvironmentEffect(ContextMenu):
|
||||
class AddEnvironmentEffect(ContextMenuUnconditional):
|
||||
|
||||
# CCP doesn't currently provide a mapping between the general Environment, and the specific environment effect
|
||||
# (which can be random when going into Abyssal space). This is how we currently define it:
|
||||
@@ -28,13 +28,13 @@ class AddEnvironmentEffect(ContextMenu):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
def display(self, srcContext):
|
||||
return srcContext == "projected"
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
def getText(self, itmContext):
|
||||
return "Add Environmental Effect"
|
||||
|
||||
def getSubMenu(self, context, selection, rootMenu, i, pitem):
|
||||
def getSubMenu(self, context, rootMenu, i, pitem):
|
||||
msw = True if "wxMSW" in wx.PlatformInfo else False
|
||||
|
||||
# Wormholes
|
||||
@@ -92,7 +92,7 @@ class AddEnvironmentEffect(ContextMenu):
|
||||
|
||||
def processFlat(data, root, sub):
|
||||
for swData in sorted(data, key=lambda tpl: tpl[2]):
|
||||
wxid = ContextMenu.nextID()
|
||||
wxid = ContextMenuUnconditional.nextID()
|
||||
swObj, swName, swClass = swData
|
||||
self.idmap[wxid] = (swObj, swName)
|
||||
subItem = wx.MenuItem(sub, wxid, swClass)
|
||||
@@ -123,7 +123,8 @@ class AddEnvironmentEffect(ContextMenu):
|
||||
|
||||
# Expressions for matching when detecting effects we're looking for
|
||||
if incursions:
|
||||
validgroups = ("Incursion ship attributes effects",)
|
||||
validgroups = ("Incursion ship attributes effects",
|
||||
"Invasion Effects")
|
||||
else:
|
||||
validgroups = ("Black Hole Effect Beacon",
|
||||
"Cataclysmic Variable Effect Beacon",
|
||||
@@ -133,7 +134,7 @@ class AddEnvironmentEffect(ContextMenu):
|
||||
"Wolf Rayet Effect Beacon")
|
||||
|
||||
# Stuff we don't want to see in names
|
||||
garbages = ("Effect", "Beacon", "ship attributes effects")
|
||||
garbages = ("Effects?", "Beacon", "ship attributes effects")
|
||||
|
||||
# Get group with all the system-wide beacons
|
||||
grp = sMkt.getGroup("Effect Beacon")
|
||||
|
||||
@@ -3,27 +3,28 @@ import wx
|
||||
|
||||
import gui.globalEvents as GE
|
||||
import gui.mainFrame
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuUnconditional
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class FactorReload(ContextMenu):
|
||||
class FactorReload(ContextMenuUnconditional):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
def display(self, srcContext):
|
||||
return srcContext == "firepowerViewFull"
|
||||
|
||||
@property
|
||||
def enabled(self):
|
||||
return self.mainFrame.getActiveFit() is not None
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
def getText(self, itmContext):
|
||||
return "Factor in Reload Time"
|
||||
|
||||
def activate(self, fullContext, selection, i):
|
||||
def activate(self, fullContext, i):
|
||||
sFit = Fit.getInstance()
|
||||
sFit.serviceFittingOptions["useGlobalForceReload"] = not sFit.serviceFittingOptions["useGlobalForceReload"]
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
|
||||
@@ -3,37 +3,43 @@ import wx
|
||||
|
||||
import gui.mainFrame
|
||||
from gui import fitCommands as cmd
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.fitCommands.helpers import getSimilarFighters
|
||||
from gui.contextMenu import ContextMenuCombined
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class FighterAbilities(ContextMenu):
|
||||
class FighterAbilities(ContextMenuCombined):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
self.isProjected = None
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
def display(self, srcContext, mainItem, selection):
|
||||
if self.mainFrame.getActiveFit() is None or srcContext not in ("fighterItem", "projectedFighter"):
|
||||
return False
|
||||
|
||||
self.fighter = selection[0]
|
||||
if mainItem is None:
|
||||
return False
|
||||
|
||||
self.fighter = mainItem
|
||||
self.selection = selection
|
||||
self.isProjected = True if srcContext == "projectedFighter" else False
|
||||
return True
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
def getText(self, itmContext, mainItem, selection):
|
||||
return "Abilities"
|
||||
|
||||
def addAbility(self, menu, ability):
|
||||
label = ability.name
|
||||
id = ContextMenu.nextID()
|
||||
id = ContextMenuCombined.nextID()
|
||||
self.abilityIds[id] = ability
|
||||
menuItem = wx.MenuItem(menu, id, label, kind=wx.ITEM_CHECK)
|
||||
menu.Bind(wx.EVT_MENU, self.handleMode, menuItem)
|
||||
return menuItem
|
||||
|
||||
def getSubMenu(self, context, selection, rootMenu, i, pitem):
|
||||
def getSubMenu(self, context, mainItem, selection, rootMenu, i, pitem):
|
||||
msw = True if "wxMSW" in wx.PlatformInfo else False
|
||||
self.context = context
|
||||
self.abilityIds = {}
|
||||
@@ -58,12 +64,26 @@ class FighterAbilities(ContextMenu):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
if self.isProjected:
|
||||
self.mainFrame.command.Submit(cmd.GuiToggleProjectedFighterAbilityStateCommand(
|
||||
fitID=fitID, position=fit.projectedFighters.index(self.fighter), effectID=ability.effectID))
|
||||
container = fit.projectedFighters
|
||||
command = cmd.GuiToggleProjectedFighterAbilityStateCommand
|
||||
else:
|
||||
self.mainFrame.command.Submit(cmd.GuiToggleLocalFighterAbilityStateCommand(
|
||||
fitID=fitID, position=fit.fighters.index(self.fighter), effectID=ability.effectID))
|
||||
|
||||
container = fit.fighters
|
||||
command = cmd.GuiToggleLocalFighterAbilityStateCommand
|
||||
if self.fighter in container:
|
||||
mainPosition = container.index(self.fighter)
|
||||
if wx.GetMouseState().GetModifiers() == wx.MOD_ALT:
|
||||
fighters = getSimilarFighters(container, self.fighter)
|
||||
else:
|
||||
fighters = self.selection
|
||||
positions = []
|
||||
for fighter in fighters:
|
||||
if fighter in container:
|
||||
positions.append(container.index(fighter))
|
||||
self.mainFrame.command.Submit(command(
|
||||
fitID=fitID,
|
||||
mainPosition=mainPosition,
|
||||
positions=positions,
|
||||
effectID=ability.effectID))
|
||||
|
||||
|
||||
FighterAbilities.register()
|
||||
|
||||
@@ -4,25 +4,26 @@ import wx
|
||||
import gui.fitCommands as cmd
|
||||
import gui.mainFrame
|
||||
from gui.builtinViews.emptyView import BlankPage
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuUnconditional
|
||||
from service.fit import Fit
|
||||
|
||||
|
||||
class AddCurrentlyOpenFit(ContextMenu):
|
||||
class AddCurrentlyOpenFit(ContextMenuUnconditional):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
def display(self, srcContext):
|
||||
|
||||
if self.mainFrame.getActiveFit() is None or srcContext not in ('projected', 'commandView'):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
def getText(self, itmContext):
|
||||
return 'Add Currently Open Fit'
|
||||
|
||||
def getSubMenu(self, context, selection, rootMenu, i, pitem):
|
||||
def getSubMenu(self, context, rootMenu, i, pitem):
|
||||
self.fitLookup = {}
|
||||
self.context = context
|
||||
sFit = Fit.getInstance()
|
||||
@@ -40,7 +41,7 @@ class AddCurrentlyOpenFit(ContextMenu):
|
||||
if isinstance(page, BlankPage):
|
||||
continue
|
||||
fit = sFit.getFit(page.activeFitID, basic=True)
|
||||
id = ContextMenu.nextID()
|
||||
id = ContextMenuUnconditional.nextID()
|
||||
mitem = wx.MenuItem(rootMenu, id, "{}: {}".format(fit.ship.item.name, fit.name))
|
||||
bindmenu.Bind(wx.EVT_MENU, self.handleSelection, mitem)
|
||||
self.fitLookup[id] = fit
|
||||
@@ -56,7 +57,7 @@ class AddCurrentlyOpenFit(ContextMenu):
|
||||
if self.context == 'commandView':
|
||||
self.mainFrame.command.Submit(cmd.GuiAddCommandFitCommand(fitID=fitID, commandFitID=fit.ID))
|
||||
elif self.context == 'projected':
|
||||
self.mainFrame.command.Submit(cmd.GuiAddProjectedFitCommand(fitID=fitID, projectedFitID=fit.ID))
|
||||
self.mainFrame.command.Submit(cmd.GuiAddProjectedFitCommand(fitID=fitID, projectedFitID=fit.ID, amount=1))
|
||||
|
||||
|
||||
AddCurrentlyOpenFit.register()
|
||||
|
||||
@@ -3,30 +3,34 @@ import wx
|
||||
|
||||
import gui.mainFrame
|
||||
from gui.builtinShipBrowser.events import FitSelected
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuSingle
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class OpenFitInNewTab(ContextMenu):
|
||||
class OpenFitInNewTab(ContextMenuSingle):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
def display(self, srcContext, mainItem):
|
||||
if srcContext not in ("projectedFit", "commandFit"):
|
||||
return False
|
||||
|
||||
if mainItem is None:
|
||||
return False
|
||||
|
||||
currentFitID = self.mainFrame.getActiveFit()
|
||||
selectedFitID = selection[0].ID
|
||||
selectedFitID = mainItem.ID
|
||||
if currentFitID == selectedFitID:
|
||||
return False
|
||||
return True
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
def getText(self, itmContext, mainItem):
|
||||
return "Open Fit in New Tab"
|
||||
|
||||
def activate(self, fullContext, selection, i):
|
||||
fit = selection[0]
|
||||
wx.PostEvent(self.mainFrame, FitSelected(fitID=fit.ID, startup=2))
|
||||
def activate(self, fullContext, mainItem, i):
|
||||
wx.PostEvent(self.mainFrame, FitSelected(fitID=mainItem.ID, startup=2))
|
||||
|
||||
|
||||
OpenFitInNewTab.register()
|
||||
|
||||
67
gui/builtinContextMenus/fitSystemSecurity.py
Normal file
67
gui/builtinContextMenus/fitSystemSecurity.py
Normal file
@@ -0,0 +1,67 @@
|
||||
from collections import OrderedDict
|
||||
|
||||
import wx
|
||||
|
||||
import gui.fitCommands as cmd
|
||||
import gui.mainFrame
|
||||
from eos.const import FitSystemSecurity
|
||||
from gui.contextMenu import ContextMenuUnconditional
|
||||
from service.fit import Fit
|
||||
|
||||
|
||||
optionMap = OrderedDict((
|
||||
('High Security', FitSystemSecurity.HISEC),
|
||||
('Low Security', FitSystemSecurity.LOWSEC),
|
||||
('Null Security', FitSystemSecurity.NULLSEC),
|
||||
('W-Space', FitSystemSecurity.WSPACE)))
|
||||
|
||||
|
||||
class FitSystemSecurityMenu(ContextMenuUnconditional):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
|
||||
def display(self, srcContext):
|
||||
if srcContext != "fittingShip":
|
||||
return False
|
||||
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
|
||||
if not fit.isStructure:
|
||||
return
|
||||
|
||||
return True
|
||||
|
||||
def getText(self, itmContext):
|
||||
return "Citadel System Security"
|
||||
|
||||
def addOption(self, menu, optionLabel):
|
||||
id = ContextMenuUnconditional.nextID()
|
||||
self.optionIds[id] = optionLabel
|
||||
menuItem = wx.MenuItem(menu, id, optionLabel, kind=wx.ITEM_CHECK)
|
||||
menu.Bind(wx.EVT_MENU, self.handleMode, menuItem)
|
||||
return menuItem
|
||||
|
||||
def getSubMenu(self, context, rootMenu, i, pitem):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
msw = True if "wxMSW" in wx.PlatformInfo else False
|
||||
self.optionIds = {}
|
||||
sub = wx.Menu()
|
||||
for optionLabel, optionValue in optionMap.items():
|
||||
menuItem = self.addOption(rootMenu if msw else sub, optionLabel)
|
||||
sub.Append(menuItem)
|
||||
menuItem.Check(fit.getSystemSecurity() == optionValue)
|
||||
|
||||
return sub
|
||||
|
||||
def handleMode(self, event):
|
||||
optionLabel = self.optionIds[event.Id]
|
||||
optionValue = optionMap[optionLabel]
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeFitSystemSecurityCommand(
|
||||
fitID=self.mainFrame.getActiveFit(),
|
||||
secStatus=optionValue))
|
||||
|
||||
|
||||
FitSystemSecurityMenu.register()
|
||||
@@ -4,18 +4,19 @@ import wx
|
||||
import gui.fitCommands as cmd
|
||||
import gui.globalEvents as GE
|
||||
import gui.mainFrame
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuSingle
|
||||
from service.character import Character
|
||||
from service.implantSet import ImplantSets as s_ImplantSets
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class addImplantSet(ContextMenu):
|
||||
class AddImplantSet(ContextMenuSingle):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
def display(self, srcContext, mainItem):
|
||||
|
||||
sIS = s_ImplantSets.getInstance()
|
||||
implantSets = sIS.getImplantSetList()
|
||||
@@ -24,17 +25,17 @@ class addImplantSet(ContextMenu):
|
||||
return False
|
||||
return srcContext in ("implantView", "implantEditor")
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
def getText(self, itmContext, mainItem):
|
||||
return "Add Implant Set"
|
||||
|
||||
def getSubMenu(self, context, selection, rootMenu, i, pitem):
|
||||
def getSubMenu(self, context, mainItem, rootMenu, i, pitem):
|
||||
"""
|
||||
A note on the selection here: Most context menus act on a fit, so it's easy enough to get the active fit from
|
||||
A note on the mainItem here: Most context menus act on a fit, so it's easy enough to get the active fit from
|
||||
the MainFrame instance. There's never been a reason to get info from another window, so there's not common
|
||||
way of doing this. However, we use this context menu within the Character Editor to apply implant sets to a
|
||||
character, so we need to access the character editor.
|
||||
|
||||
It is for these reasons that I hijack the selection parameter when calling the menu and pass a pointer to the
|
||||
It is for these reasons that I hijack the mainItem parameter when calling the menu and pass a pointer to the
|
||||
Character Editor. This way we can use it to get current editing character ID and apply the implants.
|
||||
|
||||
It would probably be better to have a function on the MainFrame to get the currently open Character Editor (as
|
||||
@@ -49,13 +50,12 @@ class addImplantSet(ContextMenu):
|
||||
implantSets = sIS.getImplantSetList()
|
||||
|
||||
self.context = context
|
||||
if len(selection) == 1:
|
||||
self.selection = selection[0] # dirty hack here
|
||||
self.mainItem = mainItem # dirty hack here
|
||||
|
||||
self.idmap = {}
|
||||
|
||||
for set in implantSets:
|
||||
id = ContextMenu.nextID()
|
||||
id = ContextMenuSingle.nextID()
|
||||
mitem = wx.MenuItem(rootMenu, id, set.name)
|
||||
bindmenu.Bind(wx.EVT_MENU, self.handleSelection, mitem)
|
||||
self.idmap[id] = set
|
||||
@@ -73,16 +73,16 @@ class addImplantSet(ContextMenu):
|
||||
if self.context == "implantEditor":
|
||||
# we are calling from character editor, the implant source is different
|
||||
sChar = Character.getInstance()
|
||||
char = self.selection.entityEditor.getActiveEntity()
|
||||
char = self.mainItem.entityEditor.getActiveEntity()
|
||||
|
||||
for implant in set.implants:
|
||||
sChar.addImplant(char.ID, implant.item.ID)
|
||||
|
||||
wx.PostEvent(self.selection, GE.CharChanged())
|
||||
wx.PostEvent(self.mainItem, GE.CharChanged())
|
||||
else:
|
||||
self.mainFrame.command.Submit(cmd.GuiAddImplantSetCommand(
|
||||
fitID=self.mainFrame.getActiveFit(),
|
||||
itemIDs=[i.itemID for i in set.implants]))
|
||||
|
||||
|
||||
addImplantSet.register()
|
||||
AddImplantSet.register()
|
||||
|
||||
@@ -9,35 +9,43 @@ from eos.saveddata.cargo import Cargo as es_Cargo
|
||||
from eos.saveddata.drone import Drone
|
||||
from eos.saveddata.fighter import Fighter as es_Fighter
|
||||
from eos.saveddata.fit import Fit as es_Fit
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuSingle
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class ChangeItemAmount(ContextMenu):
|
||||
class ChangeItemAmount(ContextMenuSingle):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
return srcContext in ("droneItem", "projectedDrone", "cargoItem", "projectedFit", "fighterItem", "projectedFighter")
|
||||
def display(self, srcContext, mainItem):
|
||||
if srcContext not in ("droneItem", "projectedDrone", "cargoItem", "projectedFit", "fighterItem", "projectedFighter"):
|
||||
return False
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
return u"Change {0} Quantity".format(itmContext)
|
||||
if mainItem is None:
|
||||
return False
|
||||
|
||||
def activate(self, fullContext, selection, i):
|
||||
thing = selection[0]
|
||||
mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
fitID = mainFrame.getActiveFit()
|
||||
return True
|
||||
|
||||
def getText(self, itmContext, mainItem):
|
||||
return "Change {0} Quantity".format(itmContext)
|
||||
|
||||
def activate(self, fullContext, mainItem, i):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
srcContext = fullContext[0]
|
||||
if isinstance(thing, es_Fit):
|
||||
value = thing.getProjectionInfo(fitID).amount
|
||||
elif isinstance(thing, es_Fighter):
|
||||
value = thing.amountActive
|
||||
if isinstance(mainItem, es_Fit):
|
||||
try:
|
||||
value = mainItem.getProjectionInfo(fitID).amount
|
||||
except AttributeError:
|
||||
return
|
||||
elif isinstance(mainItem, es_Fighter):
|
||||
value = mainItem.amountActive
|
||||
else:
|
||||
value = thing.amount
|
||||
value = mainItem.amount
|
||||
|
||||
dlg = AmountChanger(self.mainFrame, value, (0, 20)) if isinstance(thing, es_Fit) else AmountChanger(self.mainFrame, value)
|
||||
dlg = AmountChanger(self.mainFrame, value, (0, 20)) if isinstance(mainItem, es_Fit) else AmountChanger(self.mainFrame, value)
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
|
||||
if dlg.input.GetLineText(0).strip() == '':
|
||||
@@ -47,20 +55,32 @@ class ChangeItemAmount(ContextMenu):
|
||||
fit = sFit.getFit(fitID)
|
||||
cleanInput = int(float(re.sub(r'[^0-9.]', '', dlg.input.GetLineText(0).strip())))
|
||||
|
||||
if isinstance(thing, es_Cargo):
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeCargoAmountCommand(fitID, thing.itemID, cleanInput))
|
||||
elif isinstance(thing, Drone):
|
||||
if isinstance(mainItem, es_Cargo):
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeCargoAmountCommand(
|
||||
fitID=fitID, itemID=mainItem.itemID, amount=cleanInput))
|
||||
elif isinstance(mainItem, Drone):
|
||||
if srcContext == "projectedDrone":
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeProjectedDroneAmountCommand(fitID, thing.itemID, cleanInput))
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeProjectedDroneAmountCommand(
|
||||
fitID=fitID, itemID=mainItem.itemID, amount=cleanInput))
|
||||
else:
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeLocalDroneAmountCommand(fitID, fit.drones.index(thing), cleanInput))
|
||||
elif isinstance(thing, es_Fit):
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeProjectedFitAmountCommand(fitID, thing.ID, cleanInput))
|
||||
elif isinstance(thing, es_Fighter):
|
||||
if mainItem in fit.drones:
|
||||
position = fit.drones.index(mainItem)
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeLocalDroneAmountCommand(
|
||||
fitID=fitID, position=position, amount=cleanInput))
|
||||
elif isinstance(mainItem, es_Fit):
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeProjectedFitAmountCommand(
|
||||
fitID=fitID, projectedFitID=mainItem.ID, amount=cleanInput))
|
||||
elif isinstance(mainItem, es_Fighter):
|
||||
if srcContext == "projectedFighter":
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeProjectedFighterAmountCommand(fitID, fit.projectedFighters.index(thing), cleanInput))
|
||||
if mainItem in fit.projectedFighters:
|
||||
position = fit.projectedFighters.index(mainItem)
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeProjectedFighterAmountCommand(
|
||||
fitID=fitID, position=position, amount=cleanInput))
|
||||
else:
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeLocalFighterAmountCommand(fitID, fit.fighters.index(thing), cleanInput))
|
||||
if mainItem in fit.fighters:
|
||||
position = fit.fighters.index(mainItem)
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeLocalFighterAmountCommand(
|
||||
fitID=fitID, position=position, amount=cleanInput))
|
||||
|
||||
|
||||
ChangeItemAmount.register()
|
||||
|
||||
40
gui/builtinContextMenus/itemFill.py
Normal file
40
gui/builtinContextMenus/itemFill.py
Normal file
@@ -0,0 +1,40 @@
|
||||
import gui.fitCommands as cmd
|
||||
import gui.mainFrame
|
||||
from gui.contextMenu import ContextMenuSingle
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class FillWithItem(ContextMenuSingle):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, mainItem):
|
||||
if not self.settings.get('moduleFill'):
|
||||
return False
|
||||
|
||||
if srcContext not in ('marketItemGroup', 'marketItemMisc'):
|
||||
return False
|
||||
|
||||
if self.mainFrame.getActiveFit() is None:
|
||||
return False
|
||||
|
||||
if mainItem is None:
|
||||
return False
|
||||
|
||||
if mainItem.category.name != 'Module':
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def getText(self, itmContext, mainItem):
|
||||
return "Fill With Module"
|
||||
|
||||
def activate(self, fullContext, mainItem, i):
|
||||
self.mainFrame.command.Submit(cmd.GuiFillWithNewLocalModulesCommand(
|
||||
fitID=self.mainFrame.getActiveFit(),
|
||||
itemID=int(mainItem.ID)))
|
||||
|
||||
|
||||
FillWithItem.register()
|
||||
@@ -1,15 +1,15 @@
|
||||
import gui.mainFrame
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuSingle
|
||||
from service.market import Market
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class JumpToMarketItem(ContextMenu):
|
||||
class JumpToMarketItem(ContextMenuSingle):
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
def display(self, srcContext, mainItem):
|
||||
validContexts = ("marketItemMisc", "fittingModule",
|
||||
"fittingCharge", "droneItem",
|
||||
"implantItem", "boosterItem",
|
||||
@@ -18,37 +18,40 @@ class JumpToMarketItem(ContextMenu):
|
||||
"implantItemChar", "fighterItem",
|
||||
"projectedFighter")
|
||||
|
||||
if srcContext not in validContexts or selection is None or len(selection) < 1:
|
||||
if srcContext not in validContexts or mainItem is None:
|
||||
return False
|
||||
|
||||
if mainItem is None or getattr(mainItem, "isEmpty", False):
|
||||
return False
|
||||
|
||||
sMkt = Market.getInstance()
|
||||
item = getattr(selection[0], "item", selection[0])
|
||||
isMutated = getattr(selection[0], "isMutated", False)
|
||||
item = getattr(mainItem, "item", mainItem)
|
||||
isMutated = getattr(mainItem, "isMutated", False)
|
||||
mktGrp = sMkt.getMarketGroupByItem(item)
|
||||
if mktGrp is None and isMutated:
|
||||
mktGrp = sMkt.getMarketGroupByItem(selection[0].baseItem)
|
||||
mktGrp = sMkt.getMarketGroupByItem(mainItem.baseItem)
|
||||
|
||||
# 1663 is Special Edition Festival Assets, we don't have root group for it
|
||||
if mktGrp is None or mktGrp.ID == 1663:
|
||||
return False
|
||||
|
||||
doit = not selection[0].isEmpty if srcContext == "fittingModule" else True
|
||||
doit = not mainItem.isEmpty if srcContext == "fittingModule" else True
|
||||
return doit
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
def getText(self, itmContext, mainItem):
|
||||
return "{0} Market Group".format(itmContext if itmContext is not None else "Item")
|
||||
|
||||
def activate(self, fullContext, selection, i):
|
||||
def activate(self, fullContext, mainItem, i):
|
||||
srcContext = fullContext[0]
|
||||
if srcContext in ("fittingCharge", "projectedCharge"):
|
||||
item = selection[0].charge
|
||||
elif hasattr(selection[0], "item"):
|
||||
if getattr(selection[0], "isMutated", False):
|
||||
item = selection[0].baseItem
|
||||
item = mainItem.charge
|
||||
elif hasattr(mainItem, "item"):
|
||||
if getattr(mainItem, "isMutated", False):
|
||||
item = mainItem.baseItem
|
||||
else:
|
||||
item = selection[0].item
|
||||
item = mainItem.item
|
||||
else:
|
||||
item = selection[0]
|
||||
item = mainItem
|
||||
|
||||
self.mainFrame.notebookBrowsers.SetSelection(0)
|
||||
self.mainFrame.marketBrowser.jump(item)
|
||||
|
||||
@@ -1,22 +1,26 @@
|
||||
import gui.fitCommands as cmd
|
||||
import gui.mainFrame
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuSingle
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class ProjectItem(ContextMenu):
|
||||
class ProjectItem(ContextMenuSingle):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
def display(self, srcContext, mainItem):
|
||||
if not self.settings.get('project'):
|
||||
return False
|
||||
|
||||
if srcContext not in ("marketItemGroup", "marketItemMisc") or self.mainFrame.getActiveFit() is None:
|
||||
return False
|
||||
|
||||
if mainItem is None:
|
||||
return False
|
||||
|
||||
sFit = Fit.getInstance()
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = sFit.getFit(fitID)
|
||||
@@ -24,25 +28,23 @@ class ProjectItem(ContextMenu):
|
||||
if fit.isStructure:
|
||||
return False
|
||||
|
||||
item = selection[0]
|
||||
return item.isType("projected")
|
||||
return mainItem.isType("projected")
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
def getText(self, itmContext, mainItem):
|
||||
return "Project {0} onto Fit".format(itmContext)
|
||||
|
||||
def activate(self, fullContext, selection, i):
|
||||
def activate(self, fullContext, mainItem, i):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
category = selection[0].category.name
|
||||
if category == 'Module':
|
||||
success = self.mainFrame.command.Submit(cmd.GuiAddProjectedModuleCommand(fitID=fitID, itemID=selection[0].ID))
|
||||
elif category == 'Drone':
|
||||
success = self.mainFrame.command.Submit(cmd.GuiAddProjectedDroneCommand(fitID=fitID, itemID=selection[0].ID))
|
||||
elif category == 'Fighter':
|
||||
success = self.mainFrame.command.Submit(cmd.GuiAddProjectedFighterCommand(fitID=fitID, itemID=selection[0].ID))
|
||||
if mainItem.isModule:
|
||||
success = self.mainFrame.command.Submit(cmd.GuiAddProjectedModuleCommand(fitID=fitID, itemID=mainItem.ID))
|
||||
elif mainItem.isDrone:
|
||||
success = self.mainFrame.command.Submit(cmd.GuiAddProjectedDroneCommand(fitID=fitID, itemID=mainItem.ID))
|
||||
elif mainItem.isFighter:
|
||||
success = self.mainFrame.command.Submit(cmd.GuiAddProjectedFighterCommand(fitID=fitID, itemID=mainItem.ID))
|
||||
else:
|
||||
success = False
|
||||
if success:
|
||||
self.mainFrame.additionsPane.select('Projected')
|
||||
self.mainFrame.additionsPane.select('Projected', focus=False)
|
||||
|
||||
|
||||
ProjectItem.register()
|
||||
|
||||
@@ -1,71 +1,163 @@
|
||||
import math
|
||||
|
||||
import wx
|
||||
|
||||
import gui.fitCommands as cmd
|
||||
import gui.mainFrame
|
||||
from gui.contextMenu import ContextMenu
|
||||
from eos.saveddata.drone import Drone as EosDrone
|
||||
from eos.saveddata.fighter import Fighter as EosFighter
|
||||
from eos.saveddata.fit import Fit as EosFit
|
||||
from eos.saveddata.module import Module as EosModule
|
||||
from gui.contextMenu import ContextMenuCombined
|
||||
from gui.fitCommands.helpers import getSimilarFighters, getSimilarModPositions
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class RemoveItem(ContextMenu):
|
||||
class RemoveItem(ContextMenuCombined):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
return srcContext in ("fittingModule", "droneItem",
|
||||
"implantItem", "boosterItem",
|
||||
"projectedModule", "cargoItem",
|
||||
"projectedFit", "projectedDrone",
|
||||
"fighterItem", "projectedFighter",
|
||||
"commandFit")
|
||||
def display(self, srcContext, mainItem, selection):
|
||||
if srcContext not in (
|
||||
"fittingModule", "droneItem",
|
||||
"implantItem", "boosterItem",
|
||||
"projectedModule", "cargoItem",
|
||||
"projectedFit", "projectedDrone",
|
||||
"fighterItem", "projectedFighter",
|
||||
"commandFit"
|
||||
):
|
||||
return False
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
return u"Remove {0}".format(itmContext if itmContext is not None else "Item")
|
||||
if mainItem is None or getattr(mainItem, "isEmpty", False):
|
||||
return False
|
||||
|
||||
def activate(self, fullContext, selection, i):
|
||||
self.srcContext = srcContext
|
||||
return True
|
||||
|
||||
def getText(self, itmContext, mainItem, selection):
|
||||
return 'Remove {}{}'.format(
|
||||
itmContext if itmContext is not None else 'Item',
|
||||
' Stack' if self.srcContext in ('droneItem', 'projectedDrone', 'cargoItem', 'projectedFit') else '')
|
||||
|
||||
def activate(self, fullContext, mainItem, selection, i):
|
||||
handlerMap = {
|
||||
'fittingModule': self.__handleModule,
|
||||
'droneItem': self.__handleDrone,
|
||||
'fighterItem': self.__handleFighter,
|
||||
'implantItem': self.__handleImplant,
|
||||
'boosterItem': self.__handleBooster,
|
||||
'cargoItem': self.__handleCargo,
|
||||
'projectedFit': self.__handleProjectedItem,
|
||||
'projectedModule': self.__handleProjectedItem,
|
||||
'projectedDrone': self.__handleProjectedItem,
|
||||
'projectedFighter': self.__handleProjectedItem,
|
||||
'commandFit': self.__handleCommandFit}
|
||||
srcContext = fullContext[0]
|
||||
sFit = Fit.getInstance()
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = sFit.getFit(fitID)
|
||||
handler = handlerMap.get(srcContext)
|
||||
if handler is None:
|
||||
return
|
||||
handler(mainItem, selection)
|
||||
|
||||
if srcContext == "fittingModule":
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveLocalModuleCommand(
|
||||
fitID=fitID, modules=[module for module in selection if module is not None]))
|
||||
elif srcContext == "fittingCharge":
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeLocalModuleChargesCommand(
|
||||
fitID=fitID, modules=selection, chargeItemID=None))
|
||||
elif srcContext == "droneItem":
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveLocalDroneCommand(
|
||||
fitID=fitID, position=fit.drones.index(selection[0]), amount=math.inf))
|
||||
elif srcContext == "fighterItem":
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveLocalFighterCommand(
|
||||
fitID=fitID, position=fit.fighters.index(selection[0])))
|
||||
elif srcContext == "implantItem":
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveImplantCommand(
|
||||
fitID=fitID, position=fit.implants.index(selection[0])))
|
||||
elif srcContext == "boosterItem":
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveBoosterCommand(
|
||||
fitID=fitID, position=fit.boosters.index(selection[0])))
|
||||
elif srcContext == "cargoItem":
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveCargoCommand(
|
||||
fitID=fitID, itemID=selection[0].itemID))
|
||||
elif srcContext == "projectedFit":
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedFitCommand(
|
||||
fitID=fitID, projectedFitID=selection[0].ID))
|
||||
elif srcContext == "projectedModule":
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedModuleCommand(
|
||||
fitID=fitID, position=fit.projectedModules.index(selection[0])))
|
||||
elif srcContext == "projectedDrone":
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedDroneCommand(
|
||||
fitID=fitID, itemID=selection[0].itemID, amount=math.inf))
|
||||
elif srcContext == "projectedFighter":
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedFighterCommand(
|
||||
fitID=fitID, position=fit.projectedFighters.index(selection[0])))
|
||||
elif srcContext == "commandFit":
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveCommandFitCommand(
|
||||
fitID=fitID, commandFitID=selection[0].ID))
|
||||
def __handleModule(self, mainItem, selection):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
if wx.GetMouseState().GetModifiers() == wx.MOD_ALT:
|
||||
positions = getSimilarModPositions(fit.modules, mainItem)
|
||||
else:
|
||||
positions = []
|
||||
for mod in selection:
|
||||
if mod in fit.modules:
|
||||
positions.append(fit.modules.index(mod))
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveLocalModuleCommand(
|
||||
fitID=fitID, positions=positions))
|
||||
|
||||
def __handleDrone(self, mainItem, selection):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
positions = []
|
||||
for drone in selection:
|
||||
if drone in fit.drones:
|
||||
positions.append(fit.drones.index(drone))
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveLocalDronesCommand(
|
||||
fitID=fitID, positions=positions, amount=math.inf))
|
||||
|
||||
def __handleFighter(self, mainItem, selection):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
if wx.GetMouseState().GetModifiers() == wx.MOD_ALT:
|
||||
fighters = getSimilarFighters(fit.fighters, mainItem)
|
||||
else:
|
||||
fighters = selection
|
||||
positions = []
|
||||
for fighter in fighters:
|
||||
if fighter in fit.fighters:
|
||||
positions.append(fit.fighters.index(fighter))
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveLocalFightersCommand(
|
||||
fitID=fitID, positions=positions))
|
||||
|
||||
def __handleImplant(self, mainItem, selection):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
positions = []
|
||||
for implant in selection:
|
||||
if implant in fit.implants:
|
||||
positions.append(fit.implants.index(implant))
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveImplantsCommand(
|
||||
fitID=fitID, positions=positions))
|
||||
|
||||
def __handleBooster(self, mainItem, selection):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
positions = []
|
||||
for booster in selection:
|
||||
if booster in fit.boosters:
|
||||
positions.append(fit.boosters.index(booster))
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveBoostersCommand(
|
||||
fitID=fitID, positions=positions))
|
||||
|
||||
def __handleCargo(self, mainItem, selection):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
itemIDs = [c.itemID for c in selection]
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveCargosCommand(
|
||||
fitID=fitID, itemIDs=itemIDs))
|
||||
|
||||
def __handleProjectedItem(self, mainItem, selection):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
if isinstance(mainItem, EosFit):
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedItemsCommand(
|
||||
fitID=fitID, items=selection, amount=math.inf))
|
||||
elif isinstance(mainItem, EosModule):
|
||||
if wx.GetMouseState().GetModifiers() == wx.MOD_ALT:
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
positions = getSimilarModPositions(fit.projectedModules, mainItem)
|
||||
items = [fit.projectedModules[p] for p in positions]
|
||||
else:
|
||||
items = selection
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedItemsCommand(
|
||||
fitID=fitID, items=items, amount=math.inf))
|
||||
elif isinstance(mainItem, EosDrone):
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedItemsCommand(
|
||||
fitID=fitID, items=selection, amount=math.inf))
|
||||
elif isinstance(mainItem, EosFighter):
|
||||
if wx.GetMouseState().GetModifiers() == wx.MOD_ALT:
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
items = getSimilarFighters(fit.projectedFighters, mainItem)
|
||||
else:
|
||||
items = selection
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedItemsCommand(
|
||||
fitID=fitID, items=items, amount=math.inf))
|
||||
else:
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveProjectedItemsCommand(
|
||||
fitID=fitID, items=selection, amount=math.inf))
|
||||
|
||||
def __handleCommandFit(self, mainItem, selection):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
commandFitIDs = [cf.ID for cf in selection]
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveCommandFitsCommand(
|
||||
fitID=fitID, commandFitIDs=commandFitIDs))
|
||||
|
||||
|
||||
RemoveItem.register()
|
||||
|
||||
@@ -2,42 +2,51 @@
|
||||
import wx
|
||||
|
||||
import gui.mainFrame
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuSingle
|
||||
from gui.itemStats import ItemStatsDialog
|
||||
from service.fit import Fit
|
||||
from eos.saveddata.mode import Mode
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class ItemStats(ContextMenu):
|
||||
class ItemStats(ContextMenuSingle):
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
return srcContext in ("marketItemGroup", "marketItemMisc",
|
||||
"fittingModule", "fittingCharge",
|
||||
"fittingShip", "baseShip",
|
||||
"cargoItem", "droneItem",
|
||||
"implantItem", "boosterItem",
|
||||
"skillItem", "projectedModule",
|
||||
"projectedDrone", "projectedCharge",
|
||||
"itemStats", "fighterItem",
|
||||
"implantItemChar", "projectedFighter",
|
||||
"fittingMode")
|
||||
def display(self, srcContext, mainItem):
|
||||
if srcContext not in (
|
||||
"marketItemGroup", "marketItemMisc",
|
||||
"fittingModule", "fittingCharge",
|
||||
"fittingShip", "baseShip",
|
||||
"cargoItem", "droneItem",
|
||||
"implantItem", "boosterItem",
|
||||
"skillItem", "projectedModule",
|
||||
"projectedDrone", "projectedCharge",
|
||||
"itemStats", "fighterItem",
|
||||
"implantItemChar", "projectedFighter",
|
||||
"fittingMode"
|
||||
):
|
||||
return False
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
return "{0} Stats".format(itmContext if itmContext is not None else "Item")
|
||||
if (mainItem is None or getattr(mainItem, "isEmpty", False)) and srcContext != "fittingShip":
|
||||
return False
|
||||
|
||||
def activate(self, fullContext, selection, i):
|
||||
return True
|
||||
|
||||
def getText(self, itmContext, mainItem):
|
||||
return "{} Stats".format(itmContext if itmContext is not None else "Item")
|
||||
|
||||
def activate(self, fullContext, mainItem, i):
|
||||
srcContext = fullContext[0]
|
||||
if srcContext == "fittingShip":
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
sFit = Fit.getInstance()
|
||||
stuff = sFit.getFit(fitID).ship
|
||||
elif srcContext == "fittingMode":
|
||||
stuff = selection[0].item
|
||||
stuff = mainItem.item
|
||||
else:
|
||||
stuff = selection[0]
|
||||
stuff = mainItem
|
||||
|
||||
if srcContext == "fittingModule" and stuff.isEmpty:
|
||||
return
|
||||
@@ -45,7 +54,7 @@ class ItemStats(ContextMenu):
|
||||
mstate = wx.GetMouseState()
|
||||
reuse = False
|
||||
|
||||
if mstate.cmdDown:
|
||||
if mstate.GetModifiers() == wx.MOD_SHIFT:
|
||||
reuse = True
|
||||
|
||||
if self.mainFrame.GetActiveStatsWindow() is None and reuse:
|
||||
|
||||
@@ -3,18 +3,20 @@ import wx
|
||||
|
||||
import gui.fitCommands as cmd
|
||||
import gui.mainFrame
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuCombined
|
||||
from gui.fitCommands.helpers import getSimilarModPositions, getSimilarFighters
|
||||
from service.fit import Fit
|
||||
from service.market import Market
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class ChangeItemToVariation(ContextMenu):
|
||||
class ChangeItemToVariation(ContextMenuCombined):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
def display(self, srcContext, mainItem, selection):
|
||||
if not self.settings.get('metaSwap'):
|
||||
return False
|
||||
|
||||
@@ -31,29 +33,22 @@ class ChangeItemToVariation(ContextMenu):
|
||||
):
|
||||
return False
|
||||
|
||||
# Check if list of variations is same for all of selection
|
||||
# If not - don't show the menu
|
||||
mkt = Market.getInstance()
|
||||
self.variations = None
|
||||
for i in selection:
|
||||
variations = mkt.getVariationsByItems([i.item])
|
||||
if self.variations is None:
|
||||
self.variations = variations
|
||||
else:
|
||||
if variations != self.variations:
|
||||
return False
|
||||
if mainItem is None or getattr(mainItem, 'isEmpty', False):
|
||||
return False
|
||||
|
||||
self.mainVariations = Market.getInstance().getVariationsByItems((mainItem.item,))
|
||||
# No variations from current module
|
||||
if len(self.mainVariations) < 2:
|
||||
return False
|
||||
|
||||
self.mainItem = mainItem
|
||||
self.selection = selection
|
||||
|
||||
if len(self.variations) == 1:
|
||||
return False # no variations from current module
|
||||
|
||||
return True
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
def getText(self, itmContext, mainItem, selection):
|
||||
return 'Variations'
|
||||
|
||||
def getSubMenu(self, context, selection, rootMenu, i, pitem):
|
||||
def getSubMenu(self, context, mainItem, selection, rootMenu, i, pitem):
|
||||
self.moduleLookup = {}
|
||||
sFit = Fit.getInstance()
|
||||
fit = sFit.getFit(self.mainFrame.getActiveFit())
|
||||
@@ -64,11 +59,13 @@ class ChangeItemToVariation(ContextMenu):
|
||||
return x.attributes['metaLevel'].value
|
||||
|
||||
def get_metagroup(x):
|
||||
return x.metaGroup.ID if x.metaGroup is not None else 0
|
||||
# We want deadspace before officer mods
|
||||
remap = {5: 6, 6: 5}
|
||||
return remap.get(x.metaGroup.ID, x.metaGroup.ID) if x.metaGroup is not None else 0
|
||||
|
||||
def get_boosterrank(x):
|
||||
# If we're returning a lot of items, sort my name
|
||||
if len(self.variations) > 7:
|
||||
if len(self.mainVariations) > 7:
|
||||
return x.name
|
||||
# Sort by booster chance to get some sort of pseudorank.
|
||||
elif 'boosterEffectChance1' in x.attributes:
|
||||
@@ -87,13 +84,14 @@ class ChangeItemToVariation(ContextMenu):
|
||||
bindmenu = m
|
||||
|
||||
# Sort items by metalevel, and group within that metalevel
|
||||
items = list(self.variations)
|
||||
|
||||
items = list(self.mainVariations)
|
||||
# Sort all items by name first
|
||||
items.sort(key=lambda x: x.name)
|
||||
# Do not do any extra sorting for implants
|
||||
if 'implantItem' in context:
|
||||
# sort implants based on name
|
||||
items.sort(key=lambda x: x.name)
|
||||
pass
|
||||
# Boosters don't have meta or anything concrete that we can rank by. Go by chance to inflict side effect
|
||||
elif 'boosterItem' in context:
|
||||
# boosters don't have meta or anything concrete that we can rank by. Go by chance to inflict side effect
|
||||
items.sort(key=get_boosterrank)
|
||||
else:
|
||||
# sort by group and meta level
|
||||
@@ -112,13 +110,13 @@ class ChangeItemToVariation(ContextMenu):
|
||||
|
||||
if thisgroup != group and context not in ('implantItem', 'boosterItem'):
|
||||
group = thisgroup
|
||||
id = ContextMenu.nextID()
|
||||
id = ContextMenuCombined.nextID()
|
||||
m.Append(id, '─ %s ─' % group)
|
||||
m.Enable(id, False)
|
||||
|
||||
id = ContextMenu.nextID()
|
||||
id = ContextMenuCombined.nextID()
|
||||
mitem = wx.MenuItem(rootMenu, id, item.name)
|
||||
bindmenu.Bind(wx.EVT_MENU, self.handleModule, mitem)
|
||||
bindmenu.Bind(wx.EVT_MENU, self.handleSwitch, mitem)
|
||||
|
||||
self.moduleLookup[id] = item, context
|
||||
m.Append(mitem)
|
||||
@@ -126,48 +124,175 @@ class ChangeItemToVariation(ContextMenu):
|
||||
|
||||
return m
|
||||
|
||||
def handleModule(self, event):
|
||||
def handleSwitch(self, event):
|
||||
item, context = self.moduleLookup.get(event.Id, None)
|
||||
if item is None:
|
||||
event.Skip()
|
||||
return
|
||||
handlerMap = {
|
||||
'fittingModule': self.__handleModule,
|
||||
'droneItem': self.__handleDrone,
|
||||
'fighterItem': self.__handleFighter,
|
||||
'cargoItem': self.__handleCargo,
|
||||
'implantItem': self.__handleImplant,
|
||||
'boosterItem': self.__handleBooster,
|
||||
'projectedModule': self.__handleProjectedModule,
|
||||
'projectedDrone': self.__handleProjectedDrone,
|
||||
'projectedFighter': self.__handleProjectedFighter}
|
||||
handler = handlerMap.get(context)
|
||||
if handler is None:
|
||||
return
|
||||
handler(item)
|
||||
|
||||
def __handleModule(self, varItem):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
if context == 'fittingModule':
|
||||
positions = [mod.modPosition for mod in self.selection]
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeLocalModuleMetasCommand(
|
||||
fitID=fitID, positions=positions, newItemID=item.ID))
|
||||
elif context == 'droneItem':
|
||||
position = fit.drones.index(self.selection[0])
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeLocalDroneMetaCommand(
|
||||
fitID=fitID, position=position, newItemID=item.ID))
|
||||
elif context == 'fighterItem':
|
||||
position = fit.fighters.index(self.selection[0])
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeLocalFighterMetaCommand(
|
||||
fitID=fitID, position=position, newItemID=item.ID))
|
||||
elif context == 'implantItem':
|
||||
position = fit.implants.index(self.selection[0])
|
||||
if wx.GetMouseState().GetModifiers() == wx.MOD_ALT:
|
||||
positions = getSimilarModPositions(fit.modules, self.mainItem)
|
||||
else:
|
||||
sMkt = Market.getInstance()
|
||||
positions = []
|
||||
for mod in self.selection:
|
||||
if mod.isEmpty:
|
||||
continue
|
||||
if mod is self.mainItem:
|
||||
positions.append(fit.modules.index(mod))
|
||||
continue
|
||||
if mod not in fit.modules:
|
||||
continue
|
||||
modVariations = sMkt.getVariationsByItems((mod.item,))
|
||||
if modVariations == self.mainVariations:
|
||||
positions.append(fit.modules.index(mod))
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeLocalModuleMetasCommand(
|
||||
fitID=fitID, positions=positions, newItemID=varItem.ID))
|
||||
|
||||
def __handleDrone(self, varItem):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
sMkt = Market.getInstance()
|
||||
positions = []
|
||||
for drone in self.selection:
|
||||
if drone not in fit.drones:
|
||||
continue
|
||||
if drone is self.mainItem:
|
||||
positions.append(fit.drones.index(drone))
|
||||
continue
|
||||
droneVariations = sMkt.getVariationsByItems((drone.item,))
|
||||
if droneVariations == self.mainVariations:
|
||||
positions.append(fit.drones.index(drone))
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeLocalDroneMetasCommand(
|
||||
fitID=fitID, positions=positions, newItemID=varItem.ID))
|
||||
|
||||
def __handleFighter(self, varItem):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
if wx.GetMouseState().GetModifiers() == wx.MOD_ALT:
|
||||
fighters = getSimilarFighters(fit.fighters, self.mainItem)
|
||||
else:
|
||||
fighters = self.selection
|
||||
sMkt = Market.getInstance()
|
||||
positions = []
|
||||
for fighter in fighters:
|
||||
if fighter not in fit.fighters:
|
||||
continue
|
||||
if fighter is self.mainItem:
|
||||
positions.append(fit.fighters.index(fighter))
|
||||
continue
|
||||
fighterVariations = sMkt.getVariationsByItems((fighter.item,))
|
||||
if fighterVariations == self.mainVariations:
|
||||
positions.append(fit.fighters.index(fighter))
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeLocalFighterMetasCommand(
|
||||
fitID=fitID, positions=positions, newItemID=varItem.ID))
|
||||
|
||||
def __handleCargo(self, varItem):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
sMkt = Market.getInstance()
|
||||
itemIDs = []
|
||||
for cargo in self.selection:
|
||||
if cargo is self.mainItem:
|
||||
itemIDs.append(cargo.itemID)
|
||||
continue
|
||||
cargoVariations = sMkt.getVariationsByItems((cargo.item,))
|
||||
if cargoVariations == self.mainVariations:
|
||||
itemIDs.append(cargo.itemID)
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeCargoMetasCommand(
|
||||
fitID=fitID, itemIDs=itemIDs, newItemID=varItem.ID))
|
||||
|
||||
def __handleImplant(self, varItem):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
implant = self.mainItem
|
||||
if implant in fit.implants:
|
||||
position = fit.implants.index(implant)
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeImplantMetaCommand(
|
||||
fitID=fitID, position=position, newItemID=item.ID))
|
||||
elif context == 'boosterItem':
|
||||
position = fit.boosters.index(self.selection[0])
|
||||
fitID=fitID, position=position, newItemID=varItem.ID))
|
||||
|
||||
def __handleBooster(self, varItem):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
booster = self.mainItem
|
||||
if booster in fit.boosters:
|
||||
position = fit.boosters.index(booster)
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeBoosterMetaCommand(
|
||||
fitID=fitID, position=position, newItemID=item.ID))
|
||||
elif context == 'cargoItem':
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeCargoMetaCommand(
|
||||
fitID=fitID, itemID=self.selection[0].itemID, newItemID=item.ID))
|
||||
elif context == 'projectedModule':
|
||||
position = fit.projectedModules.index(self.selection[0])
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeProjectedModuleMetaCommand(
|
||||
fitID=fitID, position=position, newItemID=item.ID))
|
||||
elif context == 'projectedDrone':
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeProjectedDroneMetaCommand(
|
||||
fitID=fitID, itemID=self.selection[0].itemID, newItemID=item.ID))
|
||||
elif context == 'projectedFighter':
|
||||
position = fit.projectedFighters.index(self.selection[0])
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeProjectedFighterMetaCommand(
|
||||
fitID=fitID, position=position, newItemID=item.ID))
|
||||
fitID=fitID, position=position, newItemID=varItem.ID))
|
||||
|
||||
def __handleProjectedModule(self, varItem):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
if wx.GetMouseState().GetModifiers() == wx.MOD_ALT:
|
||||
positions = getSimilarModPositions(fit.projectedModules, self.mainItem)
|
||||
else:
|
||||
sMkt = Market.getInstance()
|
||||
positions = []
|
||||
for mod in self.selection:
|
||||
if mod is self.mainItem:
|
||||
positions.append(fit.projectedModules.index(mod))
|
||||
continue
|
||||
if mod not in fit.projectedModules:
|
||||
continue
|
||||
modVariations = sMkt.getVariationsByItems((mod.item,))
|
||||
if modVariations == self.mainVariations:
|
||||
positions.append(fit.projectedModules.index(mod))
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeProjectedModuleMetasCommand(
|
||||
fitID=fitID, positions=positions, newItemID=varItem.ID))
|
||||
|
||||
def __handleProjectedDrone(self, varItem):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
sMkt = Market.getInstance()
|
||||
itemIDs = []
|
||||
for drone in self.selection:
|
||||
if drone not in fit.projectedDrones:
|
||||
continue
|
||||
if drone is self.mainItem:
|
||||
itemIDs.append(drone.itemID)
|
||||
continue
|
||||
droneVariations = sMkt.getVariationsByItems((drone.item,))
|
||||
if droneVariations == self.mainVariations:
|
||||
itemIDs.append(drone.itemID)
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeProjectedDroneMetasCommand(
|
||||
fitID=fitID, itemIDs=itemIDs, newItemID=varItem.ID))
|
||||
|
||||
def __handleProjectedFighter(self, varItem):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
if wx.GetMouseState().GetModifiers() == wx.MOD_ALT:
|
||||
fighters = getSimilarFighters(fit.projectedFighters, self.mainItem)
|
||||
else:
|
||||
fighters = self.selection
|
||||
sMkt = Market.getInstance()
|
||||
positions = []
|
||||
for fighter in fighters:
|
||||
if fighter not in fit.projectedFighters:
|
||||
continue
|
||||
if fighter is self.mainItem:
|
||||
positions.append(fit.projectedFighters.index(fighter))
|
||||
continue
|
||||
fighterVariations = sMkt.getVariationsByItems((fighter.item,))
|
||||
if fighterVariations == self.mainVariations:
|
||||
positions.append(fit.projectedFighters.index(fighter))
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeProjectedFighterMetasCommand(
|
||||
fitID=fitID, positions=positions, newItemID=varItem.ID))
|
||||
|
||||
|
||||
ChangeItemToVariation.register()
|
||||
|
||||
@@ -4,54 +4,60 @@ import wx
|
||||
import gui.fitCommands as cmd
|
||||
import gui.mainFrame
|
||||
from eos.const import FittingHardpoint
|
||||
from eos.saveddata.module import Module
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuCombined
|
||||
from gui.fitCommands.helpers import getSimilarModPositions
|
||||
from service.fit import Fit
|
||||
from service.market import Market
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class ChangeModuleAmmo(ContextMenu):
|
||||
class ChangeModuleAmmo(ContextMenuCombined):
|
||||
|
||||
DAMAGE_TYPES = ("em", "explosive", "kinetic", "thermal")
|
||||
MISSILE_ORDER = ("em", "thermal", "kinetic", "explosive", "mixed")
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
# Format: {type ID: set(loadable, charges)}
|
||||
self.loadableCharges = {}
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
if self.mainFrame.getActiveFit() is None or srcContext not in ("fittingModule", "projectedModule"):
|
||||
def display(self, srcContext, mainItem, selection):
|
||||
if srcContext not in ("fittingModule", "projectedModule"):
|
||||
return False
|
||||
|
||||
modules = selection if srcContext == "fittingModule" else (selection[0],)
|
||||
|
||||
validCharges = None
|
||||
checkedTypes = set()
|
||||
|
||||
for mod in modules:
|
||||
# loop through modules and gather list of valid charges
|
||||
if mod.item.ID in checkedTypes:
|
||||
continue
|
||||
checkedTypes.add(mod.item.ID)
|
||||
currCharges = mod.getValidCharges()
|
||||
if len(currCharges) > 0:
|
||||
if validCharges is not None and validCharges != currCharges:
|
||||
return False
|
||||
|
||||
validCharges = currCharges
|
||||
self.module = mod
|
||||
|
||||
if validCharges is None:
|
||||
if self.mainFrame.getActiveFit() is None:
|
||||
return False
|
||||
|
||||
self.modules = modules
|
||||
self.charges = list([charge for charge in validCharges if Market.getInstance().getPublicityByItem(charge)])
|
||||
self.context = srcContext
|
||||
return len(self.charges) > 0
|
||||
self.mainCharges = self.getChargesForMod(mainItem)
|
||||
if not self.mainCharges:
|
||||
return False
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
self.module = mainItem
|
||||
self.selection = selection
|
||||
self.srcContext = srcContext
|
||||
return True
|
||||
|
||||
def getText(self, itmContext, mainItem, selection):
|
||||
return "Charge"
|
||||
|
||||
def getChargesForMod(self, mod):
|
||||
sMkt = Market.getInstance()
|
||||
if mod is None or mod.isEmpty:
|
||||
return set()
|
||||
typeID = mod.item.ID
|
||||
if typeID in self.loadableCharges:
|
||||
return self.loadableCharges[typeID]
|
||||
chargeSet = self.loadableCharges.setdefault(typeID, set())
|
||||
# Do not try to grab it for modes which can also be passed as part of selection
|
||||
if isinstance(mod, Module):
|
||||
for charge in mod.getValidCharges():
|
||||
if sMkt.getPublicityByItem(charge):
|
||||
chargeSet.add(charge)
|
||||
return chargeSet
|
||||
|
||||
def turretSorter(self, charge):
|
||||
damage = 0
|
||||
range_ = (self.module.item.getAttribute("maxRange")) * \
|
||||
@@ -107,7 +113,7 @@ class ChangeModuleAmmo(ContextMenu):
|
||||
return list(map(self.numericConverter, parts))
|
||||
|
||||
def addCharge(self, menu, charge):
|
||||
id_ = ContextMenu.nextID()
|
||||
id_ = ContextMenuCombined.nextID()
|
||||
name = charge.name if charge is not None else "Empty"
|
||||
self.chargeIds[id_] = charge
|
||||
item = wx.MenuItem(menu, id_, name)
|
||||
@@ -122,11 +128,11 @@ class ChangeModuleAmmo(ContextMenu):
|
||||
|
||||
@staticmethod
|
||||
def addSeperator(m, text):
|
||||
id_ = ContextMenu.nextID()
|
||||
id_ = ContextMenuCombined.nextID()
|
||||
m.Append(id_, '─ %s ─' % text)
|
||||
m.Enable(id_, False)
|
||||
|
||||
def getSubMenu(self, context, selection, rootMenu, i, pitem):
|
||||
def getSubMenu(self, context, mainItem, selection, rootMenu, i, pitem):
|
||||
msw = True if "wxMSW" in wx.PlatformInfo else False
|
||||
m = wx.Menu()
|
||||
self.chargeIds = {}
|
||||
@@ -139,8 +145,8 @@ class ChangeModuleAmmo(ContextMenu):
|
||||
range_ = None
|
||||
nameBase = None
|
||||
sub = None
|
||||
self.charges.sort(key=self.turretSorter)
|
||||
for charge in self.charges:
|
||||
chargesSorted = sorted(self.mainCharges, key=self.turretSorter)
|
||||
for charge in chargesSorted:
|
||||
if "civilian" in charge.name.lower():
|
||||
continue
|
||||
currBase = charge.name.rsplit()[-2:]
|
||||
@@ -173,11 +179,11 @@ class ChangeModuleAmmo(ContextMenu):
|
||||
|
||||
self.addSeperator(m, "Short Range")
|
||||
elif hardpoint == FittingHardpoint.MISSILE and moduleName != 'Festival Launcher':
|
||||
self.charges.sort(key=self.missileSorter)
|
||||
type_ = None
|
||||
sub = None
|
||||
defender = None
|
||||
for charge in self.charges:
|
||||
chargesSorted = sorted(self.mainCharges, key=self.missileSorter)
|
||||
for charge in chargesSorted:
|
||||
currType = self.damageInfo(charge)[0]
|
||||
|
||||
if currType != type_ or type_ is None:
|
||||
@@ -206,8 +212,8 @@ class ChangeModuleAmmo(ContextMenu):
|
||||
if sub is not None:
|
||||
self.addSeperator(sub, "More Damage")
|
||||
else:
|
||||
self.charges.sort(key=self.nameSorter)
|
||||
for charge in self.charges:
|
||||
chargesSorted = sorted(self.mainCharges, key=self.nameSorter)
|
||||
for charge in chargesSorted:
|
||||
m.Append(self.addCharge(rootMenu if msw else m, charge))
|
||||
|
||||
m.Append(self.addCharge(rootMenu if msw else m, None))
|
||||
@@ -221,33 +227,43 @@ class ChangeModuleAmmo(ContextMenu):
|
||||
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
sFit = Fit.getInstance()
|
||||
switchAll = sFit.serviceFittingOptions['ammoChangeAll'] is not wx.GetMouseState().CmdDown()
|
||||
# Switch in selection or all modules, depending on ctrl key state and settings
|
||||
fit = sFit.getFit(fitID)
|
||||
mstate = wx.GetMouseState()
|
||||
# Switch in selection or all modules, depending on modifier key state and settings
|
||||
switchAll = sFit.serviceFittingOptions['ammoChangeAll'] is not mstate.GetModifiers() in (wx.MOD_ALT, wx.MOD_CONTROL)
|
||||
if switchAll:
|
||||
fit = sFit.getFit(fitID)
|
||||
selectedModule = self.modules[0]
|
||||
if self.context == 'fittingModule':
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeLocalModuleChargesCommand(
|
||||
fitID=fitID,
|
||||
modules=[m for m in fit.modules if m.itemID is not None and m.itemID == selectedModule.itemID],
|
||||
chargeItemID=charge.ID if charge is not None else None))
|
||||
elif self.context == 'projectedModule':
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeProjectedModuleChargesCommand(
|
||||
fitID=fitID,
|
||||
modules=[m for m in fit.projectedModules if
|
||||
m.itemID is not None and m.itemID == selectedModule.itemID],
|
||||
chargeItemID=charge.ID if charge is not None else None))
|
||||
if self.srcContext == 'fittingModule':
|
||||
command = cmd.GuiChangeLocalModuleChargesCommand
|
||||
modContainer = fit.modules
|
||||
elif self.srcContext == 'projectedModule':
|
||||
command = cmd.GuiChangeProjectedModuleChargesCommand
|
||||
modContainer = fit.projectedModules
|
||||
else:
|
||||
return
|
||||
positions = getSimilarModPositions(modContainer, self.module)
|
||||
self.mainFrame.command.Submit(command(
|
||||
fitID=fitID,
|
||||
positions=positions,
|
||||
chargeItemID=charge.ID if charge is not None else None))
|
||||
else:
|
||||
if self.context == 'fittingModule':
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeLocalModuleChargesCommand(
|
||||
fitID=fitID,
|
||||
modules=self.modules,
|
||||
chargeItemID=charge.ID if charge is not None else None))
|
||||
elif self.context == 'projectedModule':
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeProjectedModuleChargesCommand(
|
||||
fitID=fitID,
|
||||
modules=self.modules,
|
||||
chargeItemID=charge.ID if charge is not None else None))
|
||||
if self.srcContext == 'fittingModule':
|
||||
command = cmd.GuiChangeLocalModuleChargesCommand
|
||||
modContainer = fit.modules
|
||||
elif self.srcContext == 'projectedModule':
|
||||
command = cmd.GuiChangeProjectedModuleChargesCommand
|
||||
modContainer = fit.projectedModules
|
||||
else:
|
||||
return
|
||||
positions = []
|
||||
for position, mod in enumerate(modContainer):
|
||||
if mod in self.selection:
|
||||
modCharges = self.getChargesForMod(mod)
|
||||
if modCharges.issubset(self.mainCharges):
|
||||
positions.append(position)
|
||||
self.mainFrame.command.Submit(command(
|
||||
fitID=fitID,
|
||||
positions=positions,
|
||||
chargeItemID=charge.ID if charge is not None else None))
|
||||
|
||||
|
||||
ChangeModuleAmmo.register()
|
||||
|
||||
@@ -1,35 +1,40 @@
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
|
||||
import gui.fitCommands as cmd
|
||||
import gui.globalEvents as GE
|
||||
import gui.mainFrame
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuSingle
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class FillWithModule(ContextMenu):
|
||||
class FillWithModule(ContextMenuSingle):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
def display(self, srcContext, mainItem):
|
||||
|
||||
if not self.settings.get('moduleFill'):
|
||||
return False
|
||||
|
||||
if mainItem is None or getattr(mainItem, 'isEmpty', False):
|
||||
return False
|
||||
|
||||
return srcContext == "fittingModule"
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
return u"Fill With {0}".format(itmContext if itmContext is not None else "Module")
|
||||
def getText(self, itmContext, mainItem):
|
||||
return "Fill With {0}".format(itmContext if itmContext is not None else "Module")
|
||||
|
||||
def activate(self, fullContext, selection, i):
|
||||
def activate(self, fullContext, mainItem, i):
|
||||
|
||||
srcContext = fullContext[0]
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
|
||||
if srcContext == "fittingModule":
|
||||
self.mainFrame.command.Submit(cmd.GuiFillWithLocalModulesCommand(fitID, selection[0].itemID))
|
||||
return # the command takes care of the PostEvent
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
if mainItem in fit.modules:
|
||||
position = fit.modules.index(mainItem)
|
||||
self.mainFrame.command.Submit(cmd.GuiFillWithClonedLocalModulesCommand(
|
||||
fitID=fitID, position=position))
|
||||
|
||||
|
||||
FillWithModule.register()
|
||||
|
||||
@@ -2,51 +2,49 @@
|
||||
import wx
|
||||
|
||||
import gui.mainFrame
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuSingle
|
||||
from gui.fitCommands import GuiConvertMutatedLocalModuleCommand, GuiRevertMutatedLocalModuleCommand
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class ChangeModuleMutation(ContextMenu):
|
||||
class ChangeModuleMutation(ContextMenuSingle):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
self.eventIDs = {}
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
|
||||
# if not self.settings.get('ammoPattern'):
|
||||
# return False
|
||||
def display(self, srcContext, mainItem):
|
||||
|
||||
if srcContext != "fittingModule" or self.mainFrame.getActiveFit() is None:
|
||||
return False
|
||||
|
||||
mod = selection[0]
|
||||
if len(mod.item.mutaplasmids) == 0 and not mod.isMutated:
|
||||
if mainItem is None or mainItem.isEmpty:
|
||||
return False
|
||||
|
||||
if len(mainItem.item.mutaplasmids) == 0 and not mainItem.isMutated:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
mod = selection[0]
|
||||
return "Apply Mutaplasmid" if not mod.isMutated else "Revert to {}".format(mod.baseItem.name)
|
||||
def getText(self, itmContext, mainItem):
|
||||
return "Apply Mutaplasmid" if not mainItem.isMutated else "Revert to {}".format(mainItem.baseItem.name)
|
||||
|
||||
def getSubMenu(self, context, selection, rootMenu, i, pitem):
|
||||
if selection[0].isMutated:
|
||||
def getSubMenu(self, context, mainItem, rootMenu, i, pitem):
|
||||
if mainItem.isMutated:
|
||||
return None
|
||||
|
||||
msw = True if "wxMSW" in wx.PlatformInfo else False
|
||||
self.skillIds = {}
|
||||
sub = wx.Menu()
|
||||
|
||||
mod = selection[0]
|
||||
|
||||
menu = rootMenu if msw else sub
|
||||
|
||||
for item in mod.item.mutaplasmids:
|
||||
for item in mainItem.item.mutaplasmids:
|
||||
label = item.item.name
|
||||
id = ContextMenu.nextID()
|
||||
self.eventIDs[id] = (item, mod)
|
||||
id = ContextMenuSingle.nextID()
|
||||
self.eventIDs[id] = (item, mainItem)
|
||||
skillItem = wx.MenuItem(menu, id, label)
|
||||
menu.Bind(wx.EVT_MENU, self.handleMenu, skillItem)
|
||||
sub.Append(skillItem)
|
||||
@@ -55,19 +53,22 @@ class ChangeModuleMutation(ContextMenu):
|
||||
|
||||
def handleMenu(self, event):
|
||||
mutaplasmid, mod = self.eventIDs[event.Id]
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
if mod in fit.modules:
|
||||
position = fit.modules.index(mod)
|
||||
self.mainFrame.command.Submit(GuiConvertMutatedLocalModuleCommand(
|
||||
fitID=fitID, position=position, mutaplasmid=mutaplasmid))
|
||||
|
||||
self.mainFrame.command.Submit(GuiConvertMutatedLocalModuleCommand(
|
||||
fitID=self.mainFrame.getActiveFit(),
|
||||
position=mod.modPosition,
|
||||
mutaplasmid=mutaplasmid))
|
||||
def activate(self, fullContext, mainItem, i):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
if mainItem in fit.modules:
|
||||
position = fit.modules.index(mainItem)
|
||||
self.mainFrame.command.Submit(GuiRevertMutatedLocalModuleCommand(
|
||||
fitID=fitID, position=position))
|
||||
|
||||
def activate(self, fullContext, selection, i):
|
||||
mod = selection[0]
|
||||
self.mainFrame.command.Submit(GuiRevertMutatedLocalModuleCommand(
|
||||
fitID=self.mainFrame.getActiveFit(),
|
||||
position=mod.modPosition))
|
||||
|
||||
def getBitmap(self, context, selection):
|
||||
def getBitmap(self, context, mainItem):
|
||||
return None
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import math
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
|
||||
@@ -5,33 +7,38 @@ import eos.config
|
||||
import gui.fitCommands as cmd
|
||||
import gui.mainFrame
|
||||
from eos.utils.spoolSupport import SpoolType, SpoolOptions
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuSingle
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class ChangeModuleSpool(ContextMenu):
|
||||
class ChangeModuleSpool(ContextMenuSingle):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
self.cycleMap = {}
|
||||
self.resetId = None
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
def display(self, srcContext, mainItem):
|
||||
if not self.settings.get('spoolup'):
|
||||
return False
|
||||
|
||||
if srcContext not in ('fittingModule', 'projectedModule') or self.mainFrame.getActiveFit() is None:
|
||||
return False
|
||||
|
||||
self.mod = selection[0]
|
||||
if mainItem is None or mainItem.isEmpty:
|
||||
return False
|
||||
|
||||
self.mod = mainItem
|
||||
self.context = srcContext
|
||||
|
||||
return self.mod.item.group.name in ("Precursor Weapon", "Mutadaptive Remote Armor Repairer")
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
def getText(self, itmContext, mainItem):
|
||||
return "Spoolup Cycles"
|
||||
|
||||
def getSubMenu(self, context, selection, rootMenu, i, pitem):
|
||||
def getSubMenu(self, context, mainItem, rootMenu, i, pitem):
|
||||
m = wx.Menu()
|
||||
if "wxMSW" in wx.PlatformInfo:
|
||||
bindmenu = rootMenu
|
||||
@@ -43,15 +50,44 @@ class ChangeModuleSpool(ContextMenu):
|
||||
cycleCurrent = self.mod.getSpoolData(spoolOptions=SpoolOptions(SpoolType.SCALE, eos.config.settings['globalDefaultSpoolupPercentage'], False))[0]
|
||||
cycleMin = self.mod.getSpoolData(spoolOptions=SpoolOptions(SpoolType.SCALE, 0, True))[0]
|
||||
cycleMax = self.mod.getSpoolData(spoolOptions=SpoolOptions(SpoolType.SCALE, 1, True))[0]
|
||||
cycleTotalMin = min(cycleDefault, cycleCurrent, cycleMin)
|
||||
cycleTotalMax = max(cycleDefault, cycleCurrent, cycleMax)
|
||||
|
||||
for cycle in range(cycleMin, cycleMax + 1):
|
||||
menuId = ContextMenu.nextID()
|
||||
def findCycles(val1, val2):
|
||||
# Try to compose list of 21 steps max (0-20)
|
||||
maxSteps = 20
|
||||
valDiff = val2 - val1
|
||||
valScale = valDiff / maxSteps
|
||||
minStep = math.ceil(round(valScale, 9))
|
||||
maxStep = math.floor(round(valDiff / 4, 9))
|
||||
# Check steps from smallest to highest and see if we can go from min value
|
||||
# to max value using those
|
||||
for currentStep in range(minStep, maxStep + 1):
|
||||
if valDiff % currentStep == 0:
|
||||
return set(range(val1, val2 + currentStep, currentStep))
|
||||
# Otherwise just split range in halves and go both ends using min values
|
||||
else:
|
||||
cycles = set()
|
||||
while val2 >= val1:
|
||||
cycles.add(val1)
|
||||
cycles.add(val2)
|
||||
val1 += minStep
|
||||
val2 -= minStep
|
||||
return cycles
|
||||
|
||||
cyclesToShow = findCycles(cycleMin, cycleMax)
|
||||
for cycle in range(cycleTotalMin, cycleTotalMax + 1):
|
||||
menuId = ContextMenuSingle.nextID()
|
||||
|
||||
# Show default only for current value and when not overriden
|
||||
if not isNotDefault and cycle == cycleDefault:
|
||||
text = "{} (default)".format(cycle)
|
||||
else:
|
||||
# Always show current selection and stuff which we decided to show via the cycles function
|
||||
elif cycle == cycleCurrent or cycle in cyclesToShow:
|
||||
text = "{}".format(cycle)
|
||||
# Ignore the rest to not have very long menu
|
||||
else:
|
||||
continue
|
||||
|
||||
item = wx.MenuItem(m, menuId, text, kind=wx.ITEM_CHECK)
|
||||
bindmenu.Bind(wx.EVT_MENU, self.handleSpoolChange, item)
|
||||
@@ -59,7 +95,7 @@ class ChangeModuleSpool(ContextMenu):
|
||||
item.Check(isNotDefault and cycle == cycleCurrent)
|
||||
self.cycleMap[menuId] = cycle
|
||||
|
||||
self.resetId = ContextMenu.nextID()
|
||||
self.resetId = ContextMenuSingle.nextID()
|
||||
item = wx.MenuItem(m, self.resetId, "Reset")
|
||||
bindmenu.Bind(wx.EVT_MENU, self.handleSpoolChange, item)
|
||||
m.Append(item)
|
||||
@@ -75,18 +111,18 @@ class ChangeModuleSpool(ContextMenu):
|
||||
spoolAmount = self.cycleMap[event.Id]
|
||||
else:
|
||||
return
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
if self.context == 'fittingModule':
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeLocalModuleSpoolCommand(
|
||||
fitID=self.mainFrame.getActiveFit(),
|
||||
position=self.mod.modPosition,
|
||||
spoolType=spoolType,
|
||||
spoolAmount=spoolAmount))
|
||||
if self.mod in fit.modules:
|
||||
position = fit.modules.index(self.mod)
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeLocalModuleSpoolCommand(
|
||||
fitID=fitID, position=position, spoolType=spoolType, spoolAmount=spoolAmount))
|
||||
elif self.context == 'projectedModule':
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeProjectedModuleSpoolCommand(
|
||||
fitID=self.mainFrame.getActiveFit(),
|
||||
position=self.mod.modPosition,
|
||||
spoolType=spoolType,
|
||||
spoolAmount=spoolAmount))
|
||||
if self.mod in fit.projectedModules:
|
||||
position = fit.projectedModules.index(self.mod)
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeProjectedModuleSpoolCommand(
|
||||
fitID=fitID, position=position, spoolType=spoolType, spoolAmount=spoolAmount))
|
||||
|
||||
|
||||
ChangeModuleSpool.register()
|
||||
|
||||
@@ -4,11 +4,11 @@ import wx
|
||||
|
||||
import gui.globalEvents as GE
|
||||
import gui.mainFrame
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuUnconditional
|
||||
from service.settings import MarketPriceSettings
|
||||
|
||||
|
||||
class ItemGroupPrice(ContextMenu, metaclass=ABCMeta):
|
||||
class ItemGroupPrice(ContextMenuUnconditional, metaclass=ABCMeta):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
@@ -24,13 +24,13 @@ class ItemGroupPrice(ContextMenu, metaclass=ABCMeta):
|
||||
def optionName(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
def display(self, srcContext):
|
||||
return srcContext in ("priceViewFull", "priceViewMinimal")
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
def getText(self, itmContext):
|
||||
return self.label
|
||||
|
||||
def activate(self, fullContext, selection, i):
|
||||
def activate(self, fullContext, i):
|
||||
self.settings.set(self.optionName, not self.settings.get(self.optionName))
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=self.mainFrame.getActiveFit()))
|
||||
|
||||
|
||||
@@ -3,30 +3,41 @@ import wx
|
||||
|
||||
import gui.mainFrame
|
||||
from gui.builtinShipBrowser.events import Stage3Selected
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuUnconditional
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class JumpToShip(ContextMenu):
|
||||
class JumpToShip(ContextMenuUnconditional):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
return srcContext == "fittingShip"
|
||||
def display(self, srcContext):
|
||||
if srcContext != "fittingShip":
|
||||
return False
|
||||
fitTabSelected = self.mainFrame.notebookBrowsers.GetSelection() == 1
|
||||
if not fitTabSelected:
|
||||
return True
|
||||
browsingStage = self.mainFrame.shipBrowser.GetActiveStage()
|
||||
if browsingStage != 3:
|
||||
return True
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
ship = Fit.getInstance().getFit(fitID).ship
|
||||
browsingShipID = self.mainFrame.shipBrowser.GetStageData(browsingStage)
|
||||
if browsingShipID != ship.item.ID:
|
||||
return True
|
||||
return False
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
def getText(self, itmContext):
|
||||
return "Open in Fitting Browser"
|
||||
|
||||
def activate(self, fullContext, selection, i):
|
||||
def activate(self, fullContext, i):
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
sFit = Fit.getInstance()
|
||||
stuff = sFit.getFit(fitID).ship
|
||||
groupID = stuff.item.group.ID
|
||||
|
||||
ship = Fit.getInstance().getFit(fitID).ship
|
||||
self.mainFrame.notebookBrowsers.SetSelection(1)
|
||||
wx.PostEvent(self.mainFrame.shipBrowser, Stage3Selected(shipID=stuff.item.ID, back=groupID))
|
||||
wx.PostEvent(self.mainFrame.shipBrowser, Stage3Selected(shipID=ship.item.ID, back=True))
|
||||
|
||||
|
||||
JumpToShip.register()
|
||||
|
||||
@@ -3,17 +3,18 @@ import wx
|
||||
|
||||
import gui.fitCommands as cmd
|
||||
import gui.mainFrame
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuUnconditional
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class ChangeShipTacticalMode(ContextMenu):
|
||||
class ChangeShipTacticalMode(ContextMenuUnconditional):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
def display(self, srcContext):
|
||||
if self.mainFrame.getActiveFit() is None or srcContext != "fittingShip":
|
||||
return False
|
||||
|
||||
@@ -26,18 +27,18 @@ class ChangeShipTacticalMode(ContextMenu):
|
||||
|
||||
return srcContext == "fittingShip" and self.modes is not None
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
def getText(self, itmContext):
|
||||
return "Tactical Mode"
|
||||
|
||||
def addMode(self, menu, mode):
|
||||
label = mode.item.name.rsplit()[-2]
|
||||
id = ContextMenu.nextID()
|
||||
id = ContextMenuUnconditional.nextID()
|
||||
self.modeIds[id] = mode
|
||||
menuItem = wx.MenuItem(menu, id, label, kind=wx.ITEM_RADIO)
|
||||
menu.Bind(wx.EVT_MENU, self.handleMode, menuItem)
|
||||
return menuItem
|
||||
|
||||
def getSubMenu(self, context, selection, rootMenu, i, pitem):
|
||||
def getSubMenu(self, context, rootMenu, i, pitem):
|
||||
msw = True if "wxMSW" in wx.PlatformInfo else False
|
||||
self.context = context
|
||||
self.modeIds = {}
|
||||
|
||||
@@ -5,28 +5,39 @@ import gui.globalEvents as GE
|
||||
import gui.mainFrame
|
||||
from eos.saveddata.character import Skill
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuSingle
|
||||
from service.character import Character
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
|
||||
|
||||
class ChangeAffectingSkills(ContextMenu):
|
||||
class ChangeAffectingSkills(ContextMenuSingle):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
def display(self, srcContext, mainItem):
|
||||
if not self.settings.get('changeAffectingSkills'):
|
||||
return False
|
||||
|
||||
if self.mainFrame.getActiveFit() is None or srcContext not in (
|
||||
"fittingModule", "fittingCharge", "fittingShip", "droneItem", "fighterItem"):
|
||||
if srcContext not in (
|
||||
"fittingModule", "fittingCharge",
|
||||
"fittingShip", "droneItem",
|
||||
"fighterItem"
|
||||
):
|
||||
return False
|
||||
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
if fitID is None:
|
||||
return False
|
||||
|
||||
if (mainItem is None or getattr(mainItem, "isEmpty", False)) and srcContext != "fittingShip":
|
||||
return False
|
||||
|
||||
self.sChar = Character.getInstance()
|
||||
self.sFit = Fit.getInstance()
|
||||
fit = self.sFit.getFit(self.mainFrame.getActiveFit())
|
||||
fit = self.sFit.getFit(fitID)
|
||||
|
||||
self.charID = fit.character.ID
|
||||
|
||||
@@ -34,14 +45,13 @@ class ChangeAffectingSkills(ContextMenu):
|
||||
# return False
|
||||
|
||||
if srcContext == "fittingShip":
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
sFit = Fit.getInstance()
|
||||
self.stuff = sFit.getFit(fitID).ship
|
||||
cont = sFit.getFit(fitID).ship.itemModifiedAttributes
|
||||
elif srcContext == "fittingCharge":
|
||||
cont = selection[0].chargeModifiedAttributes
|
||||
cont = mainItem.chargeModifiedAttributes
|
||||
else:
|
||||
cont = selection[0].itemModifiedAttributes
|
||||
cont = mainItem.itemModifiedAttributes
|
||||
|
||||
skills = set()
|
||||
|
||||
@@ -60,7 +70,7 @@ class ChangeAffectingSkills(ContextMenu):
|
||||
self.skills = sorted(skills, key=lambda x: x.item.name)
|
||||
return len(self.skills) > 0
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
def getText(self, itmContext, mainItem):
|
||||
return "Change %s Skills" % itmContext
|
||||
|
||||
def addSkill(self, rootMenu, skill, i):
|
||||
@@ -69,19 +79,19 @@ class ChangeAffectingSkills(ContextMenu):
|
||||
else:
|
||||
label = "Level %s" % i
|
||||
|
||||
id = ContextMenu.nextID()
|
||||
id = ContextMenuSingle.nextID()
|
||||
self.skillIds[id] = (skill, i)
|
||||
menuItem = wx.MenuItem(rootMenu, id, label, kind=wx.ITEM_RADIO)
|
||||
rootMenu.Bind(wx.EVT_MENU, self.handleSkillChange, menuItem)
|
||||
return menuItem
|
||||
|
||||
def getSubMenu(self, context, selection, rootMenu, i, pitem):
|
||||
def getSubMenu(self, context, mainItem, rootMenu, i, pitem):
|
||||
msw = True if "wxMSW" in wx.PlatformInfo else False
|
||||
self.skillIds = {}
|
||||
sub = wx.Menu()
|
||||
|
||||
for skill in self.skills:
|
||||
skillItem = wx.MenuItem(sub, ContextMenu.nextID(), skill.item.name)
|
||||
skillItem = wx.MenuItem(sub, ContextMenuSingle.nextID(), skill.item.name)
|
||||
grandSub = wx.Menu()
|
||||
skillItem.SetSubMenu(grandSub)
|
||||
if skill.learned:
|
||||
|
||||
@@ -6,18 +6,19 @@ import wx
|
||||
import gui.globalEvents as GE
|
||||
import gui.mainFrame
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from gui.contextMenu import ContextMenu
|
||||
from gui.contextMenu import ContextMenuUnconditional
|
||||
from service.fit import Fit
|
||||
from service.settings import ContextMenuSettings
|
||||
from service.targetResists import TargetResists as svc_TargetResists
|
||||
|
||||
|
||||
class TargetResists(ContextMenu):
|
||||
class TargetResists(ContextMenuUnconditional):
|
||||
|
||||
def __init__(self):
|
||||
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
self.settings = ContextMenuSettings.getInstance()
|
||||
|
||||
def display(self, srcContext, selection):
|
||||
def display(self, srcContext):
|
||||
if self.mainFrame.getActiveFit() is None or srcContext != "firepowerViewFull":
|
||||
return False
|
||||
|
||||
@@ -27,7 +28,7 @@ class TargetResists(ContextMenu):
|
||||
|
||||
return len(self.patterns) > 0
|
||||
|
||||
def getText(self, itmContext, selection):
|
||||
def getText(self, itmContext):
|
||||
return "Target Resists"
|
||||
|
||||
def handleResistSwitch(self, event):
|
||||
@@ -42,7 +43,7 @@ class TargetResists(ContextMenu):
|
||||
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID))
|
||||
|
||||
def addPattern(self, rootMenu, pattern):
|
||||
id = ContextMenu.nextID()
|
||||
id = ContextMenuUnconditional.nextID()
|
||||
name = getattr(pattern, "_name", pattern.name) if pattern is not None else "No Profile"
|
||||
|
||||
self.patternIds[id] = pattern
|
||||
@@ -63,7 +64,7 @@ class TargetResists(ContextMenu):
|
||||
item.SetBitmap(bitmap)
|
||||
return item
|
||||
|
||||
def getSubMenu(self, context, selection, rootMenu, i, pitem):
|
||||
def getSubMenu(self, context, rootMenu, i, pitem):
|
||||
msw = True if "wxMSW" in wx.PlatformInfo else False
|
||||
self.patternIds = {}
|
||||
self.subMenus = OrderedDict()
|
||||
@@ -92,7 +93,7 @@ class TargetResists(ContextMenu):
|
||||
# Items that have a parent
|
||||
for menuName, patterns in list(self.subMenus.items()):
|
||||
# Create parent item for root menu that is simply name of parent
|
||||
item = wx.MenuItem(rootMenu, ContextMenu.nextID(), menuName)
|
||||
item = wx.MenuItem(rootMenu, ContextMenuUnconditional.nextID(), menuName)
|
||||
|
||||
# Create menu for child items
|
||||
grandSub = wx.Menu()
|
||||
|
||||
@@ -82,7 +82,8 @@ class ItemAffectedBy(wx.Panel):
|
||||
# instead, we send the item.
|
||||
type_ = stuff.__class__.__name__
|
||||
contexts.append(("itemStats", type_))
|
||||
menu = ContextMenu.getMenu(stuff if type_ != "Skill" else stuff.item, *contexts)
|
||||
stuff = stuff if type_ != "Skill" else stuff.item
|
||||
menu = ContextMenu.getMenu(stuff, (stuff,), *contexts)
|
||||
self.PopupMenu(menu)
|
||||
|
||||
def ExpandCollapseTree(self):
|
||||
|
||||
@@ -4,6 +4,7 @@ import random
|
||||
import wx
|
||||
from logbook import Logger
|
||||
|
||||
import gui.fitCommands as cmd
|
||||
import gui.globalEvents as GE
|
||||
import gui.mainFrame
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
@@ -11,44 +12,91 @@ from service.fit import Fit
|
||||
from .attributeSlider import AttributeSlider, EVT_VALUE_CHANGED
|
||||
from .itemAttributes import ItemParams
|
||||
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class ItemMutator(wx.Panel):
|
||||
class ItemMutatorPanel(wx.Panel):
|
||||
|
||||
def __init__(self, parent, stuff, item):
|
||||
def __init__(self, parent, mod):
|
||||
wx.Panel.__init__(self, parent)
|
||||
self.stuff = stuff
|
||||
self.item = item
|
||||
self.timer = None
|
||||
self.activeFit = gui.mainFrame.MainFrame.getInstance().getActiveFit()
|
||||
|
||||
font = parent.GetFont()
|
||||
font.SetWeight(wx.BOLD)
|
||||
self.stuff = mod
|
||||
|
||||
mainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
sourceItemsSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
sourceItemsSizer.Add(BitmapLoader.getStaticBitmap(stuff.item.iconID, self, "icons"), 0, wx.LEFT, 5)
|
||||
sourceItemsSizer.Add(BitmapLoader.getStaticBitmap(stuff.mutaplasmid.item.iconID, self, "icons"), 0, wx.LEFT, 0)
|
||||
sourceItemShort = "{} {}".format(stuff.mutaplasmid.item.name.split(" ")[0], stuff.baseItem.name)
|
||||
headerSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
headerSizer.AddStretchSpacer()
|
||||
itemIcon = BitmapLoader.getStaticBitmap(mod.item.iconID, self, "icons")
|
||||
if itemIcon is not None:
|
||||
headerSizer.Add(itemIcon, 0, 0, 0)
|
||||
mutaIcon = BitmapLoader.getStaticBitmap(mod.mutaplasmid.item.iconID, self, "icons")
|
||||
if mutaIcon is not None:
|
||||
headerSizer.Add(mutaIcon, 0, wx.LEFT, 0)
|
||||
sourceItemShort = "{} {}".format(mod.mutaplasmid.item.name.split(" ")[0], mod.baseItem.name)
|
||||
sourceItemText = wx.StaticText(self, wx.ID_ANY, sourceItemShort)
|
||||
font = parent.GetFont()
|
||||
font.SetWeight(wx.BOLD)
|
||||
sourceItemText.SetFont(font)
|
||||
sourceItemsSizer.Add(sourceItemText, 0, wx.LEFT, 10)
|
||||
mainSizer.Add(sourceItemsSizer, 0, wx.TOP | wx.EXPAND, 10)
|
||||
headerSizer.Add(sourceItemText, 0, wx.LEFT, 10)
|
||||
headerSizer.AddStretchSpacer()
|
||||
mainSizer.Add(headerSizer, 0, wx.ALL | wx.EXPAND, 5)
|
||||
mainSizer.Add(wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0, wx.EXPAND, 0)
|
||||
|
||||
mainSizer.Add(wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0, wx.ALL | wx.EXPAND, 5)
|
||||
self.mutaList = ItemMutatorList(self, mod)
|
||||
mainSizer.Add(self.mutaList, 1, wx.EXPAND | wx.ALL, 0)
|
||||
|
||||
self.goodColor = wx.Colour(96, 191, 0)
|
||||
self.badColor = wx.Colour(255, 64, 0)
|
||||
mainSizer.Add(wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0, wx.EXPAND, 0)
|
||||
footerSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
self.refreshBtn = wx.Button(self, wx.ID_ANY, "Reset defaults", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
footerSizer.Add(self.refreshBtn, 0, wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 5)
|
||||
self.refreshBtn.Bind(wx.EVT_BUTTON, self.mutaList.resetMutatedValues)
|
||||
self.randomBtn = wx.Button(self, wx.ID_ANY, "Random stats", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
footerSizer.Add(self.randomBtn, 0, wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 5)
|
||||
self.randomBtn.Bind(wx.EVT_BUTTON, self.mutaList.randomMutatedValues)
|
||||
self.revertBtn = wx.Button(self, wx.ID_ANY, "Revert changes", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
footerSizer.Add(self.revertBtn, 0, wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 5)
|
||||
self.revertBtn.Bind(wx.EVT_BUTTON, self.mutaList.revertChanges)
|
||||
mainSizer.Add(footerSizer, 0, wx.ALL | wx.EXPAND, 5)
|
||||
|
||||
self.SetSizer(mainSizer)
|
||||
self.Layout()
|
||||
|
||||
def submitMutationChanges(self):
|
||||
self.mutaList.submitMutationChanges()
|
||||
|
||||
|
||||
class ItemMutatorList(wx.ScrolledWindow):
|
||||
|
||||
def __init__(self, parent, mod):
|
||||
wx.ScrolledWindow.__init__(self, parent)
|
||||
self.SetScrollRate(0, 15)
|
||||
self.carryingFitID = gui.mainFrame.MainFrame.getInstance().getActiveFit()
|
||||
self.initialMutations = {}
|
||||
self.mod = mod
|
||||
self.timer = None
|
||||
|
||||
goodColor = wx.Colour(96, 191, 0)
|
||||
badColor = wx.Colour(255, 64, 0)
|
||||
font = parent.GetFont()
|
||||
font.SetWeight(wx.BOLD)
|
||||
|
||||
sizer = wx.BoxSizer(wx.VERTICAL)
|
||||
|
||||
self.event_mapping = {}
|
||||
higOverrides = {
|
||||
('Stasis Web', 'speedFactor'): False,
|
||||
('Damage Control', 'duration'): True,
|
||||
}
|
||||
|
||||
for m in sorted(stuff.mutators.values(), key=lambda x: x.attribute.displayName):
|
||||
highIsGood = higOverrides.get((stuff.item.group.name, m.attribute.name), m.highIsGood)
|
||||
first = True
|
||||
for m in sorted(mod.mutators.values(), key=lambda x: x.attribute.displayName):
|
||||
if not first:
|
||||
sizer.Add(wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0, wx.ALL | wx.EXPAND, 5)
|
||||
first = False
|
||||
|
||||
self.initialMutations[m.attrID] = m.value
|
||||
|
||||
highIsGood = higOverrides.get((mod.item.group.name, m.attribute.name), m.highIsGood)
|
||||
# Format: [raw value, modifier applied to base raw value, display value]
|
||||
range1 = (m.minValue, m.attribute.unit.SimplifyValue(m.minValue))
|
||||
range2 = (m.maxValue, m.attribute.unit.SimplifyValue(m.maxValue))
|
||||
@@ -96,17 +144,17 @@ class ItemMutator(wx.Panel):
|
||||
|
||||
worseVal = ItemParams.FormatValue(*m.attribute.unit.PreformatValue(worseRange[0]), rounding='dec')
|
||||
worseText = wx.StaticText(self, wx.ID_ANY, worseVal)
|
||||
worseText.SetForegroundColour(self.badColor)
|
||||
worseText.SetForegroundColour(badColor)
|
||||
|
||||
betterVal = ItemParams.FormatValue(*m.attribute.unit.PreformatValue(betterRange[0]), rounding='dec')
|
||||
betterText = wx.StaticText(self, wx.ID_ANY, betterVal)
|
||||
betterText.SetForegroundColour(self.goodColor)
|
||||
betterText.SetForegroundColour(goodColor)
|
||||
|
||||
headingSizer.Add(worseText, 0, wx.ALL | wx.EXPAND, 0)
|
||||
headingSizer.Add(wx.StaticText(self, wx.ID_ANY, " ─ "), 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 5)
|
||||
headingSizer.Add(betterText, 0, wx.RIGHT | wx.EXPAND, 10)
|
||||
|
||||
mainSizer.Add(headingSizer, 0, wx.ALL | wx.EXPAND, 5)
|
||||
sizer.Add(headingSizer, 0, wx.ALL | wx.EXPAND, 5)
|
||||
|
||||
slider = AttributeSlider(parent=self,
|
||||
baseValue=m.attribute.unit.SimplifyValue(sliderBaseValue),
|
||||
@@ -116,29 +164,9 @@ class ItemMutator(wx.Panel):
|
||||
slider.SetValue(m.attribute.unit.SimplifyValue(m.value), False)
|
||||
slider.Bind(EVT_VALUE_CHANGED, self.changeMutatedValue)
|
||||
self.event_mapping[slider] = m
|
||||
mainSizer.Add(slider, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 10)
|
||||
sizer.Add(slider, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 10)
|
||||
|
||||
mainSizer.Add(wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0, wx.ALL | wx.EXPAND, 5)
|
||||
|
||||
mainSizer.AddStretchSpacer()
|
||||
|
||||
self.m_staticline = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL)
|
||||
mainSizer.Add(self.m_staticline, 0, wx.EXPAND)
|
||||
|
||||
bSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
|
||||
self.refreshBtn = wx.Button(self, wx.ID_ANY, "Reset defaults", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
bSizer.Add(self.refreshBtn, 0, wx.ALIGN_CENTER_VERTICAL)
|
||||
self.refreshBtn.Bind(wx.EVT_BUTTON, self.resetMutatedValues)
|
||||
|
||||
self.randomBtn = wx.Button(self, wx.ID_ANY, "Random stats", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
bSizer.Add(self.randomBtn, 0, wx.ALIGN_CENTER_VERTICAL)
|
||||
self.randomBtn.Bind(wx.EVT_BUTTON, self.randomMutatedValues)
|
||||
|
||||
mainSizer.Add(bSizer, 0, wx.RIGHT | wx.LEFT | wx.EXPAND, 0)
|
||||
|
||||
self.SetSizer(mainSizer)
|
||||
self.Layout()
|
||||
self.SetSizer(sizer)
|
||||
|
||||
def changeMutatedValue(self, evt):
|
||||
m = self.event_mapping[evt.Object]
|
||||
@@ -146,12 +174,12 @@ class ItemMutator(wx.Panel):
|
||||
value = m.attribute.unit.ComplicateValue(value)
|
||||
sFit = Fit.getInstance()
|
||||
|
||||
sFit.changeMutatedValue(m, value)
|
||||
sFit.changeMutatedValuePrelim(m, value)
|
||||
if self.timer:
|
||||
self.timer.Stop()
|
||||
self.timer = None
|
||||
|
||||
for x in self.Parent.Children:
|
||||
for x in self.Parent.Parent.Children:
|
||||
if isinstance(x, ItemParams):
|
||||
x.RefreshValues(None)
|
||||
break
|
||||
@@ -159,36 +187,54 @@ class ItemMutator(wx.Panel):
|
||||
|
||||
def resetMutatedValues(self, evt):
|
||||
sFit = Fit.getInstance()
|
||||
|
||||
for slider, m in self.event_mapping.items():
|
||||
value = sFit.changeMutatedValue(m, m.baseValue)
|
||||
value = sFit.changeMutatedValuePrelim(m, m.baseValue)
|
||||
value = m.attribute.unit.SimplifyValue(value)
|
||||
slider.SetValue(value)
|
||||
|
||||
evt.Skip()
|
||||
|
||||
def randomMutatedValues(self, evt):
|
||||
sFit = Fit.getInstance()
|
||||
|
||||
for slider, m in self.event_mapping.items():
|
||||
value = random.uniform(m.minValue, m.maxValue)
|
||||
value = sFit.changeMutatedValue(m, value)
|
||||
value = sFit.changeMutatedValuePrelim(m, value)
|
||||
value = m.attribute.unit.SimplifyValue(value)
|
||||
slider.SetValue(value)
|
||||
|
||||
evt.Skip()
|
||||
|
||||
def revertChanges(self, evt):
|
||||
sFit = Fit.getInstance()
|
||||
for slider, m in self.event_mapping.items():
|
||||
if m.attrID in self.initialMutations:
|
||||
value = sFit.changeMutatedValuePrelim(m, self.initialMutations[m.attrID])
|
||||
value = m.attribute.unit.SimplifyValue(value)
|
||||
slider.SetValue(value)
|
||||
evt.Skip()
|
||||
|
||||
def submitMutationChanges(self):
|
||||
fit = Fit.getInstance().getFit(self.carryingFitID)
|
||||
if self.mod in fit.modules:
|
||||
currentMutation = {}
|
||||
for m in self.event_mapping.values():
|
||||
currentMutation[m.attrID] = m.value
|
||||
mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
mainFrame.getCommandForFit(self.carryingFitID).Submit(cmd.GuiChangeLocalModuleMutationCommand(
|
||||
fitID=self.carryingFitID,
|
||||
position=fit.modules.index(self.mod),
|
||||
mutation=currentMutation,
|
||||
oldMutation=self.initialMutations))
|
||||
|
||||
def callLater(self):
|
||||
self.timer = None
|
||||
sFit = Fit.getInstance()
|
||||
|
||||
# recalc the fit that this module affects. This is not necessarily the currently active fit
|
||||
sFit.refreshFit(self.activeFit)
|
||||
sFit.refreshFit(self.carryingFitID)
|
||||
|
||||
mainFrame = gui.mainFrame.MainFrame.getInstance()
|
||||
activeFit = mainFrame.getActiveFit()
|
||||
|
||||
if activeFit != self.activeFit:
|
||||
if activeFit != self.carryingFitID:
|
||||
# if we're no longer on the fit this module is affecting, simulate a "switch fit" so that the active fit
|
||||
# can be recalculated (if needed)
|
||||
sFit.switchFit(activeFit)
|
||||
|
||||
@@ -21,7 +21,7 @@ class ItemView(Display):
|
||||
"attr:cpu,,,True"]
|
||||
|
||||
def __init__(self, parent, marketBrowser):
|
||||
Display.__init__(self, parent)
|
||||
Display.__init__(self, parent, style=wx.LC_SINGLE_SEL)
|
||||
pyfalog.debug("Initialize ItemView")
|
||||
marketBrowser.Bind(wx.EVT_TREE_SEL_CHANGED, self.treeSelectionChanged)
|
||||
|
||||
@@ -51,6 +51,7 @@ class ItemView(Display):
|
||||
|
||||
# Make reverse map, used by sorter
|
||||
self.metaMap = self.makeReverseMetaMap()
|
||||
self.active = []
|
||||
|
||||
# Fill up recently used modules set
|
||||
pyfalog.debug("Fill up recently used modules set")
|
||||
@@ -247,7 +248,7 @@ class ItemView(Display):
|
||||
sourceContext = "marketItemMisc" if self.marketBrowser.mode in ("search", "recent") else "marketItemGroup"
|
||||
itemContext = sMkt.getCategoryByItem(item).name
|
||||
|
||||
menu = ContextMenu.getMenu((item,), (sourceContext, itemContext))
|
||||
menu = ContextMenu.getMenu(item, (item,), (sourceContext, itemContext))
|
||||
self.PopupMenu(menu)
|
||||
|
||||
def populate(self, items):
|
||||
@@ -258,7 +259,7 @@ class ItemView(Display):
|
||||
sMkt = self.sMkt
|
||||
self.metalvls = sMkt.directAttrRequest(items, attrs)
|
||||
# Clear selection
|
||||
self.deselectItems()
|
||||
self.unselectAll()
|
||||
# Perform sorting, using item's meta levels besides other stuff
|
||||
items.sort(key=self.itemSort)
|
||||
# Mark current item list as active
|
||||
|
||||
@@ -37,6 +37,7 @@ class MarketTree(wx.TreeCtrl):
|
||||
|
||||
# Bind our lookup method to when the tree gets expanded
|
||||
self.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.expandLookup)
|
||||
self.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnCollapsed)
|
||||
|
||||
def addImage(self, iconFile, location="icons"):
|
||||
if iconFile is None:
|
||||
@@ -71,6 +72,10 @@ class MarketTree(wx.TreeCtrl):
|
||||
|
||||
self.SortChildren(root)
|
||||
|
||||
def OnCollapsed(self, event):
|
||||
self.CollapseAllChildren(event.Item)
|
||||
event.Skip()
|
||||
|
||||
def jump(self, item):
|
||||
"""Open market group and meta tab of given item"""
|
||||
sMkt = self.sMkt
|
||||
|
||||
@@ -80,10 +80,10 @@ class PFFittingEnginePref(PreferenceView):
|
||||
|
||||
# Future code once new cap sim is implemented
|
||||
'''
|
||||
self.cbGlobalForceReactivationTimer = wx.CheckBox( panel, wx.ID_ANY, u"Factor in reactivation timer", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.cbGlobalForceReactivationTimer = wx.CheckBox( panel, wx.ID_ANY, "Factor in reactivation timer", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
mainSizer.Add( self.cbGlobalForceReactivationTimer, 0, wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
text = u" Ignores reactivation timer when calculating capacitor usage,\n damage, and tank."
|
||||
text = " Ignores reactivation timer when calculating capacitor usage,\n damage, and tank."
|
||||
self.cbGlobalForceReactivationTimerText = wx.StaticText( panel, wx.ID_ANY, text, wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.cbGlobalForceReactivationTimerText.Wrap( -1 )
|
||||
self.cbGlobalForceReactivationTimerText.SetFont( wx.Font( 10, 70, 90, 90, False, wx.EmptyString ) )
|
||||
@@ -92,10 +92,10 @@ class PFFittingEnginePref(PreferenceView):
|
||||
|
||||
# Future code for mining laser crystal
|
||||
'''
|
||||
self.cbGlobalMiningSpecialtyCrystal = wx.CheckBox( panel, wx.ID_ANY, u"Factor in reactivation timer", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.cbGlobalMiningSpecialtyCrystal = wx.CheckBox( panel, wx.ID_ANY, "Factor in reactivation timer", wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
mainSizer.Add( self.cbGlobalMiningSpecialtyCrystal, 0, wx.ALL|wx.EXPAND, 5 )
|
||||
|
||||
text = u" If enabled, displays the Specialty Crystal mining amount.\n This is the amount mined when using crystals and mining the matching asteroid."
|
||||
text = " If enabled, displays the Specialty Crystal mining amount.\n This is the amount mined when using crystals and mining the matching asteroid."
|
||||
self.cbGlobalMiningSpecialtyCrystalText = wx.StaticText( panel, wx.ID_ANY, text, wx.DefaultPosition, wx.DefaultSize, 0 )
|
||||
self.cbGlobalMiningSpecialtyCrystalText.Wrap( -1 )
|
||||
self.cbGlobalMiningSpecialtyCrystalText.SetFont( wx.Font( 10, 70, 90, 90, False, wx.EmptyString ) )
|
||||
|
||||
@@ -75,7 +75,7 @@ class PFEsiPref(PreferenceView):
|
||||
fgAddrSizer.SetFlexibleDirection(wx.BOTH)
|
||||
fgAddrSizer.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED)
|
||||
|
||||
self.stSetID = wx.StaticText(panel, wx.ID_ANY, u"Client ID:", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stSetID = wx.StaticText(panel, wx.ID_ANY, "Client ID:", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stSetID.Wrap(-1)
|
||||
fgAddrSizer.Add(self.stSetID, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
|
||||
@@ -84,7 +84,7 @@ class PFEsiPref(PreferenceView):
|
||||
|
||||
fgAddrSizer.Add(self.inputClientID, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL | wx.EXPAND, 5)
|
||||
|
||||
self.stSetSecret = wx.StaticText(panel, wx.ID_ANY, u"Client Secret:", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stSetSecret = wx.StaticText(panel, wx.ID_ANY, "Client Secret:", wx.DefaultPosition, wx.DefaultSize, 0)
|
||||
self.stSetSecret.Wrap(-1)
|
||||
|
||||
fgAddrSizer.Add(self.stSetSecret, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
from wx.lib.intctrl import IntCtrl
|
||||
|
||||
from gui.preferenceView import PreferenceView
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
|
||||
import gui.mainFrame
|
||||
import gui.globalEvents as GE
|
||||
from service.settings import SettingsProvider
|
||||
import gui.mainFrame
|
||||
from gui.bitmap_loader import BitmapLoader
|
||||
from gui.preferenceView import PreferenceView
|
||||
from service.fit import Fit
|
||||
from service.price import Price
|
||||
from service.settings import SettingsProvider
|
||||
|
||||
|
||||
class PFGeneralPref(PreferenceView):
|
||||
|
||||
title = "General"
|
||||
|
||||
def populatePanel(self, panel):
|
||||
@@ -85,7 +83,7 @@ class PFGeneralPref(PreferenceView):
|
||||
if "wxGTK" not in wx.PlatformInfo:
|
||||
self.cbReloadAll.SetCursor(helpCursor)
|
||||
self.cbReloadAll.SetToolTip(wx.ToolTip(
|
||||
'When disabled, reloads charges just in selected modules. Action can be reversed by holding Ctrl key while changing charge.'))
|
||||
'When disabled, reloads charges just in selected modules. Action can be reversed by holding Ctrl or Alt key while changing charge.'))
|
||||
mainSizer.Add(self.cbReloadAll, 0, wx.ALL | wx.EXPAND, 5)
|
||||
|
||||
self.sFit = Fit.getInstance()
|
||||
|
||||
@@ -185,13 +185,14 @@ class FitItem(SFItem.SFBrowserItem):
|
||||
if activeFit:
|
||||
sFit = Fit.getInstance()
|
||||
projectedFit = sFit.getFit(self.fitID)
|
||||
if self.mainFrame.command.Submit(cmd.GuiAddProjectedCommand(activeFit, projectedFit.ID, 'fit')):
|
||||
command = cmd.GuiAddProjectedFitCommand(fitID=activeFit, projectedFitID=projectedFit.ID, amount=1)
|
||||
if self.mainFrame.command.Submit(command):
|
||||
self.mainFrame.additionsPane.select("Projected")
|
||||
|
||||
def OnAddCommandFit(self, event):
|
||||
activeFit = self.mainFrame.getActiveFit()
|
||||
if activeFit:
|
||||
if self.mainFrame.command.Submit(cmd.GuiAddCommandFitCommand(activeFit, self.fitID)):
|
||||
if self.mainFrame.command.Submit(cmd.GuiAddCommandFitCommand(fitID=activeFit, commandFitID=self.fitID)):
|
||||
self.mainFrame.additionsPane.select("Command")
|
||||
|
||||
def OnMouseCaptureLost(self, event):
|
||||
@@ -345,7 +346,8 @@ class FitItem(SFItem.SFBrowserItem):
|
||||
return
|
||||
|
||||
# to prevent accidental deletion, give dialog confirmation unless shift is depressed
|
||||
if wx.GetMouseState().ShiftDown() or wx.GetMouseState().MiddleIsDown():
|
||||
mstate = wx.GetMouseState()
|
||||
if mstate.GetModifiers() == wx.MOD_SHIFT or mstate.MiddleIsDown():
|
||||
self.deleteFit()
|
||||
else:
|
||||
dlg = wx.MessageDialog(
|
||||
|
||||
@@ -22,6 +22,7 @@ import wx
|
||||
|
||||
|
||||
class PFListPane(wx.ScrolledWindow):
|
||||
|
||||
def __init__(self, parent):
|
||||
wx.ScrolledWindow.__init__(self, parent, pos=wx.DefaultPosition, style=wx.TAB_TRAVERSAL)
|
||||
|
||||
@@ -150,6 +151,11 @@ class PFListPane(wx.ScrolledWindow):
|
||||
self._wList[i].Refresh()
|
||||
self.itemsHeight = max(self.itemsHeight, iheight - 1)
|
||||
|
||||
# This is needed as under GTK wx does not emit scroll up/scroll down
|
||||
# events, see issue #1909 for more info
|
||||
if 'wxGTK' in wx.PlatformInfo:
|
||||
self.SetScrollRate(0, self.itemsHeight)
|
||||
|
||||
def RemoveWidget(self, child):
|
||||
child.Destroy()
|
||||
self._wList.remove(child)
|
||||
|
||||
@@ -108,7 +108,7 @@ class ShipItem(SFItem.SFBrowserItem):
|
||||
pos = event.GetPosition()
|
||||
pos = self.ScreenToClient(pos)
|
||||
contexts = [("baseShip", "Ship Basic")]
|
||||
menu = ContextMenu.getMenu(self.baseItem, *contexts)
|
||||
menu = ContextMenu.getMenu(self.baseItem, (self.baseItem,), *contexts)
|
||||
self.PopupMenu(menu, pos)
|
||||
|
||||
def OnTimer(self, event):
|
||||
|
||||
@@ -49,6 +49,7 @@ class ResourcesViewFull(StatsView):
|
||||
self.toggleContext("fighter")
|
||||
else:
|
||||
self.toggleContext("drone")
|
||||
event.Skip()
|
||||
|
||||
def toggleContext(self, context):
|
||||
# Apparently you cannot .Hide(True) on a Window, otherwise I would just .Hide(context !== x).
|
||||
|
||||
@@ -1,259 +0,0 @@
|
||||
# =============================================================================
|
||||
# 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/>.
|
||||
# =============================================================================
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
from gui.statsView import StatsView
|
||||
from gui.utils.numberFormatter import formatAmount
|
||||
from collections import OrderedDict
|
||||
|
||||
|
||||
class TargetingMiscViewFull(StatsView):
|
||||
name = "targetingMiscViewFull"
|
||||
|
||||
def __init__(self, parent):
|
||||
StatsView.__init__(self)
|
||||
self.parent = parent
|
||||
self._cachedValues = []
|
||||
|
||||
def getHeaderText(self, fit):
|
||||
return "Targeting && Misc"
|
||||
|
||||
def getTextExtentW(self, text):
|
||||
width, height = self.parent.GetTextExtent(text)
|
||||
return width
|
||||
|
||||
def populatePanel(self, contentPanel, headerPanel):
|
||||
contentSizer = contentPanel.GetSizer()
|
||||
|
||||
self.panel = contentPanel
|
||||
self.headerPanel = headerPanel
|
||||
gridTargetingMisc = wx.FlexGridSizer(1, 3, 0, 0)
|
||||
contentSizer.Add(gridTargetingMisc, 0, wx.EXPAND | wx.ALL, 0)
|
||||
gridTargetingMisc.AddGrowableCol(0)
|
||||
gridTargetingMisc.AddGrowableCol(2)
|
||||
# Targeting
|
||||
|
||||
gridTargeting = wx.FlexGridSizer(5, 2, 0, 0)
|
||||
gridTargeting.AddGrowableCol(1)
|
||||
|
||||
gridTargetingMisc.Add(gridTargeting, 0, wx.ALIGN_LEFT | wx.ALL, 5)
|
||||
|
||||
labels = (("Targets", "Targets", ""),
|
||||
("Range", "Range", "km"),
|
||||
("Scan res.", "ScanRes", "mm"),
|
||||
("Sensor str.", "SensorStr", ""),
|
||||
("Drone range", "CtrlRange", "km"))
|
||||
|
||||
for header, labelShort, unit in labels:
|
||||
gridTargeting.Add(wx.StaticText(contentPanel, wx.ID_ANY, "%s: " % header), 0, wx.ALIGN_LEFT)
|
||||
|
||||
box = wx.BoxSizer(wx.HORIZONTAL)
|
||||
gridTargeting.Add(box, 0, wx.ALIGN_LEFT)
|
||||
|
||||
lbl = wx.StaticText(contentPanel, wx.ID_ANY, "0 %s" % unit)
|
||||
setattr(self, "label%s" % labelShort, lbl)
|
||||
box.Add(lbl, 0, wx.ALIGN_LEFT)
|
||||
|
||||
self._cachedValues.append({"main": 0})
|
||||
|
||||
# Misc
|
||||
gridTargetingMisc.Add(wx.StaticLine(contentPanel, wx.ID_ANY, style=wx.VERTICAL), 0, wx.EXPAND, 3)
|
||||
gridMisc = wx.FlexGridSizer(5, 2, 0, 0)
|
||||
gridMisc.AddGrowableCol(1)
|
||||
gridTargetingMisc.Add(gridMisc, 0, wx.ALIGN_LEFT | wx.ALL, 5)
|
||||
|
||||
labels = (("Speed", "Speed", "m/s"),
|
||||
("Align time", "AlignTime", "s"),
|
||||
("Signature", "SigRadius", "m"),
|
||||
("Warp Speed", "WarpSpeed", "AU/s"),
|
||||
("Cargo", "Cargo", "m\u00B3"))
|
||||
|
||||
for header, labelShort, unit in labels:
|
||||
gridMisc.Add(wx.StaticText(contentPanel, wx.ID_ANY, "%s: " % header), 0, wx.ALIGN_LEFT)
|
||||
|
||||
box = wx.BoxSizer(wx.HORIZONTAL)
|
||||
gridMisc.Add(box, 0, wx.ALIGN_LEFT)
|
||||
|
||||
lbl = wx.StaticText(contentPanel, wx.ID_ANY, "0 %s" % unit)
|
||||
setattr(self, "labelFull%s" % labelShort, lbl)
|
||||
box.Add(lbl, 0, wx.ALIGN_LEFT)
|
||||
|
||||
self._cachedValues.append({"main": 0})
|
||||
|
||||
def refreshPanel(self, fit):
|
||||
# If we did anything interesting, we'd update our labels to reflect the new fit's stats here
|
||||
|
||||
cargoNamesOrder = OrderedDict((
|
||||
("fleetHangarCapacity", "Fleet hangar"),
|
||||
("shipMaintenanceBayCapacity", "Maintenance bay"),
|
||||
("specialAmmoHoldCapacity", "Ammo hold"),
|
||||
("specialFuelBayCapacity", "Fuel bay"),
|
||||
("specialShipHoldCapacity", "Ship hold"),
|
||||
("specialSmallShipHoldCapacity", "Small ship hold"),
|
||||
("specialMediumShipHoldCapacity", "Medium ship hold"),
|
||||
("specialLargeShipHoldCapacity", "Large ship hold"),
|
||||
("specialIndustrialShipHoldCapacity", "Industrial ship hold"),
|
||||
("specialOreHoldCapacity", "Ore hold"),
|
||||
("specialMineralHoldCapacity", "Mineral hold"),
|
||||
("specialMaterialBayCapacity", "Material bay"),
|
||||
("specialGasHoldCapacity", "Gas hold"),
|
||||
("specialSalvageHoldCapacity", "Salvage hold"),
|
||||
("specialCommandCenterHoldCapacity", "Command center hold"),
|
||||
("specialPlanetaryCommoditiesHoldCapacity", "Planetary goods hold"),
|
||||
("specialQuafeHoldCapacity", "Quafe hold")
|
||||
))
|
||||
|
||||
cargoValues = {
|
||||
"main": lambda: fit.ship.getModifiedItemAttr("capacity"),
|
||||
"fleetHangarCapacity": lambda: fit.ship.getModifiedItemAttr("fleetHangarCapacity"),
|
||||
"shipMaintenanceBayCapacity": lambda: fit.ship.getModifiedItemAttr("shipMaintenanceBayCapacity"),
|
||||
"specialAmmoHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialAmmoHoldCapacity"),
|
||||
"specialFuelBayCapacity": lambda: fit.ship.getModifiedItemAttr("specialFuelBayCapacity"),
|
||||
"specialShipHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialShipHoldCapacity"),
|
||||
"specialSmallShipHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialSmallShipHoldCapacity"),
|
||||
"specialMediumShipHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialMediumShipHoldCapacity"),
|
||||
"specialLargeShipHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialLargeShipHoldCapacity"),
|
||||
"specialIndustrialShipHoldCapacity": lambda: fit.ship.getModifiedItemAttr(
|
||||
"specialIndustrialShipHoldCapacity"),
|
||||
"specialOreHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialOreHoldCapacity"),
|
||||
"specialMineralHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialMineralHoldCapacity"),
|
||||
"specialMaterialBayCapacity": lambda: fit.ship.getModifiedItemAttr("specialMaterialBayCapacity"),
|
||||
"specialGasHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialGasHoldCapacity"),
|
||||
"specialSalvageHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialSalvageHoldCapacity"),
|
||||
"specialCommandCenterHoldCapacity": lambda: fit.ship.getModifiedItemAttr(
|
||||
"specialCommandCenterHoldCapacity"),
|
||||
"specialPlanetaryCommoditiesHoldCapacity": lambda: fit.ship.getModifiedItemAttr(
|
||||
"specialPlanetaryCommoditiesHoldCapacity"),
|
||||
"specialQuafeHoldCapacity": lambda: fit.ship.getModifiedItemAttr("specialQuafeHoldCapacity")
|
||||
}
|
||||
|
||||
stats = (("labelTargets", {"main": lambda: fit.maxTargets}, 3, 0, 0, ""),
|
||||
("labelRange", {"main": lambda: fit.maxTargetRange / 1000}, 3, 0, 0, "km"),
|
||||
("labelScanRes", {"main": lambda: fit.ship.getModifiedItemAttr("scanResolution")}, 3, 0, 0, "mm"),
|
||||
("labelSensorStr", {"main": lambda: fit.scanStrength}, 3, 0, 0, ""),
|
||||
("labelCtrlRange", {"main": lambda: fit.extraAttributes["droneControlRange"] / 1000}, 3, 0, 0, "km"),
|
||||
("labelFullSpeed", {"main": lambda: fit.maxSpeed}, 3, 0, 0, "m/s"),
|
||||
("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, 4, 0, 9, "m\u00B3"))
|
||||
|
||||
counter = 0
|
||||
RADII = [("Pod", 25), ("Interceptor", 33), ("Frigate", 38),
|
||||
("Destroyer", 83), ("Cruiser", 130),
|
||||
("Battlecruiser", 265), ("Battleship", 420),
|
||||
("Carrier", 3000)]
|
||||
for labelName, valueDict, prec, lowest, highest, unit in stats:
|
||||
label = getattr(self, labelName)
|
||||
newValues = {}
|
||||
for valueAlias, value in list(valueDict.items()):
|
||||
value = value() if fit is not None else 0
|
||||
value = value if value is not None else 0
|
||||
newValues[valueAlias] = value
|
||||
if self._cachedValues[counter] != newValues:
|
||||
mainValue = newValues["main"]
|
||||
otherValues = dict((k, newValues[k]) for k in [k for k in newValues if k != "main"])
|
||||
if labelName == "labelFullCargo":
|
||||
# Get sum of all cargoholds except for maintenance bay
|
||||
additionalCargo = sum(otherValues.values())
|
||||
if additionalCargo > 0:
|
||||
label.SetLabel("%s+%s %s" % (formatAmount(mainValue, prec, lowest, highest),
|
||||
formatAmount(additionalCargo, prec, lowest, highest),
|
||||
unit))
|
||||
else:
|
||||
label.SetLabel("%s %s" % (formatAmount(mainValue, prec, lowest, highest), unit))
|
||||
else:
|
||||
label.SetLabel("%s %s" % (formatAmount(mainValue, prec, lowest, highest), unit))
|
||||
# Tooltip stuff
|
||||
if fit:
|
||||
if labelName == "labelScanRes":
|
||||
lockTime = "%s\n" % "Lock Times".center(30)
|
||||
for size, radius in RADII:
|
||||
left = "%.1fs" % fit.calculateLockTime(radius)
|
||||
right = "%s [%d]" % (size, radius)
|
||||
lockTime += "%5s\t%s\n" % (left, right)
|
||||
label.SetToolTip(wx.ToolTip(lockTime))
|
||||
elif labelName == "labelFullSigRadius":
|
||||
label.SetToolTip(wx.ToolTip("Probe Size: %.3f" % (fit.probeSize or 0)))
|
||||
elif labelName == "labelFullWarpSpeed":
|
||||
maxWarpDistance = "Max Warp Distance: %.1f AU" % fit.maxWarpDistance
|
||||
if fit.ship.getModifiedItemAttr("warpScrambleStatus"):
|
||||
warpScrambleStatus = "Warp Core Strength: %.1f" % (fit.ship.getModifiedItemAttr("warpScrambleStatus") * -1)
|
||||
else:
|
||||
warpScrambleStatus = "Warp Core Strength: %.1f" % 0
|
||||
label.SetToolTip(wx.ToolTip("%s\n%s" % (maxWarpDistance, warpScrambleStatus)))
|
||||
elif labelName == "labelSensorStr":
|
||||
if fit.jamChance > 0:
|
||||
label.SetToolTip(
|
||||
wx.ToolTip("Type: %s\n%.1f%% Chance of Jam" % (fit.scanType, fit.jamChance)))
|
||||
else:
|
||||
label.SetToolTip(wx.ToolTip("Type: %s" % fit.scanType))
|
||||
elif labelName == "labelFullAlignTime":
|
||||
alignTime = "Align:\t%.3fs" % mainValue
|
||||
mass = 'Mass:\t{:,.0f}kg'.format(fit.ship.getModifiedItemAttr("mass"))
|
||||
agility = "Agility:\t%.3fx" % (fit.ship.getModifiedItemAttr("agility") or 0)
|
||||
label.SetToolTip(wx.ToolTip("%s\n%s\n%s" % (alignTime, mass, agility)))
|
||||
elif labelName == "labelFullCargo":
|
||||
tipLines = ["Cargohold: {:,.2f}m\u00B3 / {:,.2f}m\u00B3".format(fit.cargoBayUsed, newValues["main"])]
|
||||
for attrName, tipAlias in list(cargoNamesOrder.items()):
|
||||
if newValues[attrName] > 0:
|
||||
tipLines.append("{}: {:,.2f}m\u00B3".format(tipAlias, newValues[attrName]))
|
||||
label.SetToolTip(wx.ToolTip("\n".join(tipLines)))
|
||||
else:
|
||||
label.SetToolTip(wx.ToolTip("%.1f" % mainValue))
|
||||
else:
|
||||
label.SetToolTip(wx.ToolTip(""))
|
||||
self._cachedValues[counter] = newValues
|
||||
elif labelName == "labelFullWarpSpeed":
|
||||
if fit:
|
||||
maxWarpDistance = "Max Warp Distance: %.1f AU" % fit.maxWarpDistance
|
||||
if fit.ship.getModifiedItemAttr("warpScrambleStatus"):
|
||||
warpScrambleStatus = "Warp Core Strength: %.1f" % (fit.ship.getModifiedItemAttr("warpScrambleStatus") * -1)
|
||||
else:
|
||||
warpScrambleStatus = "Warp Core Strength: %.1f" % 0
|
||||
label.SetToolTip(wx.ToolTip("%s\n%s" % (maxWarpDistance, warpScrambleStatus)))
|
||||
elif labelName == "labelSensorStr":
|
||||
if fit:
|
||||
if fit.jamChance > 0:
|
||||
label.SetToolTip(wx.ToolTip("Type: %s\n%.1f%% Chance of Jam" % (fit.scanType, fit.jamChance)))
|
||||
else:
|
||||
label.SetToolTip(wx.ToolTip("Type: %s" % fit.scanType))
|
||||
else:
|
||||
label.SetToolTip(wx.ToolTip(""))
|
||||
elif labelName == "labelFullCargo":
|
||||
if fit:
|
||||
cachedCargo = self._cachedValues[counter]
|
||||
# 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 = ["Cargohold: {:,.2f}m\u00B3 / {:,.2f}m\u00B3".format(fit.cargoBayUsed, cachedCargo["main"])]
|
||||
for attrName, tipAlias in list(cargoNamesOrder.items()):
|
||||
if cachedCargo[attrName] > 0:
|
||||
tipLines.append("{}: {:,.2f}m\u00B3".format(tipAlias, cachedCargo[attrName]))
|
||||
label.SetToolTip(wx.ToolTip("\n".join(tipLines)))
|
||||
else:
|
||||
label.SetToolTip(wx.ToolTip(""))
|
||||
|
||||
counter += 1
|
||||
|
||||
self.panel.Layout()
|
||||
self.headerPanel.Layout()
|
||||
|
||||
|
||||
TargetingMiscViewFull.register()
|
||||
@@ -258,6 +258,35 @@ class Miscellanea(ViewColumn):
|
||||
|
||||
tooltip = "{0} disruption".format(formatList(ttEntries)).capitalize()
|
||||
return text, tooltip
|
||||
elif itemGroup in ("Gyrostabilizer", "Magnetic Field Stabilizer", "Heat Sink", "Ballistic Control system", "Entropic Radiation Sink"):
|
||||
attrMap = {
|
||||
"Gyrostabilizer": ("damageMultiplier", "speedMultiplier", "Projectile weapon"),
|
||||
"Magnetic Field Stabilizer": ("damageMultiplier", "speedMultiplier", "Hybrid weapon"),
|
||||
"Heat Sink": ("damageMultiplier", "speedMultiplier", "Energy weapon"),
|
||||
"Ballistic Control system": ("missileDamageMultiplierBonus", "speedMultiplier", "Missile"),
|
||||
"Entropic Radiation Sink": ("damageMultiplier", "speedMultiplier", "Precursor weapon")}
|
||||
dmgAttr, rofAttr, weaponName = attrMap[itemGroup]
|
||||
dmg = stuff.getModifiedItemAttr(dmgAttr)
|
||||
rof = stuff.getModifiedItemAttr(rofAttr)
|
||||
if not dmg or not rof:
|
||||
return "", None
|
||||
texts = []
|
||||
tooltips = []
|
||||
cumulative = (dmg / rof - 1) * 100
|
||||
texts.append("{}%".format(formatAmount(cumulative, 3, 0, 3, forceSign=True)))
|
||||
tooltips.append("{} DPS boost".format(weaponName))
|
||||
droneDmg = stuff.getModifiedItemAttr("droneDamageBonus")
|
||||
if droneDmg:
|
||||
texts.append("{}%".format(formatAmount(droneDmg, 3, 0, 3, forceSign=True)))
|
||||
tooltips.append("drone DPS boost".format(weaponName))
|
||||
return ' | '.join(texts), ' and '.join(tooltips)
|
||||
elif itemGroup == "Drone Damage Modules":
|
||||
dmg = stuff.getModifiedItemAttr("droneDamageBonus")
|
||||
if not dmg:
|
||||
return
|
||||
text = "{}%".format(formatAmount(dmg, 3, 0, 3, forceSign=True))
|
||||
tooltip = "Drone DPS boost"
|
||||
return text, tooltip
|
||||
elif itemGroup in ("ECM", "Burst Jammer", "Burst Projectors"):
|
||||
grav = stuff.getModifiedItemAttr("scanGravimetricStrengthBonus")
|
||||
ladar = stuff.getModifiedItemAttr("scanLadarStrengthBonus")
|
||||
@@ -499,9 +528,9 @@ class Miscellanea(ViewColumn):
|
||||
text = "{0}/s".format(formatAmount(capPerSec, 3, 0, 3))
|
||||
tooltip = "Energy neutralization per second"
|
||||
return text, tooltip
|
||||
elif itemGroup == "Micro Jump Drive":
|
||||
elif itemGroup in ("Micro Jump Drive", "Micro Jump Field Generators"):
|
||||
cycleTime = stuff.getModifiedItemAttr("duration") / 1000
|
||||
text = "{0}s".format(cycleTime)
|
||||
text = "{0}s".format(formatAmount(cycleTime, 3, 0, 3))
|
||||
tooltip = "Spoolup time"
|
||||
return text, tooltip
|
||||
elif itemGroup in ("Siege Module", "Cynosural Field Generator"):
|
||||
|
||||
@@ -42,6 +42,7 @@ from gui.utils.staticHelpers import DragDropHelper
|
||||
from service.fit import Fit
|
||||
from service.market import Market
|
||||
from config import slotColourMap
|
||||
from gui.fitCommands.helpers import getSimilarModPositions
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
@@ -74,8 +75,8 @@ class FitSpawner(gui.multiSwitch.TabSpawner):
|
||||
sFit = Fit.getInstance()
|
||||
openFitInNew = sFit.serviceFittingOptions["openFitInNew"]
|
||||
mstate = wx.GetMouseState()
|
||||
|
||||
if from_import or (not openFitInNew and mstate.CmdDown()) or startup or (openFitInNew and not mstate.CmdDown()):
|
||||
modifierKey = mstate.GetModifiers() == wx.MOD_CONTROL
|
||||
if from_import or (not openFitInNew and modifierKey) or startup or (openFitInNew and not modifierKey):
|
||||
self.multiSwitch.AddPage()
|
||||
|
||||
view = self.multiSwitch.GetSelectedPage()
|
||||
@@ -163,7 +164,7 @@ class FittingView(d.Display):
|
||||
self.hoveredRow = None
|
||||
self.hoveredColumn = None
|
||||
|
||||
self.Bind(wx.EVT_KEY_UP, self.kbEvent)
|
||||
self.Bind(wx.EVT_KEY_DOWN, self.kbEvent)
|
||||
self.Bind(wx.EVT_LEFT_DOWN, self.click)
|
||||
self.Bind(wx.EVT_RIGHT_DOWN, self.click)
|
||||
self.Bind(wx.EVT_MIDDLE_DOWN, self.click)
|
||||
@@ -189,7 +190,7 @@ class FittingView(d.Display):
|
||||
self.hoveredRow = row
|
||||
self.hoveredColumn = col
|
||||
if row != -1 and row not in self.blanks and col != -1 and col < len(self.DEFAULT_COLS):
|
||||
mod = self.mods[self.GetItemData(row)]
|
||||
mod = self.mods[row]
|
||||
tooltip = self.activeColumns[col].getToolTip(mod)
|
||||
if tooltip is not None:
|
||||
self.SetToolTip(tooltip)
|
||||
@@ -207,7 +208,6 @@ class FittingView(d.Display):
|
||||
data[0] is hard-coded str of originating source
|
||||
data[1] is typeID or index of data we want to manipulate
|
||||
"""
|
||||
|
||||
if data[0] == "fitting":
|
||||
self.swapItems(x, y, int(data[1]))
|
||||
elif data[0] == "cargo":
|
||||
@@ -237,44 +237,57 @@ class FittingView(d.Display):
|
||||
return self.activeFitID
|
||||
|
||||
def startDrag(self, event):
|
||||
row = event.GetIndex()
|
||||
srcRow = event.GetIndex()
|
||||
|
||||
if row != -1 and row not in self.blanks and isinstance(self.mods[row], Module) and not self.mods[row].isEmpty:
|
||||
data = wx.TextDataObject()
|
||||
dataStr = "fitting:" + str(self.mods[row].modPosition)
|
||||
data.SetText(dataStr)
|
||||
if srcRow == -1:
|
||||
return
|
||||
if srcRow in self.blanks:
|
||||
return
|
||||
try:
|
||||
mod = self.mods[srcRow]
|
||||
except IndexError:
|
||||
return
|
||||
if not isinstance(self.mods[srcRow], Module):
|
||||
return
|
||||
if mod.isEmpty:
|
||||
return
|
||||
fit = Fit.getInstance().getFit(self.activeFitID)
|
||||
if mod not in fit.modules:
|
||||
return
|
||||
|
||||
dropSource = wx.DropSource(self)
|
||||
dropSource.SetData(data)
|
||||
DragDropHelper.data = dataStr
|
||||
dropSource.DoDragDrop()
|
||||
self.unselectAll()
|
||||
self.Select(srcRow, True)
|
||||
|
||||
data = wx.TextDataObject()
|
||||
dataStr = "fitting:" + str(fit.modules.index(mod))
|
||||
data.SetText(dataStr)
|
||||
|
||||
dropSource = wx.DropSource(self)
|
||||
dropSource.SetData(data)
|
||||
DragDropHelper.data = dataStr
|
||||
dropSource.DoDragDrop()
|
||||
|
||||
def getSelectedMods(self):
|
||||
sel = []
|
||||
row = self.GetFirstSelected()
|
||||
while row != -1:
|
||||
mod = self.mods[self.GetItemData(row)]
|
||||
mods = []
|
||||
for row in self.getSelectedRows():
|
||||
try:
|
||||
mod = self.mods[row]
|
||||
except IndexError:
|
||||
continue
|
||||
if mod and not isinstance(mod, Rack):
|
||||
sel.append(mod)
|
||||
row = self.GetNextSelected(row)
|
||||
|
||||
return sel
|
||||
mods.append(mod)
|
||||
return mods
|
||||
|
||||
def kbEvent(self, event):
|
||||
keycode = event.GetKeyCode()
|
||||
if keycode == wx.WXK_DELETE or keycode == wx.WXK_NUMPAD_DELETE:
|
||||
row = self.GetFirstSelected()
|
||||
modules = []
|
||||
|
||||
while row != -1:
|
||||
if row not in self.blanks:
|
||||
mod = self.mods[row]
|
||||
if isinstance(mod, Module) and not mod.isEmpty:
|
||||
modules.append(self.mods[row])
|
||||
self.Select(row, 0)
|
||||
row = self.GetNextSelected(row)
|
||||
mstate = wx.GetMouseState()
|
||||
if keycode == wx.WXK_ESCAPE and mstate.GetModifiers() == wx.MOD_NONE:
|
||||
self.unselectAll()
|
||||
elif keycode == 65 and mstate.GetModifiers() == wx.MOD_CONTROL:
|
||||
self.selectAll()
|
||||
elif keycode in (wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE) and mstate.GetModifiers() == wx.MOD_NONE:
|
||||
modules = [m for m in self.getSelectedMods() if not m.isEmpty]
|
||||
self.removeModule(modules)
|
||||
|
||||
event.Skip()
|
||||
|
||||
def fitRemoved(self, event):
|
||||
@@ -358,35 +371,54 @@ class FittingView(d.Display):
|
||||
fitID = self.activeFitID
|
||||
if fitID is not None:
|
||||
item = Market.getInstance().getItem(itemID, eager='group.category')
|
||||
if item is None or not (item.isModule or item.isSubsystem):
|
||||
if item is None:
|
||||
event.Skip()
|
||||
return
|
||||
batchOp = wx.GetMouseState().GetModifiers() == wx.MOD_ALT and getattr(event, 'allowBatch', None) is not False
|
||||
# If we've selected ammo, then apply to the selected module(s)
|
||||
if item.isCharge:
|
||||
# If we've selected ammo, then apply to the selected module(s)
|
||||
modules = []
|
||||
sel = self.GetFirstSelected()
|
||||
while sel != -1 and sel not in self.blanks:
|
||||
mod = self.mods[self.GetItemData(sel)]
|
||||
if isinstance(mod, Module) and not mod.isEmpty:
|
||||
modules.append(self.mods[self.GetItemData(sel)])
|
||||
sel = self.GetNextSelected(sel)
|
||||
|
||||
if len(modules) > 0:
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeLocalModuleChargesCommand(fitID, modules, itemID))
|
||||
else:
|
||||
self.mainFrame.command.Submit(cmd.GuiAddLocalModuleCommand(fitID, itemID))
|
||||
positions = []
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
if batchOp:
|
||||
for position, mod in enumerate(fit.modules):
|
||||
if isinstance(mod, Module) and not mod.isEmpty:
|
||||
positions.append(position)
|
||||
else:
|
||||
for mod in self.getSelectedMods():
|
||||
if mod.isEmpty or mod not in fit.modules:
|
||||
continue
|
||||
positions.append(fit.modules.index(mod))
|
||||
if len(positions) > 0:
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeLocalModuleChargesCommand(
|
||||
fitID=fitID, positions=positions, chargeItemID=itemID))
|
||||
elif (item.isModule and not batchOp) or item.isSubsystem:
|
||||
self.mainFrame.command.Submit(cmd.GuiAddLocalModuleCommand(fitID=fitID, itemID=itemID))
|
||||
elif item.isModule and batchOp:
|
||||
self.mainFrame.command.Submit(cmd.GuiFillWithNewLocalModulesCommand(fitID=fitID, itemID=itemID))
|
||||
|
||||
event.Skip()
|
||||
|
||||
def removeItem(self, event):
|
||||
"""Double Left Click - remove module"""
|
||||
if event.CmdDown():
|
||||
if event.GetModifiers() == wx.MOD_CONTROL:
|
||||
return
|
||||
row, _ = self.HitTest(event.Position)
|
||||
if row != -1 and row not in self.blanks and isinstance(self.mods[row], Module):
|
||||
col = self.getColumn(event.Position)
|
||||
if col != self.getColIndex(State):
|
||||
self.removeModule(self.mods[row])
|
||||
try:
|
||||
mod = self.mods[row]
|
||||
except IndexError:
|
||||
return
|
||||
if not isinstance(mod, Module) or mod.isEmpty:
|
||||
return
|
||||
if event.GetModifiers() == wx.MOD_ALT:
|
||||
fit = Fit.getInstance().getFit(self.activeFitID)
|
||||
positions = getSimilarModPositions(fit.modules, mod)
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveLocalModuleCommand(
|
||||
fitID=self.activeFitID, positions=positions))
|
||||
else:
|
||||
self.removeModule(mod)
|
||||
else:
|
||||
if "wxMSW" in wx.PlatformInfo:
|
||||
self.click(event)
|
||||
@@ -396,19 +428,66 @@ class FittingView(d.Display):
|
||||
if not isinstance(modules, list):
|
||||
modules = [modules]
|
||||
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveLocalModuleCommand(self.activeFitID, modules))
|
||||
fit = Fit.getInstance().getFit(self.activeFitID)
|
||||
positions = []
|
||||
for position, mod in enumerate(fit.modules):
|
||||
if mod in modules:
|
||||
positions.append(position)
|
||||
|
||||
self.mainFrame.command.Submit(cmd.GuiRemoveLocalModuleCommand(
|
||||
fitID=self.activeFitID, positions=positions))
|
||||
|
||||
def addModule(self, x, y, itemID):
|
||||
"""Add a module from the market browser (from dragging it)"""
|
||||
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
item = Market.getInstance().getItem(itemID)
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
dstRow, _ = self.HitTest((x, y))
|
||||
if dstRow != -1 and dstRow not in self.blanks:
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
mod = self.mods[dstRow]
|
||||
if not isinstance(mod, Module): # make sure we're not adding something to a T3D Mode
|
||||
return
|
||||
if dstRow == -1 or dstRow in self.blanks:
|
||||
dstMod = None
|
||||
else:
|
||||
try:
|
||||
dstMod = self.mods[dstRow]
|
||||
except IndexError:
|
||||
dstMod = None
|
||||
if not isinstance(dstMod, Module):
|
||||
dstMod = None
|
||||
if dstMod not in fit.modules:
|
||||
dstMod = None
|
||||
dstPos = fit.modules.index(dstMod) if dstMod is not None else None
|
||||
mstate = wx.GetMouseState()
|
||||
# If we dropping on a module, try to replace, or add if replacement fails
|
||||
if item.isModule and dstMod is not None and not dstMod.isEmpty:
|
||||
positions = getSimilarModPositions(fit.modules, dstMod) if mstate.GetModifiers() == wx.MOD_ALT else [dstPos]
|
||||
command = cmd.GuiReplaceLocalModuleCommand(fitID=fitID, itemID=itemID, positions=positions)
|
||||
if not self.mainFrame.command.Submit(command):
|
||||
if mstate.GetModifiers() == wx.MOD_ALT:
|
||||
self.mainFrame.command.Submit(cmd.GuiFillWithNewLocalModulesCommand(fitID=fitID, itemID=itemID))
|
||||
else:
|
||||
self.mainFrame.command.Submit(cmd.GuiAddLocalModuleCommand(fitID=fitID, itemID=itemID))
|
||||
elif item.isModule:
|
||||
if mstate.GetModifiers() == wx.MOD_ALT:
|
||||
self.mainFrame.command.Submit(cmd.GuiFillWithNewLocalModulesCommand(fitID=fitID, itemID=itemID))
|
||||
else:
|
||||
self.mainFrame.command.Submit(cmd.GuiAddLocalModuleCommand(fitID=fitID, itemID=itemID))
|
||||
elif item.isSubsystem:
|
||||
self.mainFrame.command.Submit(cmd.GuiAddLocalModuleCommand(fitID=fitID, itemID=itemID))
|
||||
elif item.isCharge:
|
||||
failoverToAll = False
|
||||
positionsAll = list(range(len(fit.modules)))
|
||||
if dstMod is None or dstMod.isEmpty:
|
||||
positions = positionsAll
|
||||
elif mstate.GetModifiers() == wx.MOD_ALT:
|
||||
positions = getSimilarModPositions(fit.modules, dstMod)
|
||||
failoverToAll = True
|
||||
else:
|
||||
positions = [fit.modules.index(dstMod)]
|
||||
if len(positions) > 0:
|
||||
command = cmd.GuiChangeLocalModuleChargesCommand(fitID=fitID, positions=positions, chargeItemID=itemID)
|
||||
if not self.mainFrame.command.Submit(command) and failoverToAll:
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeLocalModuleChargesCommand(
|
||||
fitID=fitID, positions=positionsAll, chargeItemID=itemID))
|
||||
|
||||
self.mainFrame.command.Submit(cmd.GuiAddLocalModuleCommand(fitID, itemID, self.mods[dstRow].modPosition))
|
||||
|
||||
def swapCargo(self, x, y, cargoItemID):
|
||||
"""Swap a module from cargo to fitting window"""
|
||||
@@ -420,11 +499,15 @@ class FittingView(d.Display):
|
||||
if not isinstance(mod, Module):
|
||||
return
|
||||
|
||||
self.mainFrame.command.Submit(cmd.GuiCargoToLocalModuleCommand(
|
||||
fitID=self.mainFrame.getActiveFit(),
|
||||
cargoItemID=cargoItemID,
|
||||
modPosition=mod.modPosition,
|
||||
copy=wx.GetMouseState().CmdDown()))
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
if mod in fit.modules:
|
||||
position = fit.modules.index(mod)
|
||||
self.mainFrame.command.Submit(cmd.GuiCargoToLocalModuleCommand(
|
||||
fitID=fitID,
|
||||
cargoItemID=cargoItemID,
|
||||
modPosition=position,
|
||||
copy=wx.GetMouseState().GetModifiers() == wx.MOD_CONTROL))
|
||||
|
||||
def swapItems(self, x, y, srcIdx):
|
||||
"""Swap two modules in fitting window"""
|
||||
@@ -434,27 +517,30 @@ class FittingView(d.Display):
|
||||
dstRow, _ = self.HitTest((x, y))
|
||||
|
||||
if dstRow != -1 and dstRow not in self.blanks:
|
||||
mod1 = fit.modules[srcIdx]
|
||||
mod2 = self.mods[dstRow]
|
||||
|
||||
try:
|
||||
mod1 = fit.modules[srcIdx]
|
||||
mod2 = self.mods[dstRow]
|
||||
except IndexError:
|
||||
return
|
||||
if not isinstance(mod2, Module):
|
||||
return
|
||||
|
||||
# can't swap modules to different racks
|
||||
if mod1.slot != mod2.slot:
|
||||
return
|
||||
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
if getattr(mod2, "modPosition") is not None:
|
||||
mstate = wx.GetMouseState()
|
||||
if mstate.CmdDown() and mod2.isEmpty:
|
||||
self.mainFrame.command.Submit(cmd.GuiCloneLocalModuleCommand(
|
||||
fitID=fitID, srcPosition=srcIdx, dstPosition=mod2.modPosition))
|
||||
elif not mstate.CmdDown():
|
||||
self.mainFrame.command.Submit(cmd.GuiSwapLocalModulesCommand(
|
||||
fitID=fitID, position1=srcIdx, position2=mod2.modPosition))
|
||||
else:
|
||||
if mod2 not in fit.modules:
|
||||
pyfalog.error("Missing module position for: {0}", str(getattr(mod2, "ID", "Unknown")))
|
||||
return
|
||||
mod2Position = fit.modules.index(mod2)
|
||||
mstate = wx.GetMouseState()
|
||||
if mstate.GetModifiers() == wx.MOD_CONTROL | wx.MOD_ALT:
|
||||
self.mainFrame.command.Submit(cmd.GuiFillWithClonedLocalModulesCommand(
|
||||
fitID=self.activeFitID, position=srcIdx))
|
||||
elif mstate.GetModifiers() == wx.MOD_CONTROL and mod2.isEmpty:
|
||||
self.mainFrame.command.Submit(cmd.GuiCloneLocalModuleCommand(
|
||||
fitID=self.activeFitID, srcPosition=srcIdx, dstPosition=mod2Position))
|
||||
elif mstate.GetModifiers() == wx.MOD_NONE:
|
||||
self.mainFrame.command.Submit(cmd.GuiSwapLocalModulesCommand(
|
||||
fitID=self.activeFitID, position1=srcIdx, position2=mod2Position))
|
||||
|
||||
def generateMods(self):
|
||||
"""
|
||||
@@ -518,7 +604,6 @@ class FittingView(d.Display):
|
||||
self.populate(self.mods)
|
||||
|
||||
def fitChanged(self, event):
|
||||
# print('====== Fit Changed: {} {} activeFitID: {}, eventFitID: {}'.format(repr(self), str(bool(self)), self.activeFitID, event.fitID))
|
||||
if not self:
|
||||
event.Skip()
|
||||
return
|
||||
@@ -538,52 +623,52 @@ class FittingView(d.Display):
|
||||
event.Skip()
|
||||
|
||||
def spawnMenu(self, event):
|
||||
if self.activeFitID is None or self.getColumn(self.ScreenToClient(event.Position)) == self.getColIndex(State):
|
||||
if self.activeFitID is None or self.getColumn(self.screenToClientFixed(event.Position)) == self.getColIndex(State):
|
||||
return
|
||||
|
||||
sMkt = Market.getInstance()
|
||||
selection = []
|
||||
sel = self.GetFirstSelected()
|
||||
contexts = []
|
||||
|
||||
while sel != -1 and sel not in self.blanks:
|
||||
mod = self.mods[self.GetItemData(sel)]
|
||||
|
||||
for mod in self.getSelectedMods():
|
||||
# Test if this is a mode, which is a special snowflake of a Module
|
||||
if isinstance(mod, Mode):
|
||||
srcContext = "fittingMode"
|
||||
|
||||
itemContext = "Tactical Mode"
|
||||
fullContext = (srcContext, itemContext)
|
||||
if srcContext not in tuple(fCtxt[0] for fCtxt in contexts):
|
||||
contexts.append(fullContext)
|
||||
|
||||
selection.append(mod)
|
||||
|
||||
elif not mod.isEmpty:
|
||||
srcContext = "fittingModule"
|
||||
itemContext = sMkt.getCategoryByItem(mod.item).name
|
||||
selection.append(mod)
|
||||
|
||||
fit = Fit.getInstance().getFit(self.activeFitID)
|
||||
clickedPos = self.getRowByAbs(event.Position)
|
||||
mainMod = None
|
||||
if clickedPos != -1:
|
||||
try:
|
||||
mod = self.mods[clickedPos]
|
||||
except IndexError:
|
||||
pass
|
||||
else:
|
||||
if mod is not None and (mod in fit.modules or mod is fit.mode):
|
||||
mainMod = mod
|
||||
|
||||
sMkt = Market.getInstance()
|
||||
contexts = []
|
||||
if isinstance(mainMod, Module) and not mainMod.isEmpty:
|
||||
srcContext = "fittingModule"
|
||||
itemContext = sMkt.getCategoryByItem(mainMod.item).name
|
||||
fullContext = (srcContext, itemContext)
|
||||
if srcContext not in tuple(fCtx[0] for fCtx in contexts):
|
||||
contexts.append(fullContext)
|
||||
if mainMod.charge is not None:
|
||||
srcContext = "fittingCharge"
|
||||
itemContext = sMkt.getCategoryByItem(mainMod.charge).name
|
||||
fullContext = (srcContext, itemContext)
|
||||
if srcContext not in tuple(fCtxt[0] for fCtxt in contexts):
|
||||
contexts.append(fullContext)
|
||||
|
||||
if mod.charge is not None:
|
||||
srcContext = "fittingCharge"
|
||||
itemContext = sMkt.getCategoryByItem(mod.charge).name
|
||||
fullContext = (srcContext, itemContext)
|
||||
if srcContext not in tuple(fCtxt[0] for fCtxt in contexts):
|
||||
contexts.append(fullContext)
|
||||
|
||||
selection.append(mod)
|
||||
|
||||
sel = self.GetNextSelected(sel)
|
||||
|
||||
sFit = Fit.getInstance()
|
||||
fit = sFit.getFit(self.activeFitID)
|
||||
|
||||
elif isinstance(mainMod, Mode):
|
||||
srcContext = "fittingMode"
|
||||
itemContext = "Tactical Mode"
|
||||
fullContext = (srcContext, itemContext)
|
||||
if srcContext not in tuple(fCtx[0] for fCtx in contexts):
|
||||
contexts.append(fullContext)
|
||||
contexts.append(("fittingShip", "Ship" if not fit.isStructure else "Citadel"))
|
||||
|
||||
menu = ContextMenu.getMenu(selection, *contexts)
|
||||
menu = ContextMenu.getMenu(mainMod, selection, *contexts)
|
||||
self.PopupMenu(menu)
|
||||
|
||||
def click(self, event):
|
||||
@@ -595,34 +680,53 @@ class FittingView(d.Display):
|
||||
change State
|
||||
"""
|
||||
|
||||
row, _, col = self.HitTestSubItem(event.Position)
|
||||
clickedRow, _, col = self.HitTestSubItem(event.Position)
|
||||
|
||||
# only do State column and ignore invalid rows
|
||||
if row != -1 and row not in self.blanks and col == self.getColIndex(State):
|
||||
sel = []
|
||||
curr = self.GetFirstSelected()
|
||||
if clickedRow != -1 and clickedRow not in self.blanks and col == self.getColIndex(State):
|
||||
selectedRows = []
|
||||
currentRow = self.GetFirstSelected()
|
||||
|
||||
while curr != -1 and row not in self.blanks:
|
||||
sel.append(curr)
|
||||
curr = self.GetNextSelected(curr)
|
||||
while currentRow != -1 and clickedRow not in self.blanks:
|
||||
selectedRows.append(currentRow)
|
||||
currentRow = self.GetNextSelected(currentRow)
|
||||
|
||||
if row not in sel:
|
||||
mods = [self.mods[self.GetItemData(row)]]
|
||||
if clickedRow not in selectedRows:
|
||||
try:
|
||||
selectedMods = [self.mods[clickedRow]]
|
||||
except IndexError:
|
||||
return
|
||||
else:
|
||||
mods = self.getSelectedMods()
|
||||
selectedMods = self.getSelectedMods()
|
||||
|
||||
click = "ctrl" if event.GetModifiers() == wx.MOD_CONTROL or event.middleIsDown else "right" if event.GetButton() == 3 else "left"
|
||||
|
||||
try:
|
||||
mainMod = self.mods[clickedRow]
|
||||
except IndexError:
|
||||
return
|
||||
if mainMod.isEmpty:
|
||||
return
|
||||
fitID = self.mainFrame.getActiveFit()
|
||||
ctrl = event.cmdDown or event.middleIsDown
|
||||
click = "ctrl" if ctrl is True else "right" if event.GetButton() == 3 else "left"
|
||||
|
||||
fit = Fit.getInstance().getFit(fitID)
|
||||
if mainMod not in fit.modules:
|
||||
return
|
||||
mainPosition = fit.modules.index(mainMod)
|
||||
if event.GetModifiers() == wx.MOD_ALT:
|
||||
positions = getSimilarModPositions(fit.modules, mainMod)
|
||||
else:
|
||||
positions = []
|
||||
for position, mod in enumerate(fit.modules):
|
||||
if mod in selectedMods:
|
||||
positions.append(position)
|
||||
self.mainFrame.command.Submit(cmd.GuiChangeLocalModuleStatesCommand(
|
||||
fitID=fitID,
|
||||
mainPosition=self.mods[self.GetItemData(row)].modPosition,
|
||||
positions=[mod.modPosition for mod in mods],
|
||||
mainPosition=mainPosition,
|
||||
positions=positions,
|
||||
click=click))
|
||||
|
||||
# update state tooltip
|
||||
tooltip = self.activeColumns[col].getToolTip(self.mods[self.GetItemData(row)])
|
||||
tooltip = self.activeColumns[col].getToolTip(self.mods[clickedRow])
|
||||
if tooltip:
|
||||
self.SetToolTip(tooltip)
|
||||
|
||||
@@ -654,21 +758,25 @@ class FittingView(d.Display):
|
||||
self.SetItemBackgroundColour(i, self.GetBackgroundColour())
|
||||
|
||||
# only consider changing color if we're dealing with a Module
|
||||
if type(mod) is Module:
|
||||
hasRestrictionOverriden = getattr(mod, 'restrictionOverridden', None)
|
||||
# If module had broken fitting restrictions but now doesn't,
|
||||
# ensure it is now valid, and remove restrictionOverridden
|
||||
# variable. More in #1519
|
||||
if not fit.ignoreRestrictions and hasRestrictionOverriden:
|
||||
clean = False
|
||||
if mod.fits(fit, False):
|
||||
if not mod.hardpoint:
|
||||
clean = True
|
||||
elif fit.getHardpointsFree(mod.hardpoint) >= 0:
|
||||
clean = True
|
||||
if clean:
|
||||
del mod.restrictionOverridden
|
||||
hasRestrictionOverriden = not hasRestrictionOverriden
|
||||
if isinstance(mod, Module):
|
||||
hasRestrictionOverriden = False
|
||||
if not mod.isEmpty:
|
||||
fits = mod.fits(fit, False)
|
||||
hasRestrictionOverriden = getattr(mod, 'restrictionOverridden', None)
|
||||
# If module had broken fitting restrictions but now doesn't,
|
||||
# ensure it is now valid, and remove restrictionOverridden
|
||||
# variable. More in #1519
|
||||
if not fit.ignoreRestrictions and hasRestrictionOverriden:
|
||||
clean = False
|
||||
if fits:
|
||||
if not mod.hardpoint:
|
||||
clean = True
|
||||
elif fit.getHardpointsFree(mod.hardpoint) >= 0:
|
||||
clean = True
|
||||
if clean:
|
||||
del mod.restrictionOverridden
|
||||
hasRestrictionOverriden = not hasRestrictionOverriden
|
||||
|
||||
|
||||
if slotMap[mod.slot] or hasRestrictionOverriden: # Color too many modules as red
|
||||
self.SetItemBackgroundColour(i, wx.Colour(204, 51, 51))
|
||||
|
||||
@@ -11,6 +11,7 @@ from service.market import Market
|
||||
|
||||
|
||||
class BaseImplantEditorView(wx.Panel):
|
||||
|
||||
def addMarketViewImage(self, iconFile):
|
||||
if iconFile is None:
|
||||
return -1
|
||||
@@ -37,13 +38,6 @@ class BaseImplantEditorView(wx.Panel):
|
||||
availableSizer.Add(self.searchBox, 0, wx.EXPAND)
|
||||
availableSizer.Add(self.itemView, 1, wx.EXPAND)
|
||||
|
||||
'''
|
||||
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)
|
||||
@@ -202,7 +196,6 @@ class BaseImplantEditorView(wx.Panel):
|
||||
|
||||
class AvailableImplantsView(d.Display):
|
||||
DEFAULT_COLS = ["attr:implantness",
|
||||
"Base Icon",
|
||||
"Base Name"]
|
||||
|
||||
def __init__(self, parent):
|
||||
@@ -212,9 +205,7 @@ class AvailableImplantsView(d.Display):
|
||||
|
||||
class ItemView(d.Display):
|
||||
DEFAULT_COLS = ["Base Icon",
|
||||
"Base Name",
|
||||
"attr:power,,,True",
|
||||
"attr:cpu,,,True"]
|
||||
"Base Name"]
|
||||
|
||||
def __init__(self, parent):
|
||||
d.Display.__init__(self, parent)
|
||||
@@ -260,6 +251,7 @@ class ItemView(d.Display):
|
||||
self.Show()
|
||||
self.parent.Layout()
|
||||
|
||||
items = [i for i in items if i.group.name != 'Booster']
|
||||
self.items = sorted(list(items), key=lambda i: i.name)
|
||||
|
||||
self.update(self.items)
|
||||
|
||||
@@ -149,7 +149,7 @@ class CharacterEntityEditor(EntityEditor):
|
||||
|
||||
class CharacterEditor(wx.Frame):
|
||||
def __init__(self, parent):
|
||||
wx.Frame.__init__(self, parent, id=wx.ID_ANY, title="pyfa: Character Editor", pos=wx.DefaultPosition,
|
||||
wx.Frame.__init__(self, parent, id=wx.ID_ANY, title="Character Editor", pos=wx.DefaultPosition,
|
||||
size=wx.Size(640, 600), style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER | wx.FRAME_FLOAT_ON_PARENT)
|
||||
|
||||
i = wx.Icon(BitmapLoader.getBitmap("character_small", "gui"))
|
||||
@@ -208,6 +208,7 @@ class CharacterEditor(wx.Frame):
|
||||
self.Centre(wx.BOTH)
|
||||
|
||||
self.Bind(wx.EVT_CLOSE, self.closeEvent)
|
||||
self.Bind(wx.EVT_CHAR_HOOK, self.kbEvent)
|
||||
self.Bind(GE.CHAR_LIST_UPDATED, self.refreshCharacterList)
|
||||
self.entityEditor.Bind(wx.EVT_CHOICE, self.charChanged)
|
||||
|
||||
@@ -253,8 +254,17 @@ class CharacterEditor(wx.Frame):
|
||||
sChr.revertCharacter(char.ID)
|
||||
wx.PostEvent(self, GE.CharListUpdated())
|
||||
|
||||
def kbEvent(self, event):
|
||||
keycode = event.GetKeyCode()
|
||||
if keycode == wx.WXK_ESCAPE:
|
||||
self.closeWindow()
|
||||
return
|
||||
event.Skip()
|
||||
|
||||
def closeEvent(self, event):
|
||||
# del self.disableWin
|
||||
self.closeWindow()
|
||||
|
||||
def closeWindow(self):
|
||||
wx.PostEvent(self.mainFrame, GE.CharListUpdated())
|
||||
self.Destroy()
|
||||
|
||||
@@ -404,31 +414,18 @@ class SkillTreeView(wx.Panel):
|
||||
self.charEditor.entityEditor.Bind(wx.EVT_CHOICE, self.charChanged)
|
||||
self.charEditor.Bind(GE.CHAR_LIST_UPDATED, self.populateSkillTree)
|
||||
|
||||
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()
|
||||
# Context menu stuff
|
||||
self.idUnlearned = wx.NewId()
|
||||
self.levelIds = {}
|
||||
|
||||
idUnlearned = wx.NewId()
|
||||
self.levelIds[idUnlearned] = "Not learned"
|
||||
self.levelChangeMenu.Append(idUnlearned, "Unlearn")
|
||||
|
||||
self.idLevels = {}
|
||||
self.levelIds[self.idUnlearned] = "Not learned"
|
||||
for level in range(6):
|
||||
id = wx.NewId()
|
||||
self.levelIds[id] = level
|
||||
self.levelChangeMenu.Append(id, "Level %d" % level)
|
||||
|
||||
self.levelChangeMenu.AppendSeparator()
|
||||
self.idLevels[level] = id
|
||||
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)
|
||||
|
||||
# This cuases issues with GTK, see #1866
|
||||
@@ -597,15 +594,27 @@ class SkillTreeView(wx.Panel):
|
||||
if thing:
|
||||
return
|
||||
|
||||
char = self.charEditor.entityEditor.getActiveEntity()
|
||||
sMkt = Market.getInstance()
|
||||
id = self.skillTreeListCtrl.GetItemData(item)[1]
|
||||
eveItem = Market.getInstance().getItem(id)
|
||||
|
||||
srcContext = "skillItem"
|
||||
itemContext = "Skill"
|
||||
context = (srcContext, itemContext)
|
||||
menu = ContextMenu.getMenu(eveItem, [eveItem], context)
|
||||
char = self.charEditor.entityEditor.getActiveEntity()
|
||||
if char.name not in ("All 0", "All 5"):
|
||||
self.levelChangeMenu.selection = sMkt.getItem(id)
|
||||
self.PopupMenu(self.levelChangeMenu)
|
||||
else:
|
||||
self.statsMenu.selection = sMkt.getItem(id)
|
||||
self.PopupMenu(self.statsMenu)
|
||||
menu.AppendSeparator()
|
||||
menu.Append(self.idUnlearned, "Unlearn")
|
||||
for level in range(6):
|
||||
menu.Append(self.idLevels[level], "Level %d" % level)
|
||||
# Doesn't make sense to have these menu items here, as they do not revert skill changes
|
||||
# done in an editor - because these changes are persisted anyway
|
||||
# menu.AppendSeparator()
|
||||
# menu.Append(self.revertID, "Revert")
|
||||
# menu.Append(self.saveID, "Save")
|
||||
menu.Bind(wx.EVT_MENU, self.changeLevel)
|
||||
|
||||
self.PopupMenu(menu)
|
||||
|
||||
def changeLevel(self, event):
|
||||
level = self.levelIds.get(event.Id)
|
||||
@@ -705,7 +714,8 @@ class ImplantEditorView(BaseImplantEditorView):
|
||||
context = (("implantEditor",),)
|
||||
# fuck good coding practices, passing a pointer to the character editor here for [reasons] =D
|
||||
# (see implantSets context class for info)
|
||||
menu = ContextMenu.getMenu((self.Parent.Parent,), *context)
|
||||
item = self.Parent.Parent
|
||||
menu = ContextMenu.getMenu(item, (item,), *context)
|
||||
|
||||
if menu:
|
||||
self.PopupMenu(menu)
|
||||
|
||||
@@ -64,8 +64,9 @@ class PageChanging(_PageChanging, NotebookTabChangeEvent, VetoAble):
|
||||
|
||||
|
||||
class PageChanged(_PageChanged, NotebookTabChangeEvent):
|
||||
def __init__(self, old, new):
|
||||
_PageChanged.__init__(self)
|
||||
|
||||
def __init__(self, old, new, *args, **kwargs):
|
||||
_PageChanged.__init__(self, *args, **kwargs)
|
||||
NotebookTabChangeEvent.__init__(self, old, new)
|
||||
|
||||
|
||||
@@ -236,13 +237,16 @@ class ChromeNotebook(wx.Panel):
|
||||
|
||||
self.tabs_container.DisableTab(idx, toggle)
|
||||
|
||||
def SetSelection(self, page):
|
||||
def SetSelection(self, page, focus=True):
|
||||
old_selection = self.GetSelection()
|
||||
if old_selection != page:
|
||||
self._active_page.Hide()
|
||||
self._active_page = self._pages[page]
|
||||
self.tabs_container.SetSelected(page)
|
||||
self.ShowActive()
|
||||
if focus:
|
||||
self._active_page.SetFocus()
|
||||
wx.PostEvent(self, PageChanged(old_selection, page))
|
||||
|
||||
def DeletePage(self, n):
|
||||
page = self._pages[n]
|
||||
|
||||
@@ -17,14 +17,18 @@
|
||||
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
|
||||
# =============================================================================
|
||||
|
||||
from abc import ABCMeta, abstractmethod
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
import wx
|
||||
from logbook import Logger
|
||||
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class ContextMenu(object):
|
||||
class ContextMenu(metaclass=ABCMeta):
|
||||
|
||||
menus = []
|
||||
_ids = [] # [wx.NewId() for x in xrange(200)] # init with decent amount
|
||||
_idxid = -1
|
||||
@@ -34,20 +38,22 @@ class ContextMenu(object):
|
||||
ContextMenu.menus.append(cls)
|
||||
|
||||
@classmethod
|
||||
def hasMenu(cls, selection, *fullContexts):
|
||||
def hasMenu(cls, mainItem, selection, *fullContexts):
|
||||
for i, fullContext in enumerate(fullContexts):
|
||||
srcContext = fullContext[0]
|
||||
for menuHandler in cls.menus:
|
||||
m = menuHandler()
|
||||
if m.display(srcContext, selection):
|
||||
if m._baseDisplay(srcContext, mainItem, selection):
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def getMenu(cls, selection, *fullContexts):
|
||||
def getMenu(cls, mainItem, selection, *fullContexts):
|
||||
"""
|
||||
getMenu returns a menu that is used with wx.PopupMenu.
|
||||
|
||||
mainItem: usually, provides item which was clicked. Useful for single-
|
||||
item actions when user has multiple items selected
|
||||
selection: provides a list of what was selected. If only 1 item was
|
||||
selected, it's is a 1-item list or tuple. Can also be None for
|
||||
contexts without selection, such as statsPane or projected view
|
||||
@@ -67,6 +73,7 @@ class ContextMenu(object):
|
||||
rootMenu = wx.Menu()
|
||||
rootMenu.info = {}
|
||||
rootMenu.selection = (selection,) if not hasattr(selection, "__iter__") else selection
|
||||
rootMenu.mainItem = mainItem
|
||||
empty = True
|
||||
for i, fullContext in enumerate(fullContexts):
|
||||
display_amount = 0
|
||||
@@ -78,14 +85,14 @@ class ContextMenu(object):
|
||||
for menuHandler in cls.menus:
|
||||
# loop through registered menus
|
||||
m = menuHandler()
|
||||
if m.display(srcContext, selection):
|
||||
if m._baseDisplay(srcContext, mainItem, selection):
|
||||
display_amount += 1
|
||||
texts = m.getText(itemContext, selection)
|
||||
texts = m._baseGetText(itemContext, mainItem, selection)
|
||||
|
||||
if isinstance(texts, str):
|
||||
texts = (texts,)
|
||||
|
||||
bitmap = m.getBitmap(srcContext, selection)
|
||||
bitmap = m._baseGetBitmap(srcContext, mainItem, selection)
|
||||
multiple = not isinstance(bitmap, wx.Bitmap)
|
||||
for it, text in enumerate(texts):
|
||||
id = cls.nextID()
|
||||
@@ -93,7 +100,7 @@ class ContextMenu(object):
|
||||
rootItem = wx.MenuItem(rootMenu, id, text, kind=wx.ITEM_NORMAL if m.checked is None else wx.ITEM_CHECK)
|
||||
rootMenu.info[id] = (m, fullContext, it)
|
||||
|
||||
sub = m.getSubMenu(srcContext, selection, rootMenu, it, rootItem)
|
||||
sub = m._baseGetSubMenu(srcContext, mainItem, selection, rootMenu, it, rootItem)
|
||||
|
||||
if sub is None:
|
||||
# if there is no sub menu, bind the handler to the rootItem
|
||||
@@ -136,7 +143,7 @@ class ContextMenu(object):
|
||||
|
||||
debug_end = len(cls._ids)
|
||||
if debug_end - debug_start:
|
||||
pyfalog.debug("{0} new IDs created for this menu", (debug_end - debug_start))
|
||||
pyfalog.debug("{} new IDs created for this menu".format(debug_end - debug_start))
|
||||
|
||||
return rootMenu if empty is False else None
|
||||
|
||||
@@ -147,22 +154,14 @@ class ContextMenu(object):
|
||||
if stuff is not None:
|
||||
menuHandler, context, i = stuff
|
||||
selection = menu.selection
|
||||
mainItem = menu.mainItem
|
||||
if not hasattr(selection, "__iter__"):
|
||||
selection = (selection,)
|
||||
|
||||
menuHandler.activate(context, selection, i)
|
||||
menuHandler._baseActivate(context, mainItem, selection, i)
|
||||
else:
|
||||
event.Skip()
|
||||
|
||||
def display(self, context, selection):
|
||||
raise NotImplementedError()
|
||||
|
||||
def activate(self, fullContext, selection, i):
|
||||
return None
|
||||
|
||||
def getSubMenu(self, context, selection, rootMenu, i, pitem):
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def nextID(cls):
|
||||
"""
|
||||
@@ -179,19 +178,6 @@ class ContextMenu(object):
|
||||
|
||||
return cls._ids[cls._idxid]
|
||||
|
||||
def getText(self, context, selection):
|
||||
"""
|
||||
getText should be implemented in child classes, and should return either
|
||||
a string that will make up a menu item label or a list of strings which
|
||||
will make numerous menu items.
|
||||
|
||||
These menu items will be added to the root menu
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def getBitmap(self, context, selection):
|
||||
return None
|
||||
|
||||
@property
|
||||
def checked(self):
|
||||
'''If menu item is toggleable, this should return bool value'''
|
||||
@@ -202,4 +188,208 @@ class ContextMenu(object):
|
||||
'''If menu item is enabled. Allows an item to display, but not be selected'''
|
||||
return True
|
||||
|
||||
@abstractmethod
|
||||
def _baseDisplay(self, context, mainItem, selection):
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def _baseGetBitmap(self, context, mainItem, selection):
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def _baseGetText(self, context, mainItem, selection):
|
||||
"""
|
||||
getText should be implemented in child classes, and should return either
|
||||
a string that will make up a menu item label or a list of strings which
|
||||
will make numerous menu items.
|
||||
|
||||
These menu items will be added to the root menu
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def _baseGetSubMenu(self, context, mainItem, selection, rootMenu, i, pitem):
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def _baseActivate(self, fullContext, mainItem, selection, i):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class ContextMenuUnconditional(ContextMenu, metaclass=ABCMeta):
|
||||
"""
|
||||
Should be used for context menus which do not depend on which item
|
||||
has been clicked and what current selection is.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def display(self, context):
|
||||
raise NotImplementedError
|
||||
|
||||
def getBitmap(self, context):
|
||||
return
|
||||
|
||||
@abstractmethod
|
||||
def getText(self, context):
|
||||
raise NotImplementedError
|
||||
|
||||
def getSubMenu(self, context, rootMenu, i, pitem):
|
||||
return
|
||||
|
||||
def activate(self, fullContext, i):
|
||||
return
|
||||
|
||||
def _baseDisplay(self, context, mainItem, selection):
|
||||
return self.display(context)
|
||||
|
||||
def _baseGetBitmap(self, context, mainItem, selection):
|
||||
return self.getBitmap(context)
|
||||
|
||||
def _baseGetText(self, context, mainItem, selection):
|
||||
return self.getText(context)
|
||||
|
||||
def _baseGetSubMenu(self, context, mainItem, selection, rootMenu, i, pitem):
|
||||
return self.getSubMenu(context, rootMenu, i, pitem)
|
||||
|
||||
def _baseActivate(self, fullContext, mainItem, selection, i):
|
||||
return self.activate(fullContext, i)
|
||||
|
||||
|
||||
class ContextMenuSingle(ContextMenu, metaclass=ABCMeta):
|
||||
"""
|
||||
Should be used for context menus which depend on
|
||||
which item was clicked, but not on selection.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def display(self, context, mainItem):
|
||||
raise NotImplementedError
|
||||
|
||||
def getBitmap(self, context, mainItem):
|
||||
return
|
||||
|
||||
@abstractmethod
|
||||
def getText(self, context, mainItem):
|
||||
raise NotImplementedError
|
||||
|
||||
def getSubMenu(self, context, mainItem, rootMenu, i, pitem):
|
||||
return
|
||||
|
||||
def activate(self, fullContext, mainItem, i):
|
||||
return
|
||||
|
||||
def _baseDisplay(self, context, mainItem, selection):
|
||||
return self.display(context, mainItem)
|
||||
|
||||
def _baseGetBitmap(self, context, mainItem, selection):
|
||||
return self.getBitmap(context, mainItem)
|
||||
|
||||
def _baseGetText(self, context, mainItem, selection):
|
||||
return self.getText(context, mainItem)
|
||||
|
||||
def _baseGetSubMenu(self, context, mainItem, selection, rootMenu, i, pitem):
|
||||
return self.getSubMenu(context, mainItem, rootMenu, i, pitem)
|
||||
|
||||
def _baseActivate(self, fullContext, mainItem, selection, i):
|
||||
return self.activate(fullContext, mainItem, i)
|
||||
|
||||
|
||||
class ContextMenuSelection(ContextMenu, metaclass=ABCMeta):
|
||||
"""
|
||||
Should be used for context menus which depend on which items are
|
||||
selected. Item clicked is used as fallback if no selection provided.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def display(self, context, selection):
|
||||
raise NotImplementedError
|
||||
|
||||
def getBitmap(self, context, selection):
|
||||
return
|
||||
|
||||
@abstractmethod
|
||||
def getText(self, context, selection):
|
||||
raise NotImplementedError
|
||||
|
||||
def getSubMenu(self, context, selection, rootMenu, i, pitem):
|
||||
return
|
||||
|
||||
def activate(self, fullContext, selection, i):
|
||||
return
|
||||
|
||||
def _baseDisplay(self, context, mainItem, selection):
|
||||
selection = self.__getSelection(selection, mainItem)
|
||||
return self.display(context, selection)
|
||||
|
||||
def _baseGetBitmap(self, context, mainItem, selection):
|
||||
selection = self.__getSelection(selection, mainItem)
|
||||
return self.getBitmap(context, selection)
|
||||
|
||||
def _baseGetText(self, context, mainItem, selection):
|
||||
selection = self.__getSelection(selection, mainItem)
|
||||
return self.getText(context, selection)
|
||||
|
||||
def _baseGetSubMenu(self, context, mainItem, selection, rootMenu, i, pitem):
|
||||
selection = self.__getSelection(selection, mainItem)
|
||||
return self.getSubMenu(context, selection, rootMenu, i, pitem)
|
||||
|
||||
def _baseActivate(self, fullContext, mainItem, selection, i):
|
||||
selection = self.__getSelection(selection, mainItem)
|
||||
return self.activate(fullContext, selection, i)
|
||||
|
||||
def __getSelection(self, selection, mainItem):
|
||||
if mainItem is not None and mainItem not in selection:
|
||||
selection.append(mainItem)
|
||||
return selection
|
||||
|
||||
|
||||
class ContextMenuCombined(ContextMenu, metaclass=ABCMeta):
|
||||
"""
|
||||
Should be used for context menus which depend on both which
|
||||
item has been clicked and which items are selected.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def display(self, context, mainItem, selection):
|
||||
raise NotImplementedError
|
||||
|
||||
def getBitmap(self, context, mainItem, selection):
|
||||
return
|
||||
|
||||
@abstractmethod
|
||||
def getText(self, context, mainItem, selection):
|
||||
raise NotImplementedError
|
||||
|
||||
def getSubMenu(self, context, mainItem, selection, rootMenu, i, pitem):
|
||||
return
|
||||
|
||||
def activate(self, fullContext, mainItem, selection, i):
|
||||
return
|
||||
|
||||
def _baseDisplay(self, context, mainItem, selection):
|
||||
selection = self.__getSelection(selection, mainItem)
|
||||
return self.display(context, mainItem, selection)
|
||||
|
||||
def _baseGetBitmap(self, context, mainItem, selection):
|
||||
selection = self.__getSelection(selection, mainItem)
|
||||
return self.getBitmap(context, mainItem, selection)
|
||||
|
||||
def _baseGetText(self, context, mainItem, selection):
|
||||
selection = self.__getSelection(selection, mainItem)
|
||||
return self.getText(context, mainItem, selection)
|
||||
|
||||
def _baseGetSubMenu(self, context, mainItem, selection, rootMenu, i, pitem):
|
||||
selection = self.__getSelection(selection, mainItem)
|
||||
return self.getSubMenu(context, mainItem, selection, rootMenu, i, pitem)
|
||||
|
||||
def _baseActivate(self, fullContext, mainItem, selection, i):
|
||||
selection = self.__getSelection(selection, mainItem)
|
||||
return self.activate(fullContext, mainItem, selection, i)
|
||||
|
||||
def __getSelection(self, selection, mainItem):
|
||||
if mainItem is not None and mainItem not in selection:
|
||||
selection.append(mainItem)
|
||||
return selection
|
||||
|
||||
|
||||
import gui.builtinContextMenus
|
||||
|
||||
@@ -25,6 +25,7 @@ from gui.cachingImageList import CachingImageList
|
||||
|
||||
|
||||
class Display(wx.ListCtrl):
|
||||
|
||||
DEFAULT_COLS = None
|
||||
|
||||
def __init__(self, parent, size=wx.DefaultSize, style=0):
|
||||
@@ -167,12 +168,16 @@ class Display(wx.ListCtrl):
|
||||
|
||||
return lastFound
|
||||
|
||||
def deselectItems(self):
|
||||
def unselectAll(self):
|
||||
sel = self.GetFirstSelected()
|
||||
while sel != -1:
|
||||
self.SetItemState(sel, 0, wx.LIST_STATE_SELECTED | wx.LIST_STATE_FOCUSED)
|
||||
self.Select(sel, False)
|
||||
sel = self.GetNextSelected(sel)
|
||||
|
||||
def selectAll(self):
|
||||
for row in range(self.GetItemCount()):
|
||||
self.Select(row, True)
|
||||
|
||||
def populate(self, stuff):
|
||||
|
||||
if stuff is not None:
|
||||
@@ -206,12 +211,12 @@ class Display(wx.ListCtrl):
|
||||
colItem = self.GetItem(item, i)
|
||||
oldText = colItem.GetText()
|
||||
oldImageId = colItem.GetImage()
|
||||
oldColour = colItem.GetBackgroundColour();
|
||||
oldColour = colItem.GetBackgroundColour()
|
||||
newText = col.getText(st)
|
||||
if newText is False:
|
||||
col.delayedText(st, self, colItem)
|
||||
newText = "\u21bb"
|
||||
newColour = self.columnBackground(colItem, st);
|
||||
newColour = self.columnBackground(colItem, st)
|
||||
|
||||
newImageId = col.getImageId(st)
|
||||
|
||||
@@ -266,3 +271,29 @@ class Display(wx.ListCtrl):
|
||||
|
||||
def columnBackground(self, colItem, item):
|
||||
return colItem.GetBackgroundColour()
|
||||
|
||||
def getRowByAbs(self, pointAbs):
|
||||
if pointAbs == wx.Point(-1, -1):
|
||||
return -1
|
||||
pointRel = self.screenToClientFixed(pointAbs)
|
||||
row, flags = self.HitTest(pointRel)
|
||||
return row
|
||||
|
||||
def screenToClientFixed(self, ptScreen):
|
||||
"""
|
||||
Wx' ScreenToClient implementation seems to not consider header row height when
|
||||
converting to screen position: https://github.com/wxWidgets/Phoenix/issues/1213
|
||||
Do it ourselves here.
|
||||
"""
|
||||
if ptScreen == wx.Point(-1, -1):
|
||||
return wx.Point(-1, -1)
|
||||
ptClient = self.GetMainWindow().ScreenToClient(ptScreen)
|
||||
return ptClient
|
||||
|
||||
def getSelectedRows(self):
|
||||
rows = []
|
||||
row = self.GetFirstSelected()
|
||||
while row != -1:
|
||||
rows.append(row)
|
||||
row = self.GetNextSelected(row)
|
||||
return rows
|
||||
|
||||
@@ -21,6 +21,7 @@ pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class EveFittings(wx.Frame):
|
||||
|
||||
def __init__(self, parent):
|
||||
wx.Frame.__init__(self, parent, id=wx.ID_ANY, title="Browse EVE Fittings", pos=wx.DefaultPosition,
|
||||
size=wx.Size(550, 450), style=wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL)
|
||||
@@ -69,6 +70,7 @@ class EveFittings(wx.Frame):
|
||||
self.deleteBtn.Bind(wx.EVT_BUTTON, self.deleteFitting)
|
||||
|
||||
self.Bind(wx.EVT_CLOSE, self.OnClose)
|
||||
self.Bind(wx.EVT_CHAR_HOOK, self.kbEvent)
|
||||
|
||||
self.statusbar = wx.StatusBar(self)
|
||||
self.statusbar.SetFieldsCount()
|
||||
@@ -92,12 +94,23 @@ class EveFittings(wx.Frame):
|
||||
|
||||
self.charChoice.SetSelection(0)
|
||||
|
||||
def kbEvent(self, event):
|
||||
keycode = event.GetKeyCode()
|
||||
if keycode == wx.WXK_ESCAPE:
|
||||
self.closeWindow()
|
||||
return
|
||||
event.Skip()
|
||||
|
||||
def OnClose(self, event):
|
||||
self.mainFrame.Unbind(GE.EVT_SSO_LOGOUT)
|
||||
self.mainFrame.Unbind(GE.EVT_SSO_LOGIN)
|
||||
self.closeWindow()
|
||||
# self.cacheTimer.Stop() # must be manually stopped, otherwise crash. See https://github.com/wxWidgets/Phoenix/issues/632
|
||||
event.Skip()
|
||||
|
||||
def closeWindow(self):
|
||||
self.mainFrame.Unbind(GE.EVT_SSO_LOGOUT)
|
||||
self.mainFrame.Unbind(GE.EVT_SSO_LOGIN)
|
||||
self.Destroy()
|
||||
|
||||
def getActiveCharacter(self):
|
||||
selection = self.charChoice.GetCurrentSelection()
|
||||
return self.charChoice.GetClientData(selection) if selection is not None else None
|
||||
@@ -186,6 +199,7 @@ class ESIExceptionHandler(object):
|
||||
|
||||
|
||||
class ExportToEve(wx.Frame):
|
||||
|
||||
def __init__(self, parent):
|
||||
wx.Frame.__init__(self, parent, id=wx.ID_ANY, title="Export fit to EVE", pos=wx.DefaultPosition,
|
||||
size=(wx.Size(350, 100)), style=wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL)
|
||||
@@ -213,6 +227,7 @@ class ExportToEve(wx.Frame):
|
||||
self.statusbar.SetStatusWidths([100, -1])
|
||||
|
||||
self.Bind(wx.EVT_CLOSE, self.OnClose)
|
||||
self.Bind(wx.EVT_CHAR_HOOK, self.kbEvent)
|
||||
|
||||
self.SetSizer(mainSizer)
|
||||
self.SetStatusBar(self.statusbar)
|
||||
@@ -233,11 +248,21 @@ class ExportToEve(wx.Frame):
|
||||
|
||||
self.charChoice.SetSelection(0)
|
||||
|
||||
def kbEvent(self, event):
|
||||
keycode = event.GetKeyCode()
|
||||
if keycode == wx.WXK_ESCAPE:
|
||||
self.closeWindow()
|
||||
return
|
||||
event.Skip()
|
||||
|
||||
def OnClose(self, event):
|
||||
self.closeWindow()
|
||||
event.Skip()
|
||||
|
||||
def closeWindow(self):
|
||||
self.mainFrame.Unbind(GE.EVT_SSO_LOGOUT)
|
||||
self.mainFrame.Unbind(GE.EVT_SSO_LOGIN)
|
||||
|
||||
event.Skip()
|
||||
self.Destroy()
|
||||
|
||||
def getActiveCharacter(self):
|
||||
selection = self.charChoice.GetCurrentSelection()
|
||||
@@ -283,6 +308,7 @@ class ExportToEve(wx.Frame):
|
||||
|
||||
|
||||
class SsoCharacterMgmt(wx.Dialog):
|
||||
|
||||
def __init__(self, parent):
|
||||
wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title="SSO Character Management", pos=wx.DefaultPosition,
|
||||
size=wx.Size(550, 250), style=wx.DEFAULT_DIALOG_STYLE)
|
||||
@@ -312,6 +338,7 @@ class SsoCharacterMgmt(wx.Dialog):
|
||||
self.deleteBtn.Bind(wx.EVT_BUTTON, self.delChar)
|
||||
|
||||
self.mainFrame.Bind(GE.EVT_SSO_LOGIN, self.ssoLogin)
|
||||
self.Bind(wx.EVT_CHAR_HOOK, self.kbEvent)
|
||||
|
||||
self.SetSizer(mainSizer)
|
||||
self.Layout()
|
||||
@@ -324,6 +351,16 @@ class SsoCharacterMgmt(wx.Dialog):
|
||||
self.popCharList()
|
||||
event.Skip()
|
||||
|
||||
def kbEvent(self, event):
|
||||
keycode = event.GetKeyCode()
|
||||
if keycode == wx.WXK_ESCAPE:
|
||||
self.closeWindow()
|
||||
return
|
||||
event.Skip()
|
||||
|
||||
def closeWindow(self):
|
||||
self.Destroy()
|
||||
|
||||
def popCharList(self):
|
||||
sEsi = Esi.getInstance()
|
||||
chars = sEsi.getSsoCharacters()
|
||||
|
||||
@@ -1,69 +1,69 @@
|
||||
from .gui.booster.add import GuiAddBoosterCommand
|
||||
from .gui.booster.changeMeta import GuiChangeBoosterMetaCommand
|
||||
from .gui.booster.remove import GuiRemoveBoosterCommand
|
||||
from .gui.booster.remove import GuiRemoveBoostersCommand
|
||||
from .gui.booster.sideEffectToggleState import GuiToggleBoosterSideEffectStateCommand
|
||||
from .gui.booster.toggleState import GuiToggleBoosterStateCommand
|
||||
from .gui.booster.toggleStates import GuiToggleBoosterStatesCommand
|
||||
from .gui.cargo.add import GuiAddCargoCommand
|
||||
from .gui.cargo.changeAmount import GuiChangeCargoAmountCommand
|
||||
from .gui.cargo.changeMeta import GuiChangeCargoMetaCommand
|
||||
from .gui.cargo.remove import GuiRemoveCargoCommand
|
||||
from .gui.cargo.changeMetas import GuiChangeCargoMetasCommand
|
||||
from .gui.cargo.remove import GuiRemoveCargosCommand
|
||||
from .gui.commandFit.add import GuiAddCommandFitCommand
|
||||
from .gui.commandFit.remove import GuiRemoveCommandFitCommand
|
||||
from .gui.commandFit.toggleState import GuiToggleCommandFitStateCommand
|
||||
from .gui.commandFit.remove import GuiRemoveCommandFitsCommand
|
||||
from .gui.commandFit.toggleStates import GuiToggleCommandFitStatesCommand
|
||||
from .gui.fitRename import GuiRenameFitCommand
|
||||
from .gui.fitRestrictionToggle import GuiToggleFittingRestrictionsCommand
|
||||
from .gui.fitSystemSecurity import GuiChangeFitSystemSecurityCommand
|
||||
from .gui.implant.add import GuiAddImplantCommand
|
||||
from .gui.implant.changeLocation import GuiChangeImplantLocationCommand
|
||||
from .gui.implant.changeMeta import GuiChangeImplantMetaCommand
|
||||
from .gui.implant.remove import GuiRemoveImplantCommand
|
||||
from .gui.implant.remove import GuiRemoveImplantsCommand
|
||||
from .gui.implant.setAdd import GuiAddImplantSetCommand
|
||||
from .gui.implant.toggleState import GuiToggleImplantStateCommand
|
||||
from .gui.implant.toggleStates import GuiToggleImplantStatesCommand
|
||||
from .gui.itemsRebase import GuiRebaseItemsCommand
|
||||
from .gui.localDrone.add import GuiAddLocalDroneCommand
|
||||
from .gui.localDrone.changeAmount import GuiChangeLocalDroneAmountCommand
|
||||
from .gui.localDrone.changeMeta import GuiChangeLocalDroneMetaCommand
|
||||
from .gui.localDrone.remove import GuiRemoveLocalDroneCommand
|
||||
from .gui.localDrone.changeMetas import GuiChangeLocalDroneMetasCommand
|
||||
from .gui.localDrone.clone import GuiCloneLocalDroneCommand
|
||||
from .gui.localDrone.remove import GuiRemoveLocalDronesCommand
|
||||
from .gui.localDrone.stackSplit import GuiSplitLocalDroneStackCommand
|
||||
from .gui.localDrone.stacksMerge import GuiMergeLocalDroneStacksCommand
|
||||
from .gui.localDrone.toggleState import GuiToggleLocalDroneStateCommand
|
||||
from .gui.localDrone.toggleStates import GuiToggleLocalDroneStatesCommand
|
||||
from .gui.localFighter.abilityToggleState import GuiToggleLocalFighterAbilityStateCommand
|
||||
from .gui.localFighter.add import GuiAddLocalFighterCommand
|
||||
from .gui.localFighter.changeAmount import GuiChangeLocalFighterAmountCommand
|
||||
from .gui.localFighter.changeMeta import GuiChangeLocalFighterMetaCommand
|
||||
from .gui.localFighter.remove import GuiRemoveLocalFighterCommand
|
||||
from .gui.localFighter.toggleState import GuiToggleLocalFighterStateCommand
|
||||
from .gui.localFighter.changeMetas import GuiChangeLocalFighterMetasCommand
|
||||
from .gui.localFighter.remove import GuiRemoveLocalFightersCommand
|
||||
from .gui.localFighter.toggleStates import GuiToggleLocalFighterStatesCommand
|
||||
from .gui.localModule.add import GuiAddLocalModuleCommand
|
||||
from .gui.localModule.changeCharges import GuiChangeLocalModuleChargesCommand
|
||||
from .gui.localModule.changeMetas import GuiChangeLocalModuleMetasCommand
|
||||
from .gui.localModule.changeMutation import GuiChangeLocalModuleMutationCommand
|
||||
from .gui.localModule.changeSpool import GuiChangeLocalModuleSpoolCommand
|
||||
from .gui.localModule.changeStates import GuiChangeLocalModuleStatesCommand
|
||||
from .gui.localModule.clone import GuiCloneLocalModuleCommand
|
||||
from .gui.localModule.fill import GuiFillWithLocalModulesCommand
|
||||
from .gui.localModule.fillAdd import GuiFillWithNewLocalModulesCommand
|
||||
from .gui.localModule.fillClone import GuiFillWithClonedLocalModulesCommand
|
||||
from .gui.localModule.mutatedConvert import GuiConvertMutatedLocalModuleCommand
|
||||
from .gui.localModule.mutatedImport import GuiImportLocalMutatedModuleCommand
|
||||
from .gui.localModule.mutatedRevert import GuiRevertMutatedLocalModuleCommand
|
||||
from .gui.localModule.remove import GuiRemoveLocalModuleCommand
|
||||
from .gui.localModule.replace import GuiReplaceLocalModuleCommand
|
||||
from .gui.localModule.swap import GuiSwapLocalModulesCommand
|
||||
from .gui.localModuleCargo.cargoToLocalModule import GuiCargoToLocalModuleCommand
|
||||
from .gui.localModuleCargo.localModuleToCargo import GuiLocalModuleToCargoCommand
|
||||
from .gui.projectedChangeStates import GuiChangeProjectedItemStatesCommand
|
||||
from .gui.projectedDrone.add import GuiAddProjectedDroneCommand
|
||||
from .gui.projectedDrone.changeAmount import GuiChangeProjectedDroneAmountCommand
|
||||
from .gui.projectedDrone.changeMeta import GuiChangeProjectedDroneMetaCommand
|
||||
from .gui.projectedDrone.remove import GuiRemoveProjectedDroneCommand
|
||||
from .gui.projectedDrone.toggleState import GuiToggleProjectedDroneStateCommand
|
||||
from .gui.projectedDrone.changeMetas import GuiChangeProjectedDroneMetasCommand
|
||||
from .gui.projectedFighter.abilityToggleState import GuiToggleProjectedFighterAbilityStateCommand
|
||||
from .gui.projectedFighter.add import GuiAddProjectedFighterCommand
|
||||
from .gui.projectedFighter.changeAmount import GuiChangeProjectedFighterAmountCommand
|
||||
from .gui.projectedFighter.changeMeta import GuiChangeProjectedFighterMetaCommand
|
||||
from .gui.projectedFighter.remove import GuiRemoveProjectedFighterCommand
|
||||
from .gui.projectedFighter.toggleState import GuiToggleProjectedFighterStateCommand
|
||||
from .gui.projectedFighter.changeMetas import GuiChangeProjectedFighterMetasCommand
|
||||
from .gui.projectedFit.add import GuiAddProjectedFitCommand
|
||||
from .gui.projectedFit.changeAmount import GuiChangeProjectedFitAmountCommand
|
||||
from .gui.projectedFit.remove import GuiRemoveProjectedFitCommand
|
||||
from .gui.projectedFit.toggleState import GuiToggleProjectedFitStateCommand
|
||||
from .gui.projectedModule.add import GuiAddProjectedModuleCommand
|
||||
from .gui.projectedModule.changeCharges import GuiChangeProjectedModuleChargesCommand
|
||||
from .gui.projectedModule.changeMeta import GuiChangeProjectedModuleMetaCommand
|
||||
from .gui.projectedModule.changeMetas import GuiChangeProjectedModuleMetasCommand
|
||||
from .gui.projectedModule.changeSpool import GuiChangeProjectedModuleSpoolCommand
|
||||
from .gui.projectedModule.changeState import GuiChangeProjectedModuleStateCommand
|
||||
from .gui.projectedModule.remove import GuiRemoveProjectedModuleCommand
|
||||
from .gui.projectedRemove import GuiRemoveProjectedItemsCommand
|
||||
from .gui.shipModeChange import GuiChangeShipModeCommand
|
||||
|
||||
@@ -11,11 +11,12 @@ pyfalog = Logger(__name__)
|
||||
|
||||
class CalcAddBoosterCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, boosterInfo, position=None):
|
||||
def __init__(self, fitID, boosterInfo, position=None, commit=True):
|
||||
wx.Command.__init__(self, True, 'Add Booster')
|
||||
self.fitID = fitID
|
||||
self.newBoosterInfo = boosterInfo
|
||||
self.newPosition = position
|
||||
self.commit = commit
|
||||
self.oldBoosterInfo = None
|
||||
self.oldPosition = None
|
||||
|
||||
@@ -38,7 +39,11 @@ class CalcAddBoosterCommand(wx.Command):
|
||||
fit.boosters.insert(self.newPosition, newBooster)
|
||||
except HandledListActionError:
|
||||
pyfalog.warning('Failed to insert to list')
|
||||
cmd = CalcAddBoosterCommand(fitID=self.fitID, boosterInfo=self.oldBoosterInfo, position=self.oldPosition)
|
||||
cmd = CalcAddBoosterCommand(
|
||||
fitID=self.fitID,
|
||||
boosterInfo=self.oldBoosterInfo,
|
||||
position=self.oldPosition,
|
||||
commit=self.commit)
|
||||
cmd.Do()
|
||||
return False
|
||||
else:
|
||||
@@ -46,19 +51,24 @@ class CalcAddBoosterCommand(wx.Command):
|
||||
fit.boosters.append(newBooster)
|
||||
except HandledListActionError:
|
||||
pyfalog.warning('Failed to append to list')
|
||||
cmd = CalcAddBoosterCommand(fitID=self.fitID, boosterInfo=self.oldBoosterInfo, position=self.oldPosition)
|
||||
cmd = CalcAddBoosterCommand(
|
||||
fitID=self.fitID,
|
||||
boosterInfo=self.oldBoosterInfo,
|
||||
position=self.oldPosition,
|
||||
commit=self.commit)
|
||||
cmd.Do()
|
||||
return False
|
||||
self.newPosition = fit.boosters.index(newBooster)
|
||||
|
||||
eos.db.commit()
|
||||
if self.commit:
|
||||
eos.db.commit()
|
||||
return True
|
||||
|
||||
def Undo(self):
|
||||
pyfalog.debug('Undo addition of booster {} to fit {}'.format(self.newBoosterInfo, self.fitID))
|
||||
if self.oldBoosterInfo is not None and self.oldPosition is not None:
|
||||
cmd = CalcAddBoosterCommand(fitID=self.fitID, boosterInfo=self.oldBoosterInfo, position=self.oldPosition)
|
||||
cmd = CalcAddBoosterCommand(fitID=self.fitID, boosterInfo=self.oldBoosterInfo, position=self.oldPosition, commit=self.commit)
|
||||
return cmd.Do()
|
||||
from .remove import CalcRemoveBoosterCommand
|
||||
cmd = CalcRemoveBoosterCommand(fitID=self.fitID, position=self.newPosition)
|
||||
cmd = CalcRemoveBoosterCommand(fitID=self.fitID, position=self.newPosition, commit=self.commit)
|
||||
return cmd.Do()
|
||||
|
||||
@@ -11,10 +11,11 @@ pyfalog = Logger(__name__)
|
||||
|
||||
class CalcRemoveBoosterCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, position):
|
||||
def __init__(self, fitID, position, commit=True):
|
||||
wx.Command.__init__(self, True, 'Remove Booster')
|
||||
self.fitID = fitID
|
||||
self.position = position
|
||||
self.commit = commit
|
||||
self.savedBoosterInfo = None
|
||||
|
||||
def Do(self):
|
||||
@@ -23,11 +24,16 @@ class CalcRemoveBoosterCommand(wx.Command):
|
||||
booster = fit.boosters[self.position]
|
||||
self.savedBoosterInfo = BoosterInfo.fromBooster(booster)
|
||||
fit.boosters.remove(booster)
|
||||
eos.db.commit()
|
||||
if self.commit:
|
||||
eos.db.commit()
|
||||
return True
|
||||
|
||||
def Undo(self):
|
||||
pyfalog.debug('Undoing removal of booster {} on fit {}'.format(self.savedBoosterInfo, self.fitID))
|
||||
from .add import CalcAddBoosterCommand
|
||||
cmd = CalcAddBoosterCommand(fitID=self.fitID, boosterInfo=self.savedBoosterInfo, position=self.position)
|
||||
cmd = CalcAddBoosterCommand(
|
||||
fitID=self.fitID,
|
||||
boosterInfo=self.savedBoosterInfo,
|
||||
position=self.position,
|
||||
commit=self.commit)
|
||||
return cmd.Do()
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
import wx
|
||||
from logbook import Logger
|
||||
|
||||
import eos.db
|
||||
from service.fit import Fit
|
||||
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class CalcToggleBoosterStateCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, position, forceState=None):
|
||||
wx.Command.__init__(self, True, 'Toggle Booster State')
|
||||
self.fitID = fitID
|
||||
self.position = position
|
||||
self.forceState = forceState
|
||||
self.savedState = None
|
||||
|
||||
def Do(self):
|
||||
pyfalog.debug('Doing toggling of booster state at position {} for fit {}'.format(self.position, self.fitID))
|
||||
fit = Fit.getInstance().getFit(self.fitID)
|
||||
booster = fit.boosters[self.position]
|
||||
self.savedState = booster.active
|
||||
booster.active = not booster.active if self.forceState is None else self.forceState
|
||||
eos.db.commit()
|
||||
return True
|
||||
|
||||
def Undo(self):
|
||||
pyfalog.debug('Undoing toggling of booster state at position {} for fit {}'.format(self.position, self.fitID))
|
||||
cmd = CalcToggleBoosterStateCommand(fitID=self.fitID, position=self.position, forceState=self.savedState)
|
||||
return cmd.Do()
|
||||
54
gui/fitCommands/calc/booster/toggleStates.py
Normal file
54
gui/fitCommands/calc/booster/toggleStates.py
Normal file
@@ -0,0 +1,54 @@
|
||||
import wx
|
||||
from logbook import Logger
|
||||
|
||||
import eos.db
|
||||
from service.fit import Fit
|
||||
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class CalcToggleBoosterStatesCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, mainPosition, positions, forceStates=None):
|
||||
wx.Command.__init__(self, True, 'Toggle Booster States')
|
||||
self.fitID = fitID
|
||||
self.mainPosition = mainPosition
|
||||
self.positions = positions
|
||||
self.forceStates = forceStates
|
||||
self.savedStates = None
|
||||
|
||||
def Do(self):
|
||||
pyfalog.debug('Doing toggling of booster state at position {}/{} for fit {}'.format(self.mainPosition, self.positions, self.fitID))
|
||||
fit = Fit.getInstance().getFit(self.fitID)
|
||||
|
||||
positions = self.positions[:]
|
||||
if self.mainPosition not in positions:
|
||||
positions.append(self.mainPosition)
|
||||
self.savedStates = {p: fit.boosters[p].active for p in positions}
|
||||
|
||||
if self.forceStates is not None:
|
||||
for position, state in self.forceStates.items():
|
||||
booster = fit.boosters[position]
|
||||
booster.active = state
|
||||
elif fit.boosters[self.mainPosition].active:
|
||||
for position in positions:
|
||||
booster = fit.boosters[position]
|
||||
if booster.active:
|
||||
booster.active = False
|
||||
else:
|
||||
for position in positions:
|
||||
booster = fit.boosters[position]
|
||||
if not booster.active:
|
||||
booster.active = True
|
||||
eos.db.commit()
|
||||
return True
|
||||
|
||||
def Undo(self):
|
||||
pyfalog.debug('Undoing toggling of booster state at position {}/{} for fit {}'.format(self.mainPosition, self.positions, self.fitID))
|
||||
cmd = CalcToggleBoosterStatesCommand(
|
||||
fitID=self.fitID,
|
||||
mainPosition=self.mainPosition,
|
||||
positions=self.positions,
|
||||
forceStates=self.savedStates)
|
||||
return cmd.Do()
|
||||
@@ -10,11 +10,12 @@ pyfalog = Logger(__name__)
|
||||
|
||||
class CalcAddCommandCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, commandFitID, state=None):
|
||||
def __init__(self, fitID, commandFitID, state=None, commit=True):
|
||||
wx.Command.__init__(self, True, 'Add Command Fit')
|
||||
self.fitID = fitID
|
||||
self.commandFitID = commandFitID
|
||||
self.state = state
|
||||
self.commit = commit
|
||||
|
||||
def Do(self):
|
||||
pyfalog.debug('Doing addition of command fit {} for fit {}'.format(self.commandFitID, self.fitID))
|
||||
@@ -30,7 +31,9 @@ class CalcAddCommandCommand(wx.Command):
|
||||
if commandFit in fit.commandFits:
|
||||
pyfalog.debug('Command fit had been applied already')
|
||||
return False
|
||||
|
||||
if commandFit.ID in fit.commandFitDict:
|
||||
pyfalog.debug('Commanding fit is in command dict already')
|
||||
return False
|
||||
fit.commandFitDict[commandFit.ID] = commandFit
|
||||
# This bit is required, see issue #83
|
||||
eos.db.saveddata_session.flush()
|
||||
@@ -44,7 +47,8 @@ class CalcAddCommandCommand(wx.Command):
|
||||
return False
|
||||
fitCommandInfo.active = self.state
|
||||
|
||||
eos.db.commit()
|
||||
if self.commit:
|
||||
eos.db.commit()
|
||||
return True
|
||||
|
||||
def Undo(self):
|
||||
@@ -54,6 +58,6 @@ class CalcAddCommandCommand(wx.Command):
|
||||
commandFit = Fit.getInstance().getFit(self.commandFitID)
|
||||
if commandFit is None:
|
||||
return True
|
||||
from .remove import CalcRemoveCommandCommand
|
||||
cmd = CalcRemoveCommandCommand(fitID=self.fitID, commandFitID=self.commandFitID)
|
||||
from .remove import CalcRemoveCommandFitCommand
|
||||
cmd = CalcRemoveCommandFitCommand(fitID=self.fitID, commandFitID=self.commandFitID, commit=self.commit)
|
||||
return cmd.Do()
|
||||
|
||||
@@ -8,12 +8,13 @@ from service.fit import Fit
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class CalcRemoveCommandCommand(wx.Command):
|
||||
class CalcRemoveCommandFitCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, commandFitID):
|
||||
def __init__(self, fitID, commandFitID, commit=True):
|
||||
wx.Command.__init__(self, True, 'Remove Command Fit')
|
||||
self.fitID = fitID
|
||||
self.commandFitID = commandFitID
|
||||
self.commit = commit
|
||||
self.savedState = None
|
||||
|
||||
def Do(self):
|
||||
@@ -30,14 +31,21 @@ class CalcRemoveCommandCommand(wx.Command):
|
||||
if commandInfo is None:
|
||||
pyfalog.warning('Fit command info is not available')
|
||||
return False
|
||||
|
||||
self.savedState = commandInfo.active
|
||||
if commandFit.ID not in fit.commandFitDict:
|
||||
pyfalog.warning('Unable to find commanding fit in command dict')
|
||||
return False
|
||||
del fit.commandFitDict[commandFit.ID]
|
||||
eos.db.commit()
|
||||
if self.commit:
|
||||
eos.db.commit()
|
||||
return True
|
||||
|
||||
def Undo(self):
|
||||
pyfalog.debug('Undoing removal of command fit {} for fit {}'.format(self.commandFitID, self.fitID))
|
||||
from .add import CalcAddCommandCommand
|
||||
cmd = CalcAddCommandCommand(fitID=self.fitID, commandFitID=self.commandFitID, state=self.savedState)
|
||||
cmd = CalcAddCommandCommand(
|
||||
fitID=self.fitID,
|
||||
commandFitID=self.commandFitID,
|
||||
state=self.savedState,
|
||||
commit=self.commit)
|
||||
return cmd.Do()
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
import wx
|
||||
from logbook import Logger
|
||||
|
||||
import eos.db
|
||||
from service.fit import Fit
|
||||
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class CalcToggleCommandFitStateCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, commandFitID, forceState=None):
|
||||
wx.Command.__init__(self, True, 'Toggle Command Fit State')
|
||||
self.fitID = fitID
|
||||
self.commandFitID = commandFitID
|
||||
self.forceState = forceState
|
||||
self.savedState = None
|
||||
|
||||
def Do(self):
|
||||
pyfalog.debug('Doing toggling of command fit {} state for fit {}'.format(self.commandFitID, self.fitID))
|
||||
commandFit = Fit.getInstance().getFit(self.commandFitID)
|
||||
# Command fit could have been deleted if we are redoing
|
||||
if commandFit is None:
|
||||
pyfalog.debug('Command fit is not available')
|
||||
return False
|
||||
commandInfo = commandFit.getCommandInfo(self.fitID)
|
||||
if commandInfo is None:
|
||||
pyfalog.warning('Fit command info is not available')
|
||||
return False
|
||||
self.savedState = commandInfo.active
|
||||
commandInfo.active = not commandInfo.active if self.forceState is None else self.forceState
|
||||
eos.db.commit()
|
||||
return True
|
||||
|
||||
def Undo(self):
|
||||
pyfalog.debug('Undoing toggling of command fit {} state for fit {}'.format(self.commandFitID, self.fitID))
|
||||
cmd = CalcToggleCommandFitStateCommand(fitID=self.fitID, commandFitID=self.commandFitID, forceState=self.savedState)
|
||||
return cmd.Do()
|
||||
73
gui/fitCommands/calc/commandFit/toggleStates.py
Normal file
73
gui/fitCommands/calc/commandFit/toggleStates.py
Normal file
@@ -0,0 +1,73 @@
|
||||
import wx
|
||||
from logbook import Logger
|
||||
|
||||
import eos.db
|
||||
from service.fit import Fit
|
||||
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class CalcToggleCommandFitStatesCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, mainCommandFitID, commandFitIDs, forceStates=None):
|
||||
wx.Command.__init__(self, True, 'Toggle Command Fit States')
|
||||
self.fitID = fitID
|
||||
self.mainCommandFitID = mainCommandFitID
|
||||
self.commandFitIDs = commandFitIDs
|
||||
self.forceStates = forceStates
|
||||
self.savedStates = None
|
||||
|
||||
def Do(self):
|
||||
pyfalog.debug('Doing toggling of command fit {}/{} state for fit {}'.format(self.mainCommandFitID, self.commandFitIDs, self.fitID))
|
||||
sFit = Fit.getInstance()
|
||||
|
||||
commandFitIDs = self.commandFitIDs[:]
|
||||
if self.mainCommandFitID not in commandFitIDs:
|
||||
commandFitIDs.append(self.mainCommandFitID)
|
||||
|
||||
commandInfos = {}
|
||||
for commandFitID in commandFitIDs:
|
||||
commandFit = sFit.getFit(commandFitID)
|
||||
# Command fit could have been deleted if we are redoing
|
||||
if commandFit is None:
|
||||
pyfalog.debug('Command fit is not available')
|
||||
continue
|
||||
commandInfo = commandFit.getCommandInfo(self.fitID)
|
||||
if commandInfo is None:
|
||||
pyfalog.warning('Fit command info is not available')
|
||||
continue
|
||||
commandInfos[commandFitID] = commandInfo
|
||||
|
||||
if len(commandInfos) == 0:
|
||||
return False
|
||||
|
||||
self.savedStates = {cfid: ci.active for cfid, ci in commandInfos.items()}
|
||||
|
||||
mainCommandInfo = commandInfos.get(self.mainCommandFitID)
|
||||
if self.forceStates is not None:
|
||||
for commandFitID, state in self.forceStates.items():
|
||||
commandInfo = commandInfos.get(commandFitID)
|
||||
if commandInfo is None:
|
||||
continue
|
||||
commandInfo.active = state
|
||||
elif mainCommandInfo is not None and mainCommandInfo.active:
|
||||
for commandInfo in commandInfos.values():
|
||||
commandInfo.active = False
|
||||
elif mainCommandInfo is not None and not mainCommandInfo.active:
|
||||
for commandInfo in commandInfos.values():
|
||||
commandInfo.active = True
|
||||
# Bail if we cannot calculate which state to take
|
||||
else:
|
||||
return False
|
||||
eos.db.commit()
|
||||
return True
|
||||
|
||||
def Undo(self):
|
||||
pyfalog.debug('Undoing toggling of command fit {}/{} state for fit {}'.format(self.mainCommandFitID, self.commandFitIDs, self.fitID))
|
||||
cmd = CalcToggleCommandFitStatesCommand(
|
||||
fitID=self.fitID,
|
||||
mainCommandFitID=self.mainCommandFitID,
|
||||
commandFitIDs=self.commandFitIDs,
|
||||
forceStates=self.savedStates)
|
||||
return cmd.Do()
|
||||
@@ -4,7 +4,7 @@ from logbook import Logger
|
||||
|
||||
import eos.db
|
||||
from eos.exception import HandledListActionError
|
||||
from gui.fitCommands.helpers import DroneInfo
|
||||
from gui.fitCommands.helpers import DroneInfo, droneStackLimit
|
||||
from service.fit import Fit
|
||||
from service.market import Market
|
||||
|
||||
@@ -14,11 +14,12 @@ pyfalog = Logger(__name__)
|
||||
|
||||
class CalcAddLocalDroneCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, droneInfo, forceNewStack=False, commit=True):
|
||||
wx.Command.__init__(self, True, 'Add Drone')
|
||||
def __init__(self, fitID, droneInfo, forceNewStack=False, ignoreRestrictions=False, commit=True):
|
||||
wx.Command.__init__(self, True, 'Add Local Drone')
|
||||
self.fitID = fitID
|
||||
self.droneInfo = droneInfo
|
||||
self.forceNewStack = forceNewStack
|
||||
self.ignoreRestrictions = ignoreRestrictions
|
||||
self.commit = commit
|
||||
self.savedDroneInfo = None
|
||||
self.savedPosition = None
|
||||
@@ -30,10 +31,11 @@ class CalcAddLocalDroneCommand(wx.Command):
|
||||
# If we're not adding any active drones, check if there's an inactive stack
|
||||
# with enough space for new drones and use it
|
||||
if not self.forceNewStack and self.droneInfo.amountActive == 0:
|
||||
maxStack = droneStackLimit(fit, item)
|
||||
for drone in fit.drones.find(item):
|
||||
if (
|
||||
drone is not None and drone.amountActive == 0 and
|
||||
drone.amount + self.droneInfo.amount) <= max(5, fit.extraAttributes["maxActiveDrones"]
|
||||
drone.amount + self.droneInfo.amount <= maxStack
|
||||
):
|
||||
self.savedDroneInfo = DroneInfo.fromDrone(drone)
|
||||
self.savedPosition = fit.drones.index(drone)
|
||||
@@ -45,7 +47,7 @@ class CalcAddLocalDroneCommand(wx.Command):
|
||||
drone = self.droneInfo.toDrone()
|
||||
if drone is None:
|
||||
return False
|
||||
if not drone.fits(fit):
|
||||
if not self.ignoreRestrictions and not drone.fits(fit):
|
||||
pyfalog.warning('Drone does not fit')
|
||||
return False
|
||||
try:
|
||||
@@ -67,6 +69,8 @@ class CalcAddLocalDroneCommand(wx.Command):
|
||||
drone = fit.drones[self.savedPosition]
|
||||
drone.amount = self.savedDroneInfo.amount
|
||||
drone.amountActive = self.savedDroneInfo.amountActive
|
||||
if self.commit:
|
||||
eos.db.commit()
|
||||
return True
|
||||
from .localRemove import CalcRemoveLocalDroneCommand
|
||||
cmd = CalcRemoveLocalDroneCommand(
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import math
|
||||
|
||||
import wx
|
||||
from logbook import Logger
|
||||
|
||||
@@ -14,7 +12,7 @@ pyfalog = Logger(__name__)
|
||||
class CalcChangeLocalDroneAmountCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, position, amount, commit=True):
|
||||
wx.Command.__init__(self, True, 'Change Drone Amount')
|
||||
wx.Command.__init__(self, True, 'Change Local Drone Amount')
|
||||
self.fitID = fitID
|
||||
self.position = position
|
||||
self.amount = amount
|
||||
|
||||
@@ -13,7 +13,7 @@ pyfalog = Logger(__name__)
|
||||
class CalcRemoveLocalDroneCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, position, amount, commit=True):
|
||||
wx.Command.__init__(self, True, 'Remove Drone')
|
||||
wx.Command.__init__(self, True, 'Remove Local Drone')
|
||||
self.fitID = fitID
|
||||
self.position = position
|
||||
self.amountToRemove = amount
|
||||
@@ -48,8 +48,6 @@ class CalcRemoveLocalDroneCommand(wx.Command):
|
||||
drone = self.savedDroneInfo.toDrone()
|
||||
if drone is None:
|
||||
return False
|
||||
if not drone.fits(fit):
|
||||
return False
|
||||
try:
|
||||
fit.drones.insert(self.position, drone)
|
||||
except HandledListActionError:
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
import wx
|
||||
from logbook import Logger
|
||||
|
||||
import eos.db
|
||||
from service.fit import Fit
|
||||
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class CalcToggleLocalDroneStateCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, position, forceAmountActive=None):
|
||||
wx.Command.__init__(self, True, 'Toggle Drone State')
|
||||
self.fitID = fitID
|
||||
self.position = position
|
||||
self.forceAmountActive = forceAmountActive
|
||||
self.savedAmountActive = None
|
||||
|
||||
def Do(self):
|
||||
pyfalog.debug('Doing toggling of local drone state at position {} for fit {}'.format(self.position, self.fitID))
|
||||
fit = Fit.getInstance().getFit(self.fitID)
|
||||
drone = fit.drones[self.position]
|
||||
self.savedAmountActive = drone.amountActive
|
||||
if self.forceAmountActive is not None:
|
||||
drone.amountActive = self.forceAmountActive
|
||||
elif drone.amountActive > 0:
|
||||
drone.amountActive = 0
|
||||
else:
|
||||
drone.amountActive = drone.amount
|
||||
eos.db.commit()
|
||||
return True
|
||||
|
||||
def Undo(self):
|
||||
pyfalog.debug('Undoing toggling of local drone state at position {} for fit {}'.format(self.position, self.fitID))
|
||||
cmd = CalcToggleLocalDroneStateCommand(fitID=self.fitID, position=self.position, forceAmountActive=self.savedAmountActive)
|
||||
return cmd.Do()
|
||||
55
gui/fitCommands/calc/drone/localToggleStates.py
Normal file
55
gui/fitCommands/calc/drone/localToggleStates.py
Normal file
@@ -0,0 +1,55 @@
|
||||
import wx
|
||||
from logbook import Logger
|
||||
|
||||
import eos.db
|
||||
from service.fit import Fit
|
||||
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class CalcToggleLocalDroneStatesCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, mainPosition, positions, forceActiveAmounts=None):
|
||||
wx.Command.__init__(self, True, 'Toggle Local Drone States')
|
||||
self.fitID = fitID
|
||||
self.mainPosition = mainPosition
|
||||
self.positions = positions
|
||||
self.forceActiveAmounts = forceActiveAmounts
|
||||
self.savedActiveAmounts = None
|
||||
|
||||
def Do(self):
|
||||
pyfalog.debug('Doing toggling of local drone state at position {}/{} for fit {}'.format(self.mainPosition, self.positions, self.fitID))
|
||||
fit = Fit.getInstance().getFit(self.fitID)
|
||||
|
||||
positions = self.positions[:]
|
||||
if self.mainPosition not in positions:
|
||||
positions.append(self.mainPosition)
|
||||
self.savedActiveAmounts = {p: fit.drones[p].amountActive for p in positions}
|
||||
|
||||
if self.forceActiveAmounts is not None:
|
||||
for position, amountActive in self.forceActiveAmounts.items():
|
||||
drone = fit.drones[position]
|
||||
drone.amountActive = amountActive
|
||||
elif fit.drones[self.mainPosition].amountActive > 0:
|
||||
for position in positions:
|
||||
drone = fit.drones[position]
|
||||
if drone.amountActive > 0:
|
||||
drone.amountActive = 0
|
||||
else:
|
||||
for position in positions:
|
||||
drone = fit.drones[position]
|
||||
if drone.amountActive == 0:
|
||||
drone.amountActive = drone.amount
|
||||
|
||||
eos.db.commit()
|
||||
return True
|
||||
|
||||
def Undo(self):
|
||||
pyfalog.debug('Undoing toggling of local drone state at position {}/{} for fit {}'.format(self.mainPosition, self.positions, self.fitID))
|
||||
cmd = CalcToggleLocalDroneStatesCommand(
|
||||
fitID=self.fitID,
|
||||
mainPosition=self.mainPosition,
|
||||
positions=self.positions,
|
||||
forceActiveAmounts=self.savedActiveAmounts)
|
||||
return cmd.Do()
|
||||
@@ -14,10 +14,11 @@ pyfalog = Logger(__name__)
|
||||
|
||||
class CalcAddProjectedDroneCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, droneInfo):
|
||||
def __init__(self, fitID, droneInfo, commit=True):
|
||||
wx.Command.__init__(self, True, 'Add Projected Drone')
|
||||
self.fitID = fitID
|
||||
self.droneInfo = droneInfo
|
||||
self.commit = commit
|
||||
self.savedDroneInfo = None
|
||||
|
||||
def Do(self):
|
||||
@@ -32,7 +33,8 @@ class CalcAddProjectedDroneCommand(wx.Command):
|
||||
drone.amount += self.droneInfo.amount
|
||||
if drone.amountActive > 0:
|
||||
drone.amountActive += self.droneInfo.amount
|
||||
eos.db.commit()
|
||||
if self.commit:
|
||||
eos.db.commit()
|
||||
return True
|
||||
# Making new stack
|
||||
drone = self.droneInfo.toDrone()
|
||||
@@ -45,9 +47,11 @@ class CalcAddProjectedDroneCommand(wx.Command):
|
||||
fit.projectedDrones.append(drone)
|
||||
except HandledListActionError:
|
||||
pyfalog.warning('Failed to append to list')
|
||||
eos.db.commit()
|
||||
if self.commit:
|
||||
eos.db.commit()
|
||||
return False
|
||||
eos.db.commit()
|
||||
if self.commit:
|
||||
eos.db.commit()
|
||||
return True
|
||||
|
||||
def Undo(self):
|
||||
@@ -61,8 +65,14 @@ class CalcAddProjectedDroneCommand(wx.Command):
|
||||
return False
|
||||
drone.amount = self.savedDroneInfo.amount
|
||||
drone.amountActive = self.savedDroneInfo.amountActive
|
||||
if self.commit:
|
||||
eos.db.commit()
|
||||
return True
|
||||
# Removing previously added stack
|
||||
from .projectedRemove import CalcRemoveProjectedDroneCommand
|
||||
cmd = CalcRemoveProjectedDroneCommand(fitID=self.fitID, itemID=self.droneInfo.itemID, amount=math.inf)
|
||||
cmd = CalcRemoveProjectedDroneCommand(
|
||||
fitID=self.fitID,
|
||||
itemID=self.droneInfo.itemID,
|
||||
amount=math.inf,
|
||||
commit=self.commit)
|
||||
return cmd.Do()
|
||||
|
||||
53
gui/fitCommands/calc/drone/projectedChangeState.py
Normal file
53
gui/fitCommands/calc/drone/projectedChangeState.py
Normal file
@@ -0,0 +1,53 @@
|
||||
import wx
|
||||
from logbook import Logger
|
||||
|
||||
import eos.db
|
||||
from service.fit import Fit
|
||||
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class CalcChangeProjectedDroneStateCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, itemID, state, commit=True):
|
||||
wx.Command.__init__(self, True, 'Change Projected Drone State')
|
||||
self.fitID = fitID
|
||||
self.itemID = itemID
|
||||
self.state = state
|
||||
self.commit = commit
|
||||
self.savedState = None
|
||||
|
||||
def Do(self):
|
||||
pyfalog.debug('Doing changing of projected drone {} state to {} for fit {}'.format(self.itemID, self.state, self.fitID))
|
||||
fit = Fit.getInstance().getFit(self.fitID)
|
||||
|
||||
drone = next((pd for pd in fit.projectedDrones if pd.itemID == self.itemID), None)
|
||||
if drone is None:
|
||||
pyfalog.warning('Unable to find projected drone')
|
||||
return False
|
||||
self.savedState = drone.amountActive > 0
|
||||
|
||||
if self.state == self.savedState:
|
||||
return False
|
||||
|
||||
if self.state:
|
||||
if not drone.canBeApplied(fit):
|
||||
pyfalog.warning('Projected drone cannot be applied')
|
||||
return False
|
||||
drone.amountActive = drone.amount
|
||||
else:
|
||||
drone.amountActive = 0
|
||||
|
||||
if self.commit:
|
||||
eos.db.commit()
|
||||
return True
|
||||
|
||||
def Undo(self):
|
||||
pyfalog.debug('Undoing changing of projected drone {} state to {} for fit {}'.format(self.itemID, self.state, self.fitID))
|
||||
cmd = CalcChangeProjectedDroneStateCommand(
|
||||
fitID=self.fitID,
|
||||
itemID=self.itemID,
|
||||
state=self.savedState,
|
||||
commit=self.commit)
|
||||
return cmd.Do()
|
||||
@@ -11,11 +11,12 @@ pyfalog = Logger(__name__)
|
||||
|
||||
class CalcRemoveProjectedDroneCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, itemID, amount):
|
||||
def __init__(self, fitID, itemID, amount, commit=True):
|
||||
wx.Command.__init__(self, True, 'Remove Projected Drone')
|
||||
self.fitID = fitID
|
||||
self.itemID = itemID
|
||||
self.amountToRemove = amount
|
||||
self.commit = commit
|
||||
self.savedDroneInfo = None
|
||||
|
||||
def Do(self):
|
||||
@@ -33,7 +34,8 @@ class CalcRemoveProjectedDroneCommand(wx.Command):
|
||||
else:
|
||||
if drone.amountActive > 0:
|
||||
drone.amountActive = min(drone.amountActive, drone.amount)
|
||||
eos.db.commit()
|
||||
if self.commit:
|
||||
eos.db.commit()
|
||||
return True
|
||||
|
||||
def Undo(self):
|
||||
@@ -44,8 +46,10 @@ class CalcRemoveProjectedDroneCommand(wx.Command):
|
||||
if drone is not None:
|
||||
drone.amount = self.savedDroneInfo.amount
|
||||
drone.amountActive = self.savedDroneInfo.amountActive
|
||||
if self.commit:
|
||||
eos.db.commit()
|
||||
return True
|
||||
# Make new stack
|
||||
from .projectedAdd import CalcAddProjectedDroneCommand
|
||||
cmd = CalcAddProjectedDroneCommand(fitID=self.fitID, droneInfo=self.savedDroneInfo)
|
||||
cmd = CalcAddProjectedDroneCommand(fitID=self.fitID, droneInfo=self.savedDroneInfo, commit=self.commit)
|
||||
return cmd.Do()
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
import wx
|
||||
from logbook import Logger
|
||||
|
||||
import eos.db
|
||||
from service.fit import Fit
|
||||
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class CalcToggleProjectedDroneStateCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, itemID, forceAmountActive=None):
|
||||
wx.Command.__init__(self, True, 'Toggle Projected Drone State')
|
||||
self.fitID = fitID
|
||||
self.itemID = itemID
|
||||
self.forceAmountActive = forceAmountActive
|
||||
self.savedAmountActive = None
|
||||
|
||||
def Do(self):
|
||||
pyfalog.debug('Doing toggling of projected drone {} state for fit {}'.format(self.itemID, self.fitID))
|
||||
fit = Fit.getInstance().getFit(self.fitID)
|
||||
drone = next((pd for pd in fit.projectedDrones if pd.itemID == self.itemID), None)
|
||||
if drone is None:
|
||||
pyfalog.warning('Unable to find projected drone')
|
||||
return False
|
||||
self.savedAmountActive = drone.amountActive
|
||||
if self.forceAmountActive is not None:
|
||||
if self.forceAmountActive > 0 and not drone.canBeApplied(fit):
|
||||
pyfalog.warning('Projected drone cannot be applied')
|
||||
return False
|
||||
drone.amountActive = self.forceAmountActive
|
||||
elif drone.amountActive > 0:
|
||||
drone.amountActive = 0
|
||||
else:
|
||||
if not drone.canBeApplied(fit):
|
||||
pyfalog.warning('Projected drone cannot be applied')
|
||||
return False
|
||||
drone.amountActive = drone.amount
|
||||
eos.db.commit()
|
||||
return True
|
||||
|
||||
def Undo(self):
|
||||
pyfalog.debug('Undoing toggling of projected drone {} state for fit {}'.format(self.itemID, self.fitID))
|
||||
cmd = CalcToggleProjectedDroneStateCommand(fitID=self.fitID, itemID=self.itemID, forceAmountActive=self.savedAmountActive)
|
||||
return cmd.Do()
|
||||
@@ -1,44 +0,0 @@
|
||||
import wx
|
||||
from logbook import Logger
|
||||
|
||||
import eos.db
|
||||
from service.fit import Fit
|
||||
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class CalcToggleFighterAbilityStateCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, projected, position, effectID, forceState=None):
|
||||
wx.Command.__init__(self, True, 'Toggle Fighter Ability State')
|
||||
self.fitID = fitID
|
||||
self.projected = projected
|
||||
self.position = position
|
||||
self.effectID = effectID
|
||||
self.forceState = forceState
|
||||
self.savedState = None
|
||||
|
||||
def Do(self):
|
||||
pyfalog.debug('Doing toggling of fighter ability {} state at position {} for fit {}'.format(self.effectID, self.position, self.fitID))
|
||||
fit = Fit.getInstance().getFit(self.fitID)
|
||||
container = fit.projectedFighters if self.projected else fit.fighters
|
||||
fighter = container[self.position]
|
||||
ability = next((fa for fa in fighter.abilities if fa.effectID == self.effectID), None)
|
||||
if ability is None:
|
||||
pyfalog.warning('Unable to find fighter ability')
|
||||
return False
|
||||
self.savedState = ability.active
|
||||
ability.active = not ability.active if self.forceState is None else self.forceState
|
||||
eos.db.commit()
|
||||
return True
|
||||
|
||||
def Undo(self):
|
||||
pyfalog.debug('Unoing toggling of fighter ability {} state at position {} for fit {}'.format(self.effectID, self.position, self.fitID))
|
||||
cmd = CalcToggleFighterAbilityStateCommand(
|
||||
fitID=self.fitID,
|
||||
projected=self.projected,
|
||||
position=self.position,
|
||||
effectID=self.effectID,
|
||||
forceState=self.savedState)
|
||||
return cmd.Do()
|
||||
87
gui/fitCommands/calc/fighter/abilityToggleStates.py
Normal file
87
gui/fitCommands/calc/fighter/abilityToggleStates.py
Normal file
@@ -0,0 +1,87 @@
|
||||
import wx
|
||||
from logbook import Logger
|
||||
|
||||
import eos.db
|
||||
from service.fit import Fit
|
||||
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class CalcToggleFighterAbilityStatesCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, projected, mainPosition, positions, effectID, forceStates=None):
|
||||
wx.Command.__init__(self, True, 'Toggle Fighter Ability States')
|
||||
self.fitID = fitID
|
||||
self.projected = projected
|
||||
self.mainPosition = mainPosition
|
||||
self.positions = positions
|
||||
self.effectID = effectID
|
||||
self.forceStates = forceStates
|
||||
self.savedStates = None
|
||||
|
||||
def Do(self):
|
||||
pyfalog.debug('Doing toggling of fighter ability {} state at position {}/{} for fit {}'.format(self.effectID, self.mainPosition, self.positions, self.fitID))
|
||||
fit = Fit.getInstance().getFit(self.fitID)
|
||||
container = fit.projectedFighters if self.projected else fit.fighters
|
||||
|
||||
positions = self.positions[:]
|
||||
if self.mainPosition not in positions:
|
||||
positions.append(self.mainPosition)
|
||||
savedStates = {}
|
||||
for position in positions:
|
||||
fighter = container[position]
|
||||
ability = next((fa for fa in fighter.abilities if fa.effectID == self.effectID), None)
|
||||
if ability is None:
|
||||
continue
|
||||
savedStates[position] = ability.active
|
||||
if len(savedStates) > 0:
|
||||
self.savedStates = savedStates
|
||||
|
||||
mainFighter = container[self.mainPosition]
|
||||
mainAbility = next((fa for fa in mainFighter.abilities if fa.effectID == self.effectID), None)
|
||||
|
||||
changes = False
|
||||
if self.forceStates is not None:
|
||||
for position, state in self.forceStates.items():
|
||||
fighter = container[position]
|
||||
ability = next((fa for fa in fighter.abilities if fa.effectID == self.effectID), None)
|
||||
if ability is None:
|
||||
continue
|
||||
changes = True
|
||||
if ability.active is not state:
|
||||
ability.active = state
|
||||
elif mainAbility is None:
|
||||
pyfalog.warning('Unable to find main fighter ability')
|
||||
return False
|
||||
elif mainAbility.active:
|
||||
for position in positions:
|
||||
fighter = container[position]
|
||||
ability = next((fa for fa in fighter.abilities if fa.effectID == self.effectID), None)
|
||||
if ability is None:
|
||||
continue
|
||||
if ability.active:
|
||||
changes = True
|
||||
ability.active = False
|
||||
else:
|
||||
for position in positions:
|
||||
fighter = container[position]
|
||||
ability = next((fa for fa in fighter.abilities if fa.effectID == self.effectID), None)
|
||||
if ability is None:
|
||||
continue
|
||||
if not ability.active:
|
||||
changes = True
|
||||
ability.active = True
|
||||
eos.db.commit()
|
||||
return changes
|
||||
|
||||
def Undo(self):
|
||||
pyfalog.debug('Undoing toggling of fighter ability {} state at position {}/{} for fit {}'.format(self.effectID, self.mainPosition, self.positions, self.fitID))
|
||||
cmd = CalcToggleFighterAbilityStatesCommand(
|
||||
fitID=self.fitID,
|
||||
projected=self.projected,
|
||||
mainPosition=self.mainPosition,
|
||||
positions=self.positions,
|
||||
effectID=self.effectID,
|
||||
forceStates=self.savedStates)
|
||||
return cmd.Do()
|
||||
@@ -11,11 +11,13 @@ pyfalog = Logger(__name__)
|
||||
|
||||
class CalcAddLocalFighterCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, fighterInfo, position=None):
|
||||
def __init__(self, fitID, fighterInfo, position=None, ignoreRestrictions=False, commit=True):
|
||||
wx.Command.__init__(self, True, 'Add Fighter')
|
||||
self.fitID = fitID
|
||||
self.fighterInfo = fighterInfo
|
||||
self.position = position
|
||||
self.ignoreRestrictions = ignoreRestrictions
|
||||
self.commit = commit
|
||||
|
||||
def Do(self):
|
||||
pyfalog.debug('Doing addition of fighter {} to fit {}'.format(self.fighterInfo, self.fitID))
|
||||
@@ -24,7 +26,7 @@ class CalcAddLocalFighterCommand(wx.Command):
|
||||
return False
|
||||
|
||||
fit = Fit.getInstance().getFit(self.fitID)
|
||||
if not fighter.fits(fit):
|
||||
if not self.ignoreRestrictions and not fighter.fits(fit):
|
||||
pyfalog.warning('Fighter does not fit')
|
||||
return False
|
||||
|
||||
@@ -43,7 +45,8 @@ class CalcAddLocalFighterCommand(wx.Command):
|
||||
fit.fighters.append(fighter)
|
||||
except HandledListActionError:
|
||||
pyfalog.warning('Failed to append to list')
|
||||
eos.db.commit()
|
||||
if self.commit:
|
||||
eos.db.commit()
|
||||
return False
|
||||
self.position = fit.fighters.index(fighter)
|
||||
else:
|
||||
@@ -51,14 +54,16 @@ class CalcAddLocalFighterCommand(wx.Command):
|
||||
fit.fighters.insert(self.position, fighter)
|
||||
except HandledListActionError:
|
||||
pyfalog.warning('Failed to insert to list')
|
||||
eos.db.commit()
|
||||
if self.commit:
|
||||
eos.db.commit()
|
||||
return False
|
||||
eos.db.commit()
|
||||
if self.commit:
|
||||
eos.db.commit()
|
||||
return True
|
||||
|
||||
def Undo(self):
|
||||
pyfalog.debug('Undoing addition of fighter {} to fit {}'.format(self.fighterInfo, self.fitID))
|
||||
from .localRemove import CalcRemoveLocalFighterCommand
|
||||
cmd = CalcRemoveLocalFighterCommand(fitID=self.fitID, position=self.position)
|
||||
cmd = CalcRemoveLocalFighterCommand(fitID=self.fitID, position=self.position, commit=self.commit)
|
||||
cmd.Do()
|
||||
return True
|
||||
|
||||
@@ -11,10 +11,11 @@ pyfalog = Logger(__name__)
|
||||
|
||||
class CalcRemoveLocalFighterCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, position):
|
||||
def __init__(self, fitID, position, commit=True):
|
||||
wx.Command.__init__(self, True, 'Remove Fighter')
|
||||
self.fitID = fitID
|
||||
self.position = position
|
||||
self.commit = commit
|
||||
self.savedFighterInfo = None
|
||||
|
||||
def Do(self):
|
||||
@@ -23,11 +24,17 @@ class CalcRemoveLocalFighterCommand(wx.Command):
|
||||
fighter = fit.fighters[self.position]
|
||||
self.savedFighterInfo = FighterInfo.fromFighter(fighter)
|
||||
fit.fighters.remove(fighter)
|
||||
eos.db.commit()
|
||||
if self.commit:
|
||||
eos.db.commit()
|
||||
return True
|
||||
|
||||
def Undo(self):
|
||||
pyfalog.debug('Undoing removal of fighter at position {} from fit {}'.format(self.position, self.fitID))
|
||||
from .localAdd import CalcAddLocalFighterCommand
|
||||
cmd = CalcAddLocalFighterCommand(fitID=self.fitID, fighterInfo=self.savedFighterInfo, position=self.position)
|
||||
cmd = CalcAddLocalFighterCommand(
|
||||
fitID=self.fitID,
|
||||
fighterInfo=self.savedFighterInfo,
|
||||
position=self.position,
|
||||
ignoreRestrictions=True,
|
||||
commit=self.commit)
|
||||
return cmd.Do()
|
||||
|
||||
56
gui/fitCommands/calc/fighter/localToggleStates.py
Normal file
56
gui/fitCommands/calc/fighter/localToggleStates.py
Normal file
@@ -0,0 +1,56 @@
|
||||
import wx
|
||||
from logbook import Logger
|
||||
|
||||
import eos.db
|
||||
from service.fit import Fit
|
||||
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class CalcToggleLocalFighterStatesCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, mainPosition, positions, forceStates=None):
|
||||
wx.Command.__init__(self, True, 'Toggle Local Fighter States')
|
||||
self.fitID = fitID
|
||||
self.mainPosition = mainPosition
|
||||
self.positions = positions
|
||||
self.forceStates = forceStates
|
||||
self.savedStates = None
|
||||
|
||||
def Do(self):
|
||||
pyfalog.debug('Doing toggling of local fighter state at position {}/{} for fit {}'.format(
|
||||
self.mainPosition, self.positions, self.fitID))
|
||||
fit = Fit.getInstance().getFit(self.fitID)
|
||||
|
||||
positions = self.positions[:]
|
||||
if self.mainPosition not in positions:
|
||||
positions.append(self.mainPosition)
|
||||
self.savedStates = {p: fit.fighters[p].active for p in positions}
|
||||
|
||||
if self.forceStates is not None:
|
||||
for position, state in self.forceStates.items():
|
||||
fighter = fit.fighters[position]
|
||||
fighter.active = state
|
||||
elif fit.fighters[self.mainPosition].active:
|
||||
for position in positions:
|
||||
fighter = fit.fighters[position]
|
||||
if fighter.active:
|
||||
fighter.active = False
|
||||
else:
|
||||
for position in positions:
|
||||
fighter = fit.fighters[position]
|
||||
if not fighter.active:
|
||||
fighter.active = True
|
||||
eos.db.commit()
|
||||
return True
|
||||
|
||||
def Undo(self):
|
||||
pyfalog.debug('Undoing toggling of local fighter state at position {}/{} for fit {}'.format(
|
||||
self.mainPosition, self.positions, self.fitID))
|
||||
cmd = CalcToggleLocalFighterStatesCommand(
|
||||
fitID=self.fitID,
|
||||
mainPosition=self.mainPosition,
|
||||
positions=self.positions,
|
||||
forceStates=self.savedStates)
|
||||
return cmd.Do()
|
||||
@@ -11,11 +11,12 @@ pyfalog = Logger(__name__)
|
||||
|
||||
class CalcAddProjectedFighterCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, fighterInfo, position=None):
|
||||
def __init__(self, fitID, fighterInfo, position=None, commit=True):
|
||||
wx.Command.__init__(self, True, 'Add Projected Fighter')
|
||||
self.fitID = fitID
|
||||
self.fighterInfo = fighterInfo
|
||||
self.position = position
|
||||
self.commit = commit
|
||||
|
||||
def Do(self):
|
||||
pyfalog.debug('Doing addition of projected fighter {} onto: {}'.format(self.fighterInfo, self.fitID))
|
||||
@@ -27,20 +28,23 @@ class CalcAddProjectedFighterCommand(wx.Command):
|
||||
try:
|
||||
fit.projectedFighters.insert(self.position, fighter)
|
||||
except HandledListActionError:
|
||||
eos.db.commit()
|
||||
if self.commit:
|
||||
eos.db.commit()
|
||||
return False
|
||||
else:
|
||||
try:
|
||||
fit.projectedFighters.append(fighter)
|
||||
except HandledListActionError:
|
||||
eos.db.commit()
|
||||
if self.commit:
|
||||
eos.db.commit()
|
||||
return False
|
||||
self.position = fit.projectedFighters.index(fighter)
|
||||
eos.db.commit()
|
||||
if self.commit:
|
||||
eos.db.commit()
|
||||
return True
|
||||
|
||||
def Undo(self):
|
||||
pyfalog.debug('Undoing addition of projected fighter {} onto: {}'.format(self.fighterInfo, self.fitID))
|
||||
from .projectedRemove import CalcRemoveProjectedFighterCommand
|
||||
cmd = CalcRemoveProjectedFighterCommand(fitID=self.fitID, position=self.position)
|
||||
cmd = CalcRemoveProjectedFighterCommand(fitID=self.fitID, position=self.position, commit=self.commit)
|
||||
return cmd.Do()
|
||||
|
||||
46
gui/fitCommands/calc/fighter/projectedChangeState.py
Normal file
46
gui/fitCommands/calc/fighter/projectedChangeState.py
Normal file
@@ -0,0 +1,46 @@
|
||||
import wx
|
||||
from logbook import Logger
|
||||
|
||||
import eos.db
|
||||
from service.fit import Fit
|
||||
|
||||
|
||||
pyfalog = Logger(__name__)
|
||||
|
||||
|
||||
class CalcChangeProjectedFighterStateCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, position, state, commit=True):
|
||||
wx.Command.__init__(self, True, 'Change Projected Fighter State')
|
||||
self.fitID = fitID
|
||||
self.position = position
|
||||
self.state = state
|
||||
self.commit = commit
|
||||
self.savedState = None
|
||||
|
||||
def Do(self):
|
||||
pyfalog.debug('Doing changing of projected fighter state to {} at position {} for fit {}'.format(
|
||||
self.state, self.position, self.fitID))
|
||||
|
||||
fit = Fit.getInstance().getFit(self.fitID)
|
||||
fighter = fit.projectedFighters[self.position]
|
||||
self.savedState = fighter.active
|
||||
|
||||
if self.state == self.savedState:
|
||||
return False
|
||||
|
||||
fighter.active = self.state
|
||||
|
||||
if self.commit:
|
||||
eos.db.commit()
|
||||
return True
|
||||
|
||||
def Undo(self):
|
||||
pyfalog.debug('Undoing changing of projected fighter state to {} at position {} for fit {}'.format(
|
||||
self.state, self.position, self.fitID))
|
||||
cmd = CalcChangeProjectedFighterStateCommand(
|
||||
fitID=self.fitID,
|
||||
position=self.position,
|
||||
state=self.savedState,
|
||||
commit=self.commit)
|
||||
return cmd.Do()
|
||||
@@ -11,10 +11,11 @@ pyfalog = Logger(__name__)
|
||||
|
||||
class CalcRemoveProjectedFighterCommand(wx.Command):
|
||||
|
||||
def __init__(self, fitID, position):
|
||||
def __init__(self, fitID, position, commit=True):
|
||||
wx.Command.__init__(self, True, 'Add Projected Fighter')
|
||||
self.fitID = fitID
|
||||
self.position = position
|
||||
self.commit = commit
|
||||
self.savedFighterInfo = None
|
||||
|
||||
def Do(self):
|
||||
@@ -23,11 +24,16 @@ class CalcRemoveProjectedFighterCommand(wx.Command):
|
||||
fighter = fit.projectedFighters[self.position]
|
||||
self.savedFighterInfo = FighterInfo.fromFighter(fighter)
|
||||
fit.projectedFighters.remove(fighter)
|
||||
eos.db.commit()
|
||||
if self.commit:
|
||||
eos.db.commit()
|
||||
return True
|
||||
|
||||
def Undo(self):
|
||||
pyfalog.debug('Undoing removal of projected fighter at position {} from fit {}'.format(self.position, self.fitID))
|
||||
from .projectedAdd import CalcAddProjectedFighterCommand
|
||||
cmd = CalcAddProjectedFighterCommand(fitID=self.fitID, fighterInfo=self.savedFighterInfo)
|
||||
cmd = CalcAddProjectedFighterCommand(
|
||||
fitID=self.fitID,
|
||||
fighterInfo=self.savedFighterInfo,
|
||||
position=self.position,
|
||||
commit=self.commit)
|
||||
return cmd.Do()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user