panelAttributes.py (23494B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\info\shipInfoPanels\panelAttributes.py 2 import eveicon 3 import localization 4 from collections import OrderedDict 5 import uthread2 6 from carbonui import Align, uiconst, TextColor 7 from carbonui.text.styles import TextHeader, TextBody 8 from carbonui.control.scrollContainer import ScrollContainer 9 from carbonui.primitives.container import Container 10 from carbonui.primitives.containerAutoSize import ContainerAutoSize 11 from carbonui.uianimations import animations 12 from dogma import const 13 from dogma.attributes.format import GetFormattedAttributeAndValue 14 from eve.client.script.ui.control.eveWindowUnderlay import ListEntryUnderlay 15 from eve.client.script.ui.inflight.shipModuleButton.attributeValueRowContainer import AttributeValueRowContainer 16 from eve.client.script.ui.shared.info.attribute import Attribute 17 from eve.client.script.ui.shared.info.shipInfoCollapsibleGroup import CollapsibleGaugeGroup, CollapsibleGroup 18 from eve.client.script.ui.shared.info.shipInfoListEntries import ListEntryStatusBarAttribute, ListEntryAttribute, ListEntryTypeAttribute 19 from eve.client.script.ui.shared.info.shipInfoPanels.panelBase import PanelBase 20 from eve.client.script.ui.shared.info.shipInfoConst import TOP_DOWN_NOSE_UP, TAB_ATTRIBUTES 21 from eve.common.script.util.eveFormat import FmtDist2 22 from fsdBuiltData.common.iconIDs import GetIconFile 23 from localization import GetByLabel 24 from shipfitting.fittingDogmaLocationUtil import GetAlignTimeFromAgilityAndMass 25 DAMAGE_TYPE_ICONS = {'em': 'res:/ui/texture/icons/22_32_12.png', 26 'thermal': 'res:/ui/texture/icons/22_32_10.png', 27 'kinetic': 'res:/ui/texture/icons/22_32_9.png', 28 'explosive': 'res:/ui/texture/icons/22_32_11.png'} 29 DAMAGE_TYPE_COLORS = {'em': (0.1, 30 0.37, 31 0.55, 32 1.0), 33 'thermal': (0.55, 34 0.1, 35 0.1, 36 1.0), 37 'kinetic': (0.45, 38 0.45, 39 0.45, 40 1.0), 41 'explosive': (0.55, 42 0.37, 43 0.1, 44 1.0)} 45 MIN_IN_MS = 60 * 1000 46 ATTRIBUTE_GROUP_ICONS = {'structure': eveicon.inventory, 47 'armor': eveicon.armor, 48 'shield': eveicon.shields, 49 'ewar': eveicon.capacitor_warfare, 50 'capacitor': eveicon.capacitor_plus, 51 'targeting': eveicon.target, 52 'sharedFacilities': eveicon.shared_folder, 53 'fighterFacilities': eveicon.drones, 54 'onDeath': eveicon.inventory, 55 'jumpDrive': eveicon.broadcast_warp_to_jump_beacon, 56 'propulsion': eveicon.warp_to, 57 'navigation': eveicon.warp_to, 58 'drones': eveicon.drones, 59 'inventory': eveicon.inventory} 60 61 class PanelAttributes(PanelBase): 62 63 def ApplyAttributes(self, attributes): 64 self.fitting_controller = None 65 super(PanelAttributes, self).ApplyAttributes(attributes) 66 67 def _construct_content(self): 68 self.scrollContainer = ScrollContainer(name='abilityScroll', parent=self.rightCont, align=Align.TOALL) 69 self.attributeCont = ContainerAutoSize(name='abilityCont', parent=self.scrollContainer, align=Align.TOTOP) 70 self._construct_attributes() 71 uthread2.start_tasklet(self._construct_size) 72 73 def _construct_attributes(self): 74 attrDict = self.infoSvc.GetAttributeDictForType(self.typeID) 75 for group_id, attribGroup in self.attributesByCaption.iteritems(): 76 group_icon = ATTRIBUTE_GROUP_ICONS[group_id] 77 group_name = attribGroup['groupName'] 78 normalAttributes = attribGroup['normalAttributes'] 79 groupedAttributes = attribGroup.get('groupedAttributes', []) 80 constructedAttributes = attribGroup.get('constructedAttributes', None) 81 derivedHeaderAttribute = attribGroup.get('derivedHeaderAttribute', None) 82 derivedHeaderAttributeLabel = None 83 derivedHeaderAttributeValue = None 84 derivedHeaderAttributeTooltip = None 85 derivedHeaderAttributeFormat = None 86 if derivedHeaderAttribute: 87 derivedHeaderAttributeLabel = derivedHeaderAttribute['name'] 88 derivedHeaderAttributeTooltip = derivedHeaderAttribute['tooltip'] 89 derivedHeaderAttributeFormat = derivedHeaderAttribute['format'] 90 valueFunc = derivedHeaderAttribute['valueFunc'] 91 parameterAttribs = derivedHeaderAttribute['parameterAttributes'] 92 params = {} 93 for name, attributeID in parameterAttribs.iteritems(): 94 params[name] = self.attributes[attributeID].value 95 96 derivedHeaderAttributeValue = valueFunc(**params) 97 if groupedAttributes: 98 groupedAttribs = {} 99 layerHpAttributeID = attribGroup['hpAttribute'] 100 hpDescriptionPath = attribGroup['hpDescriptionPath'] 101 layerHp = self.attributes[layerHpAttributeID].value 102 for damageType, attributeID in groupedAttributes: 103 attrib = self.attributes[attributeID] 104 modifiedAttrib = self.modifiedAttributesDict.get(attributeID, None) 105 groupedAttribs[damageType] = (attrib, modifiedAttrib) 106 107 groupContainer = CollapsibleGaugeGroup(parent=self.attributeCont, name=group_id, align=Align.TOTOP, groupIcon=group_icon, groupName=group_name, iconID=eveicon.armor, itemID=self.itemID, layerHp=layerHp, groupedAttributes=groupedAttribs, padBottom=8, damageTypeIcons=DAMAGE_TYPE_ICONS, damageTypeColors=DAMAGE_TYPE_COLORS, ehpDescriptionPath=hpDescriptionPath) 108 else: 109 groupContainer = CollapsibleGroupWithHeaderAttribute(parent=self.attributeCont, name=group_id, align=Align.TOTOP, groupIcon=group_icon, groupName=group_name, padBottom=8, headerAttributeLabel=derivedHeaderAttributeLabel, headerAttributeValue=derivedHeaderAttributeValue, headerAttributeTooltip=derivedHeaderAttributeTooltip, headerAttributeFormat=derivedHeaderAttributeFormat) 110 groupedEntries, attribsAdded = self.infoSvc.GetAttributeRowData(normalAttributes, attrDict, self.itemID, self.modifiedAttributesDict) 111 shipAttr = [ each for each in normalAttributes if each in attrDict ] 112 for attributeID in shipAttr: 113 if attributeID in attribsAdded: 114 continue 115 attrib = self.attributes[attributeID] 116 modifiedAttrib = self.modifiedAttributesDict.get(attributeID, None) 117 if attrib.unitID == const.unitMilliseconds and attrib.value >= 5 * MIN_IN_MS: 118 formatInfo = GetFormattedAttributeAndValue(attributeID, attrib.value / MIN_IN_MS / 60, const.unitHour) 119 else: 120 formatInfo = GetFormattedAttributeAndValue(attributeID, attrib.value) 121 if not formatInfo: 122 continue 123 statusBarData = self.infoSvc.GetStatusBarDataForAttribute(attributeID, self.itemID, self.typeID, modifiedAttrib) 124 if statusBarData: 125 texturePath = GetIconFile(statusBarData['iconID']) 126 ListEntryStatusBarAttribute(label=statusBarData['label'], text=statusBarData['text'], texturePath=texturePath, itemID=self.itemID, attributeID=statusBarData['attributeID'], modifiedAttribute=statusBarData['modifiedAttribute'], color=statusBarData['color'], value=statusBarData['value'], parent=groupContainer.mainCont) 127 continue 128 attributeData = self.infoSvc.GetDataForAttribute(attributeID, attrib.value, self.itemID, self.typeID, modifiedAttrib) 129 if attributeData: 130 texturePath = GetIconFile(attributeData['iconID']) 131 if attributeData['typeID']: 132 ListEntryTypeAttribute(label=attributeData['label'], text=attributeData['text'], texturePath=texturePath, typeID=attributeData['typeID'], itemID=self.itemID, attributeID=attributeData['attributeID'], modifiedAttribute=attributeData['modifiedAttribute'], parent=groupContainer.mainCont) 133 else: 134 ListEntryAttribute(label=attributeData['label'], text=attributeData['text'], texturePath=texturePath, itemID=self.itemID, attributeID=attributeData['attributeID'], modifiedAttribute=attributeData['modifiedAttribute'], parent=groupContainer.mainCont) 135 136 if constructedAttributes: 137 for attributeID, dataFunc in constructedAttributes: 138 data = dataFunc(self.typeID, self.itemID) 139 texturePath = GetIconFile(data['iconID']) 140 if data: 141 ListEntryAttribute(parent=groupContainer.mainCont, label=data['label'], text=data['text'], texturePath=texturePath, itemID=self.itemID, attributeID=data['attributeID'], modifiedAttribute=data.get('modifiedAttribute', None)) 142 143 for dataEntry in groupedEntries: 144 ListEntryAttributeGroup(parent=groupContainer.mainCont, padLeft=4, **dataEntry) 145 146 if len(groupContainer.mainCont.children) == 0: 147 groupContainer.Hide() 148 continue 149 150 def _construct_size(self): 151 bottomCont = Container(name='bottomCont', parent=self.leftCont, align=Align.TOBOTTOM, height=84, padLeft=32, opacity=0) 152 long_axis_length = self._controller.long_axis_length 153 while long_axis_length == 0: 154 uthread2.sleep(0.01) 155 long_axis_length = self._controller.long_axis_length 156 157 length = FmtDist2(long_axis_length, maxDecimals=0) 158 labelCont = Container(name='labelCont', parent=bottomCont, align=Align.TOTOP, height=12) 159 TextBody(name='label', parent=labelCont, align=Align.CENTERLEFT, text=localization.GetByLabel('UI/InfoWindow/LongAxis'), color=TextColor.SECONDARY) 160 valueCont = Container(name='valueCont', parent=bottomCont, align=Align.TOTOP, height=24) 161 TextHeader(name='value', parent=valueCont, align=Align.CENTERLEFT, text=length, bold=True) 162 animations.FadeIn(bottomCont, duration=1.2) 163 164 def _gather_data(self): 165 self.infoSvc = sm.GetService('info') 166 self.attributesByCaption = self.get_ship_attributes() 167 self.attributeDictForType, self.attributeDict = self.infoSvc.GetAttributeDictForItem(self.itemID, self.typeID) 168 self.modifiedAttributesDict = self.infoSvc.FindAttributesThatHaveBeenModified(self.attributeDictForType, self.attributeDict) 169 if not self.attributeDict: 170 self.attributeDict = self.attributeDictForType 171 self.attributes = {} 172 for attributeID, value in self.attributeDict.iteritems(): 173 self.attributes[attributeID] = Attribute(attributeID, value) 174 175 def _enable_expanded_view(self): 176 self.attributeCont.SetParent(self.scrollContainer) 177 178 def _enable_minimized_view(self): 179 self.attributeCont.SetParent(self.content_scroll_minimized) 180 181 @classmethod 182 def get_name(cls): 183 return localization.GetByLabel('UI/InfoWindow/TabNames/Attributes') 184 185 @classmethod 186 def get_icon(cls): 187 return eveicon.attributes 188 189 def get_camera_position(self): 190 return TOP_DOWN_NOSE_UP 191 192 def get_tab_type(self): 193 return TAB_ATTRIBUTES 194 195 @classmethod 196 def is_visible(cls, typeID, itemID = None, rec = None): 197 return True 198 199 def _get_group_icon(self, group_id): 200 return None 201 202 def get_ship_attributes(self): 203 shipAttributes = OrderedDict() 204 shipAttributes['shield'] = {'groupName': GetByLabel('UI/Common/Shield'), 205 'hpAttribute': const.attributeShieldCapacity, 206 'hpDescriptionPath': 'UI/InfoWindow/EffectiveHpDescriptionShield', 207 'groupedAttributes': [('em', const.attributeShieldEmDamageResonance), 208 ('thermal', const.attributeShieldThermalDamageResonance), 209 ('kinetic', const.attributeShieldKineticDamageResonance), 210 ('explosive', const.attributeShieldExplosiveDamageResonance)], 211 'normalAttributes': [const.attributeShieldCapacity, const.attributeShieldRechargeRate, const.attributeShieldDamageLimit]} 212 shipAttributes['armor'] = {'groupName': GetByLabel('UI/Common/Armor'), 213 'hpAttribute': const.attributeArmorHP, 214 'hpDescriptionPath': 'UI/InfoWindow/EffectiveHpDescriptionArmor', 215 'groupedAttributes': [('em', const.attributeArmorEmDamageResonance), 216 ('thermal', const.attributeArmorThermalDamageResonance), 217 ('kinetic', const.attributeArmorKineticDamageResonance), 218 ('explosive', const.attributeArmorExplosiveDamageResonance)], 219 'normalAttributes': [const.attributeArmorHP, const.attributeArmorDamageLimit]} 220 shipAttributes['structure'] = {'groupName': GetByLabel('UI/Fitting/Structure'), 221 'hpAttribute': const.attributeHp, 222 'hpDescriptionPath': 'UI/InfoWindow/EffectiveHpDescriptionStructure', 223 'groupedAttributes': [('em', const.attributeEmDamageResonance), 224 ('thermal', const.attributeThermalDamageResonance), 225 ('kinetic', const.attributeKineticDamageResonance), 226 ('explosive', const.attributeExplosiveDamageResonance)], 227 'normalAttributes': [const.attributeHp, const.attributeStructureDamageLimit]} 228 shipAttributes['capacitor'] = {'groupName': GetByLabel('UI/Fitting/FittingWindow/Capacitor'), 229 'normalAttributes': [const.attributeCapacitorCapacity, const.attributeRechargeRate]} 230 shipAttributes['navigation'] = {'groupName': GetByLabel('UI/Fitting/Navigation'), 231 'derivedHeaderAttribute': {'name': 'Tooltips/FittingWindow/AlignTime', 232 'format': 'UI/Fitting/FittingWindow/AlignTime', 233 'tooltip': 'Tooltips/FittingWindow/AlignTime_description', 234 'hint': '', 235 'valueFunc': GetAlignTimeFromAgilityAndMass, 236 'parameterAttributes': {'agility': const.attributeAgility, 237 'mass': const.attributeMass}}, 238 'normalAttributes': [const.attributeMaxVelocity, 239 const.attributeMass, 240 const.attributeAgility, 241 const.attributeBaseJumpBridgeCapacitorCost], 242 'constructedAttributes': [(const.attributeBaseWarpSpeed, lambda typeID, itemID: sm.GetService('info').GetWarpSpeedData(typeID, itemID))]} 243 shipAttributes['targeting'] = {'groupName': GetByLabel('UI/Fitting/FittingWindow/Targeting'), 244 'normalAttributes': [const.attributeMaxTargetRange, 245 const.attributeMaxRange, 246 const.attributeMaxLockedTargets, 247 const.attributeSignatureRadius, 248 const.attributeOptimalSigRadius, 249 const.attributeScanResolution, 250 const.attributeScanLadarStrength, 251 const.attributeScanMagnetometricStrength, 252 const.attributeScanRadarStrength, 253 const.attributeScanGravimetricStrength, 254 const.attributeProximityRange, 255 const.attributeFalloff, 256 const.attributeTrackingSpeed, 257 const.attributeMaxDirectionalScanRange]} 258 shipAttributes['drones'] = {'groupName': GetByLabel('UI/Drones/Drones'), 259 'normalAttributes': [const.attributeDroneCapacity, const.attributeDroneBandwidth]} 260 shipAttributes['inventory'] = {'groupName': GetByLabel('UI/Neocom/InventoryBtn'), 261 'normalAttributes': [const.attributeVolume, 262 const.attributeCapacity, 263 const.attributeFrigateEscapeBayCapacity, 264 const.attributeSpecialAmmoHoldCapacity, 265 const.attributeSpecialGasHoldCapacity, 266 const.attributeSpecialIceHoldCapacity, 267 const.attributeSpecialIndustrialShipHoldCapacity, 268 const.attributeSpecialLargeShipHoldCapacity, 269 const.attributeSpecialMediumShipHoldCapacity, 270 const.attributeSpecialMineralHoldCapacity, 271 const.attributeGeneralMiningHoldCapacity, 272 const.attributeSpecialAsteroidHoldCapacity, 273 const.attributeSpecialSalvageHoldCapacity, 274 const.attributeSpecialShipHoldCapacity, 275 const.attributeSpecialSmallShipHoldCapacity, 276 const.attributeSpecialCommandCenterHoldCapacity, 277 const.attributeSpecialPlanetaryCommoditiesHoldCapacity, 278 const.attributeSpecialSubsystemHoldCapacity, 279 const.attributeSpecialCorpseHoldCapacity, 280 const.attributeSpecialBoosterHoldCapacity, 281 const.attributeSpecialMobileDepotHoldCapacity, 282 const.attributeSpecialColonyResourcesHoldCapacity, 283 const.attributeSpecialExpeditionHoldCapacity]} 284 shipAttributes['ewar'] = {'groupName': GetByLabel('UI/Common/EWarResistances'), 285 'normalAttributes': [const.attributeECMResistance, 286 const.attributeRemoteAssistanceImpedance, 287 const.attributeRemoteRepairImpedance, 288 const.attributeEnergyWarfareResistance, 289 const.attributeSensorDampenerResistance, 290 const.attributeStasisWebifierResistance, 291 const.attributeTargetPainterResistance, 292 const.attributeWeaponDisruptionResistance]} 293 shipAttributes['sharedFacilities'] = {'groupName': GetByLabel('UI/InfoWindow/SharedFacilities'), 294 'normalAttributes': [const.attributeFleetHangarCapacity, 295 const.attributeShipMaintenanceBayCapacity, 296 const.attributeMaxJumpClones, 297 const.attributeReclonerFuelType]} 298 shipAttributes['fighterFacilities'] = {'groupName': GetByLabel('UI/InfoWindow/FighterFacilities'), 299 'normalAttributes': [const.attributeFighterCapacity, 300 const.attributeFighterTubes, 301 const.attributeFighterLightSlots, 302 const.attributeFighterSupportSlots, 303 const.attributeFighterHeavySlots, 304 const.attributeFighterStandupLightSlots, 305 const.attributeFighterStandupSupportSlots, 306 const.attributeFighterStandupHeavySlots]} 307 shipAttributes['onDeath'] = {'groupName': GetByLabel('UI/InfoWindow/OnDeath'), 308 'normalAttributes': [const.attributeOnDeathAOERadius, 309 const.attributeOnDeathSignatureRadius, 310 const.attributeOnDeathDamageEM, 311 const.attributeOnDeathDamageTherm, 312 const.attributeOnDeathDamageKin, 313 const.attributeOnDeathDamageExp]} 314 shipAttributes['jumpDrive'] = {'groupName': GetByLabel('UI/InfoWindow/JumpDriveSystems'), 315 'normalAttributes': [const.attributeJumpDriveCapacitorNeed, 316 const.attributeJumpDriveRange, 317 const.attributeJumpDriveConsumptionType, 318 const.attributeJumpDriveConsumptionAmount, 319 const.attributeJumpDriveDuration, 320 const.attributeJumpPortalCapacitorNeed, 321 const.attributeJumpPortalConsumptionMassFactor, 322 const.attributeJumpPortalDuration, 323 const.attributeSpecialFuelBayCapacity, 324 const.attributeGroupJumpDriveConsumptionAmount, 325 const.attributeConduitJumpPassengerCount]} 326 return shipAttributes 327 328 329 class CollapsibleGroupWithHeaderAttribute(CollapsibleGroup): 330 331 def ApplyAttributes(self, attributes): 332 self.headerAttributeLabel = attributes.get('headerAttributeLabel', None) 333 self.headerAttributeTooltip = attributes.get('headerAttributeTooltip', None) 334 self.headerAttributeValue = attributes.get('headerAttributeValue', None) 335 self.headerAttributeFormat = attributes.get('headerAttributeFormat', None) 336 super(CollapsibleGroupWithHeaderAttribute, self).ApplyAttributes(attributes) 337 338 def _construct_label(self): 339 super(CollapsibleGroupWithHeaderAttribute, self)._construct_label() 340 if not self.headerAttributeLabel: 341 return 342 headerAttributeCont = ContainerAutoSize(name='headerAttribContainer', parent=self.headerLabelWrapper, align=Align.TOLEFT, state=uiconst.UI_NORMAL, padLeft=8, hint=GetByLabel(self.headerAttributeTooltip)) 343 headerAttributeCont.OnClick = self.headerCont.OnClick 344 headerAttributeLabel = TextBody(parent=headerAttributeCont, align=Align.CENTERLEFT, state=uiconst.UI_DISABLED, color=TextColor.SECONDARY, text=u'{}:'.format(GetByLabel(self.headerAttributeLabel))) 345 headerValueLabel = TextBody(parent=headerAttributeCont, align=Align.CENTERLEFT, state=uiconst.UI_DISABLED, padLeft=headerAttributeLabel.width + 4, text=GetByLabel(self.headerAttributeFormat, value=self.headerAttributeValue)) 346 347 348 class ListEntryAttributeGroup(ContainerAutoSize): 349 350 def ApplyAttributes(self, attributes): 351 self.default_state = uiconst.UI_NORMAL 352 self.default_align = Align.TOTOP 353 self.default_padBottom = 2 354 self._hiliteFill = None 355 super(ListEntryAttributeGroup, self).ApplyAttributes(attributes) 356 self.itemID = attributes.itemID 357 self.attributeValues = attributes.attributeValues 358 self.modifiedAttributesDict = attributes.modifiedAttributesDict 359 self.labelCont = ContainerAutoSize(name='labelCont', parent=self, align=Align.TOTOP, padTop=8, padLeft=8) 360 self.label = TextBody(parent=self.labelCont, text=GetByLabel(attributes.labelPath)) 361 self.valueContainer = AttributeValueRowContainer(parent=self, align=Align.TOTOP, padding=(2, 2, 0, 2), doWidthAdjustments=True, loadOnStartup=False) 362 self.valueContainer.Load(self.attributeValues, mouseExitFunc=self.OnMouseExit, modifiedAttributesDict=self.modifiedAttributesDict, itemID=self.itemID) 363 364 def ConstructHiliteFill(self): 365 if not self._hiliteFill: 366 self._hiliteFill = ListEntryUnderlay(name='selectionHighlight', bgParent=self) 367 368 def ShowHilite(self, animate = True): 369 self.ConstructHiliteFill() 370 self._hiliteFill.set_hovered(True, animate) 371 372 def HideHilite(self, animate = True): 373 if self._hiliteFill: 374 self._hiliteFill.set_hovered(False, animate) 375 376 def OnMouseEnter(self, *args): 377 self.ShowHilite() 378 379 def OnMouseExit(self, *args): 380 self.HideHilite()