warningIconTooltip.py (18715B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\fittingScreen\warningIconTooltip.py 2 from collections import defaultdict 3 import evetypes 4 import inventorycommon 5 from carbonui.primitives.container import Container 6 from carbonui import const as uiconst 7 from carbonui.primitives.containerAutoSize import ContainerAutoSize 8 from carbonui.primitives.fill import Fill 9 from carbonui.primitives.sprite import Sprite 10 from carbonui.util.color import Color 11 from dogma.attributes.format import GetFormattedAttributeAndValue 12 from eve.client.script.ui.control.eveLabel import EveLabelMedium, EveHeaderLarge, EveLabelMediumBold 13 import shipfitting.fittingWarnings as fittingWarnings 14 import shipfitting.fittingWarningConst as fittingWarningConst 15 from eve.client.script.ui.shared.info.infoConst import TAB_TRAITS 16 from eve.client.script.ui.shared.neocom.skillConst import COLOR_SKILL_2 17 from fsdBuiltData.common.iconIDs import GetIconFile 18 from localization import GetByLabel 19 import dogma.data as dogma_data 20 ICON_SIZE = 20 21 22 def AddSlotsToWarningDict(warningSlotDict, warningID, updateSet): 23 warningLevel = fittingWarnings.GetWarningLevelFromWarningID(warningID) 24 warningSlotDict[warningLevel].update(updateSet) 25 26 27 def EvaluateFitAndPopulateTooltip(tooltipPanel, fittingController, warningLevel, fullVersion = False): 28 tooltipPanel.warningLevel = 0 29 tooltipPanel.Flush() 30 headerLabel = False 31 warningSlotDict = defaultdict(set) 32 fitResults = fittingWarnings.EvaluateFit(fittingController) 33 if fitResults is None: 34 return 35 fitResults = fittingWarnings.FilterResultsForWarningLevel(fitResults, [warningLevel]) 36 activeWarnings = fittingWarnings.GetActiveWarningsByLevelFromResults(fitResults) 37 if activeWarnings: 38 color = fittingWarnings.GetColorForLevel(warningLevel) 39 headerLabelPath = fittingWarnings.GetHeaderForLevel(warningLevel) 40 if headerLabelPath: 41 headerText = GetByLabel(headerLabelPath) 42 headerLabel = EveHeaderLarge(text=headerText) 43 headerLabel.SetRGBA(*color) 44 tooltipPanel.AddCell(headerLabel, colSpan=tooltipPanel.columns, cellPadding=(6, 4, 0, 4)) 45 currentWarningID = fittingWarningConst.WARNING_MISSING_SUBSYSTEMS 46 missingSubsystems = fitResults.get(currentWarningID, None) 47 if missingSubsystems: 48 AddWarningAndAddToSlotDict(tooltipPanel, currentWarningID, fullVersion, set(missingSubsystems), warningSlotDict) 49 if fullVersion: 50 AddSubsystemSlotsToTooltip(tooltipPanel, missingSubsystems) 51 currentWarningID = fittingWarningConst.WARNING_MODULES_IN_INVALID_FLAGS 52 modulesInInvalidSlots = fitResults.get(currentWarningID, None) 53 if modulesInInvalidSlots: 54 PrepareFlagsAndAddWarning(tooltipPanel, currentWarningID, fullVersion, warningSlotDict, modulesInInvalidSlots) 55 currentWarningID = fittingWarningConst.WARNING_OVER_CPU 56 if fitResults.get(currentWarningID, None): 57 AddWarningAndAddToSlotDict(tooltipPanel, currentWarningID, fullVersion, {-currentWarningID}, warningSlotDict) 58 currentWarningID = fittingWarningConst.WARNING_OVER_POWERGRID 59 if fitResults.get(currentWarningID, None): 60 semiflagIDs = {-currentWarningID} 61 AddWarningAndAddToSlotDict(tooltipPanel, currentWarningID, fullVersion, semiflagIDs, warningSlotDict) 62 currentWarningID = fittingWarningConst.WARNING_OVER_CALIBRATION 63 if fitResults.get(currentWarningID, None): 64 semiflagIDs = set(const.rigSlotFlags) 65 AddWarningAndAddToSlotDict(tooltipPanel, currentWarningID, fullVersion, semiflagIDs, warningSlotDict) 66 currentWarningID = fittingWarningConst.WARNING_OVERLOADED_CARGO 67 if fitResults.get(currentWarningID, None): 68 flagIDs = [const.flagCargo] 69 AddWarningAndAddToSlotDict(tooltipPanel, currentWarningID, fullVersion, flagIDs, warningSlotDict) 70 for currentWarningID in [fittingWarningConst.WARNING_DUAL_TANKED, fittingWarningConst.WARNING_MULTI_TANKED]: 71 tankingModules = fitResults.get(currentWarningID, None) 72 if tankingModules: 73 flagIDs = {x[1] for x in tankingModules} 74 AddSlotsToWarningDict(warningSlotDict, currentWarningID, flagIDs) 75 AddWarning(tooltipPanel, currentWarningID, fullVersion, flagIDs) 76 77 for currentWarningID in [fittingWarningConst.WARNING_ARMOR_TANKED_SHIELD_SHIP, fittingWarningConst.WARNING_SHIELD_TANKED_ARMOR_SHIP]: 78 wrongModules = fitResults.get(currentWarningID, None) 79 if wrongModules: 80 PrepareFlagsAndAddWarning(tooltipPanel, currentWarningID, fullVersion, warningSlotDict, wrongModules) 81 82 currentWarningID = fittingWarningConst.WARNING_NOT_PROVIDING_BONUS 83 notProvidingBonus = fitResults.get(currentWarningID, None) 84 if notProvidingBonus: 85 PrepareFlagsAndAddWarning(tooltipPanel, currentWarningID, fullVersion, warningSlotDict, notProvidingBonus) 86 if fullVersion: 87 AddModuleRows(tooltipPanel, notProvidingBonus, currentWarningID) 88 currentWarningID = fittingWarningConst.WARNING_MIXING_TURRET_GROUPS 89 mixedTurrets = fitResults.get(currentWarningID, None) 90 if mixedTurrets: 91 flagIDs = set() 92 for each in mixedTurrets.itervalues(): 93 flagIDs.update({x[1] for x in each}) 94 95 AddWarningAndAddToSlotDict(tooltipPanel, currentWarningID, fullVersion, flagIDs, warningSlotDict) 96 if fullVersion: 97 AddTurretOrLauncherGroups(tooltipPanel, mixedTurrets, currentWarningID) 98 currentWarningID = fittingWarningConst.WARNING_MIXING_LAUNCHER_GROUPS 99 mixedLaunchers = fitResults.get(currentWarningID, None) 100 if mixedLaunchers: 101 flagIDs = set() 102 for each in mixedLaunchers.itervalues(): 103 flagIDs.update({x[1] for x in each}) 104 105 AddWarningAndAddToSlotDict(tooltipPanel, currentWarningID, fullVersion, flagIDs, warningSlotDict) 106 if fullVersion: 107 AddTurretOrLauncherGroups(tooltipPanel, mixedLaunchers, currentWarningID) 108 currentWarningID = fittingWarningConst.WARNING_MIXING_TURRET_SIZES 109 mixedTurretSizes = fitResults.get(currentWarningID, None) 110 if mixedTurretSizes: 111 flagIDs = set() 112 for each in mixedTurretSizes.itervalues(): 113 flagIDs.update({x[1] for x in each}) 114 115 AddWarningAndAddToSlotDict(tooltipPanel, currentWarningID, fullVersion, flagIDs, warningSlotDict) 116 if fullVersion: 117 AddTurretSizes(tooltipPanel, mixedTurretSizes, currentWarningID) 118 currentWarningID = fittingWarningConst.WARNING_OFFLINE_MODULES 119 offlineModules = fitResults.get(currentWarningID, None) 120 if offlineModules: 121 PrepareFlagsAndAddWarning(tooltipPanel, currentWarningID, fullVersion, warningSlotDict, offlineModules) 122 if fullVersion: 123 AddModuleRows(tooltipPanel, offlineModules, currentWarningID) 124 currentWarningID = fittingWarningConst.WARNING_POLARIZED_WEAPONS 125 polarizedWeapons = fitResults.get(currentWarningID, None) 126 if polarizedWeapons: 127 PrepareFlagsAndAddWarning(tooltipPanel, currentWarningID, fullVersion, warningSlotDict, polarizedWeapons) 128 for currentWarningID in [fittingWarningConst.WARNING_MISSING_REQ_CHARGES, fittingWarningConst.WARNING_MISSING_OPTIONAL_CHARGES]: 129 missingCharges = fitResults.get(currentWarningID, None) 130 if missingCharges: 131 PrepareFlagsAndAddWarning(tooltipPanel, currentWarningID, fullVersion, warningSlotDict, missingCharges) 132 133 currentWarningID = fittingWarningConst.WARNING_UNDERSIZED_PROP_MOD 134 undersizedPropMods = fitResults.get(currentWarningID, None) 135 if undersizedPropMods: 136 PrepareFlagsAndAddWarning(tooltipPanel, currentWarningID, fullVersion, warningSlotDict, undersizedPropMods) 137 currentWarningID = fittingWarningConst.WARNING_INEFFICIENT_PROP_MOD 138 inefficientPropMods = fitResults.get(currentWarningID, None) 139 if inefficientPropMods: 140 PrepareFlagsAndAddWarning(tooltipPanel, currentWarningID, fullVersion, warningSlotDict, inefficientPropMods) 141 for currentWarningID in [fittingWarningConst.WARNING_STACKING_PENALTY_MED, fittingWarningConst.WARNING_STACKING_PENALTY_LOW, fittingWarningConst.WARNING_STACKING_PENALTY_TARGETED_LOW]: 142 stackingPenalty = fitResults.get(currentWarningID, None) 143 if stackingPenalty: 144 flagIDs = set() 145 for each in stackingPenalty.itervalues(): 146 flagIDs.update({x[1] for x in each}) 147 148 AddSlotsToWarningDict(warningSlotDict, currentWarningID, flagIDs) 149 AddWarning(tooltipPanel, currentWarningID, fullVersion, flagIDs) 150 if fullVersion: 151 AddAttributes(tooltipPanel, stackingPenalty, currentWarningID) 152 153 currentWarningID = fittingWarningConst.WARNING_DISABLED_BUBBLE_IMMUNITY 154 modulesDisablingBubbleImmunity = fitResults.get(currentWarningID, None) 155 if modulesDisablingBubbleImmunity: 156 PrepareFlagsAndAddWarning(tooltipPanel, currentWarningID, fullVersion, warningSlotDict, modulesDisablingBubbleImmunity) 157 slotsLevelLow = warningSlotDict[fittingWarningConst.WARNING_LEVEL_LOW] 158 slotsLevelMedium = warningSlotDict[fittingWarningConst.WARNING_LEVEL_MEDIUM] 159 slotsLevelHigh = warningSlotDict[fittingWarningConst.WARNING_LEVEL_HIGH] 160 slotsLevelLow = slotsLevelLow - slotsLevelMedium - slotsLevelHigh 161 slotsLevelMedium = slotsLevelMedium - slotsLevelHigh 162 warningSlotDict = {x:fittingWarningConst.WARNING_LEVEL_HIGH for x in slotsLevelHigh} 163 warningSlotDict.update({x:fittingWarningConst.WARNING_LEVEL_MEDIUM for x in slotsLevelMedium}) 164 warningSlotDict.update({x:fittingWarningConst.WARNING_LEVEL_LOW for x in slotsLevelLow}) 165 fittingController.ChangeFittingWarningDisplay(warningSlotDict) 166 if headerLabel and headerLabel.parent: 167 cell = headerLabel.parent 168 cell.state = uiconst.UI_NORMAL 169 cell.OnMouseEnter = (OnMouseEnterContainer, warningSlotDict) 170 cell.OnMouseExit = OnMouseExitContainer 171 172 173 def PrepareFlagsAndAddWarning(tooltipPanel, currentWarningID, fullVersion, flagIDsDict, notProvidingBonus): 174 flagIDs = {x[1] for x in notProvidingBonus} 175 AddWarningAndAddToSlotDict(tooltipPanel, currentWarningID, fullVersion, flagIDs, flagIDsDict) 176 177 178 def AddWarningAndAddToSlotDict(tooltipPanel, currentWarningID, fullVersion, flagIDs, warningSlotDict): 179 AddWarning(tooltipPanel, currentWarningID, fullVersion, flagIDs) 180 AddSlotsToWarningDict(warningSlotDict, currentWarningID, flagIDs) 181 182 183 def AddWarning(tooltipPanel, warningID, fullVersion = False, flagIDs = ()): 184 warningLevel, textPath, _ = fittingWarningConst.warningsByWarningID[warningID] 185 color = fittingWarnings.GetColorForLevel(warningLevel) 186 hint = GetQuestionMarkHint(warningID) 187 faintColor = color[:3] + (0.25,) 188 row = tooltipPanel.AddRow() 189 row.OnMouseEnter = (OnMouseEnterContainer, {flagID:warningLevel for flagID in flagIDs}) 190 row.OnMouseExit = OnMouseExitContainer 191 row.state = uiconst.UI_NORMAL 192 row.hint = hint 193 tooltipPanel.warningLevel = max(tooltipPanel.warningLevel, warningLevel) 194 tooltipPanel.FillRow() 195 iconObj = Sprite(pos=(0, 196 0, 197 ICON_SIZE, 198 ICON_SIZE), align=uiconst.CENTERLEFT) 199 row.AddCell(iconObj, cellPadding=(0, 0, 10, 0)) 200 iconObj.LoadIcon(fittingWarningConst.WARNING_PATH, ignoreSize=True) 201 iconObj.SetRGBA(*color) 202 labelColSpan = tooltipPanel.columns - 1 - bool(fullVersion) 203 label = EveLabelMediumBold(text=GetByLabel(textPath), align=uiconst.CENTERLEFT, bold=True, width=350, autoFitToText=True) 204 cell = row.AddCell(label, cellPadding=(6, 4, 0, 4), colSpan=labelColSpan) 205 if fullVersion: 206 questionmarkLabel = EveLabelMedium(name='questionMark', text='?', align=uiconst.CENTERRIGHT, bold=True) 207 cell = row.AddCell(questionmarkLabel, cellPadding=(6, 0, 6, 0), colSpan=labelColSpan) 208 questionmarkLabel.SetRGBA(*color) 209 210 211 def GetQuestionMarkHint(warningID): 212 _, _, hintPath = fittingWarningConst.warningsByWarningID[warningID] 213 if warningID in (fittingWarningConst.WARNING_ARMOR_TANKED_SHIELD_SHIP, fittingWarningConst.WARNING_SHIELD_TANKED_ARMOR_SHIP, fittingWarningConst.WARNING_WRONG_TANKING): 214 fittingController = sm.GetService('ghostFittingSvc').GetGhostFittingController() 215 hint = GetByLabel(hintPath, shipTypeID=fittingController.GetTypeID()) 216 elif warningID in (fittingWarningConst.WARNING_OVER_CPU_POWER, fittingWarningConst.WARNING_OVER_CPU, fittingWarningConst.WARNING_OVER_POWERGRID): 217 hint = GetByLabel(hintPath, cpuMgmtLink=__GetSkillText(const.typeElectronics), weaponUpgradesLink=__GetSkillText(const.typeWeaponUpgrades), advancedWeaponUpgradesLink=__GetSkillText(const.typeAdvancedWeaponUpgrades), powerGridMgmtLink=__GetSkillText(const.typeEngineering)) 218 else: 219 hint = GetByLabel(hintPath) if hintPath else None 220 return hint 221 222 223 def __GetSkillText(skillTypeID): 224 skillName = evetypes.GetName(skillTypeID) 225 color = Color.RGBtoHex(*COLOR_SKILL_2) 226 return '<font color=%s><b>%s</b></font>' % (color, skillName) 227 228 229 def AddModuleRows(tooltipPanel, modules, warningID): 230 warningLevel = fittingWarnings.GetWarningLevelFromWarningID(warningID) 231 sortedModules = sorted(modules, key=lambda x: const.moduleSlotFlags.index(x[1])) 232 for eachTypeID, eachFlagID in sortedModules: 233 texturePath = inventorycommon.typeHelpers.GetIconFile(eachTypeID) 234 cell = _AddRowForGroupingAndItsWeapons(tooltipPanel, evetypes.GetName(eachTypeID), texturePath, [(eachTypeID, eachFlagID)], warningLevel) 235 cell.GetMenu = lambda *args: sm.GetService('menu').GetMenuFromItemIDTypeID(itemID=None, typeID=eachTypeID) 236 237 238 def AddTurretOrLauncherGroups(tooltipPanel, mixedTurrets, warningID): 239 weaponGroupsAndNames = [ (groupID, evetypes.GetGroupNameByGroup(groupID)) for groupID, weapons in mixedTurrets.iteritems() if weapons ] 240 weaponGroupsAndNames.sort(key=lambda x: x[1]) 241 warningLevel = fittingWarnings.GetWarningLevelFromWarningID(warningID) 242 for eachGroup, eachGroupName in weaponGroupsAndNames: 243 weapons = mixedTurrets[eachGroup] 244 texturePath = fittingWarnings.GetIconPathForTurretGroup(eachGroup) 245 _AddRowForGroupingAndItsWeapons(tooltipPanel, eachGroupName, texturePath, weapons, warningLevel) 246 247 248 def AddTurretSizes(tooltipPanel, turretSizes, warningID): 249 sizeAttributeInUse = turretSizes.keys() 250 sizeAttributeInUse.sort() 251 warningLevel = fittingWarnings.GetWarningLevelFromWarningID(warningID) 252 for eachSize in sizeAttributeInUse: 253 turrets = turretSizes[eachSize] 254 groupingName = GetValueName(const.attributeChargeSize, eachSize) 255 texturePath = fittingWarnings.GetIconPathForSizes(eachSize) 256 _AddRowForGroupingAndItsWeapons(tooltipPanel, groupingName, texturePath, turrets, warningLevel) 257 258 259 def AddAttributes(tooltipPanel, attributeInfo, warningID): 260 attributesByModules = defaultdict(list) 261 for k, v in attributeInfo.iteritems(): 262 attributesByModules[tuple(v)].append(k) 263 264 for v in attributesByModules.itervalues(): 265 v.sort(key=lambda x: dogma_data.get_attribute_display_name(x[0])) 266 267 sortedAttributes = [ (dogma_data.get_attribute_display_name(x[0]), x[0], y) for x, y in attributeInfo.iteritems() ] 268 sortedAttributes.sort() 269 warningLevel = fittingWarnings.GetWarningLevelFromWarningID(warningID) 270 attributeAdded = defaultdict(list) 271 for moduleInfoList, attrList in attributesByModules.iteritems(): 272 sortedModuleList = sorted(moduleInfoList) 273 for attributeID, op, skillTypeID, domain in attrList: 274 attrText = dogma_data.get_attribute_display_name(attributeID) 275 if skillTypeID: 276 attrText = '%s<br>%s' % (attrText, GetByLabel('UI/Fitting/FittingWindow/Warnings/ForEquipmentRequiringSkill', skillName=evetypes.GetName(skillTypeID))) 277 modulesAlreadyAddedForAttrName = attributeAdded.get(attrText.lower(), []) 278 if sortedModuleList in modulesAlreadyAddedForAttrName: 279 continue 280 attributeAdded[attrText.lower()].append(sortedModuleList) 281 iconID = dogma_data.get_attribute_icon_id(attributeID) 282 iconFile = GetIconFile(iconID) 283 _AddRowForGroupingAndItsWeapons(tooltipPanel, attrText, iconFile, moduleInfoList, warningLevel) 284 285 286 def _AddRowForGroupingAndItsWeapons(tooltipPanel, groupingName, texturePath, itemTypes, warningLevel, addExtraTypeText = False): 287 typeIDs = {typeID for typeID, flagID in itemTypes} 288 flagIDs = {flagID for typeID, flagID in itemTypes} 289 if addExtraTypeText: 290 typeNames = [ evetypes.GetName(typeID) for typeID in typeIDs ] 291 typeNames.sort() 292 typeText = ', '.join(typeNames[:2]) 293 if len(typeNames) > 2: 294 typeText += '...' 295 text = '%s (%s)' % (groupingName, typeText) 296 else: 297 text = groupingName 298 tooltipPanel.FillRow() 299 tooltipPanel.AddCell() 300 c = Container(height=ICON_SIZE, align=uiconst.CENTERLEFT, state=uiconst.UI_NORMAL) 301 c.flagIDs = flagIDs 302 c.OnMouseEnter = (OnMouseEnterContainer, {flagID:warningLevel for _, flagID in itemTypes}) 303 c.OnMouseExit = OnMouseExitContainer 304 iconObj = Sprite(parent=c, pos=(0, 305 0, 306 ICON_SIZE, 307 ICON_SIZE), align=uiconst.CENTERLEFT, texturePath=texturePath) 308 l = EveLabelMedium(parent=c, align=uiconst.CENTERLEFT, left=ICON_SIZE + 2, text=text) 309 c.width = l.left + l.textwidth 310 c.height = max(c.height, l.height + 4) 311 tooltipPanel.AddCell(cellObject=c, colSpan=tooltipPanel.columns - 1) 312 return c 313 314 315 def OnMouseEnterContainer(warningSlotDict): 316 if warningSlotDict: 317 fittingController = sm.GetService('ghostFittingSvc').GetGhostFittingController() 318 fittingController.ChangeFittingWarningDisplay(warningSlotDict) 319 320 321 def OnMouseExitContainer(*args): 322 fittingController = sm.GetService('ghostFittingSvc').GetGhostFittingController() 323 fittingController.ChangeFittingWarningDisplay({}) 324 325 326 def AddSubsystemSlotsToTooltip(tooltipPanel, missingSubsystems): 327 for eachFlagID in missingSubsystems: 328 groupID, iconPath = fittingWarningConst.SUBSYSTEM_INFO_BY_SLOT[eachFlagID] 329 groupName = evetypes.GetGroupNameByGroup(groupID) 330 tooltipPanel.FillRow() 331 tooltipPanel.AddCell() 332 c = ContainerAutoSize(height=ICON_SIZE) 333 iconObj = Sprite(parent=c, pos=(0, 334 0, 335 ICON_SIZE, 336 ICON_SIZE), align=uiconst.CENTERLEFT, texturePath=iconPath) 337 EveLabelMedium(parent=c, align=uiconst.CENTERLEFT, left=30, text=groupName) 338 tooltipPanel.AddCell(cellObject=c, colSpan=tooltipPanel.columns - 1) 339 340 341 def GetValueName(attributeID, value): 342 formatInfo = GetFormattedAttributeAndValue(attributeID, value) 343 return formatInfo.value