industryTooltips.py (36939B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\industry\views\industryTooltips.py 2 from collections import defaultdict 3 import math 4 from carbonui import const as uiconst, fontconst, TextColor 5 from carbonui.primitives.fill import Fill 6 from eve.client.script.ui.control.entries.item import Item 7 from eve.client.script.ui.control.entries.util import GetFromClass 8 from menu import MenuLabel 9 from carbonui.control.scrollContainer import ScrollContainer 10 from carbonui.primitives.containerAutoSize import ContainerAutoSize 11 from carbonui.primitives.frame import Frame 12 from carbonui.primitives.sprite import Sprite 13 from carbonui.primitives.transform import Transform 14 from carbonui.util.color import Color 15 from dogma.const import attributeManufactureSlotLimit, attributeMaxLaborotorySlots, attributeReactionSlotLimit 16 from eve.client.script.ui.control.itemIcon import ItemIcon 17 from eve.client.script.ui.control.eveLabel import EveLabelMedium, Label, EveHeaderMedium, EveHeaderLarge 18 from eve.client.script.ui.control.eveScroll import Scroll 19 from eve.client.script.ui.control.themeColored import FillThemeColored 20 from eve.client.script.ui.shared.cloneGrade import ORIGIN_INDUSTRY 21 from eve.client.script.ui.shared.cloneGrade.omegaTooltipPanelCell import OmegaTooltipPanelCell 22 from eve.client.script.ui.shared.industry import industryUIConst 23 from eve.client.script.ui.shared.industry.systemCostIndexGauge import SystemCostIndexGauge 24 from eve.client.script.ui.shared.industry.views.errorFrame import ErrorFrame 25 from eve.client.script.ui.shared.industry.views.industryCaptionLabel import IndustryCaptionLabel 26 from eve.client.script.ui.shared.shipTree.infoBubble import SkillEntry 27 from eve.common.script.util import industryCommon 28 from eve.common.script.util.eveFormat import FmtISK 29 import evetypes 30 import industry 31 from inventorycommon import const 32 import localization 33 from localization import GetByLabel 34 from localization.formatters import FormatNumeric 35 from carbonui.primitives.container import Container 36 from eveservices.menu import GetMenuService 37 import structures 38 from eve.client.script.ui import eveColor 39 from omega.client.clone_grade_svc import get_clone_grade_svc 40 from security.common.const import INDUSTRY_SECURITY_TAX_RATE 41 MARGIN = (8, 8, 8, 0) 42 PADBOTTOM = (0, 0, 0, 8) 43 44 def AddMaterialGroupRow(materialGroupID, panel): 45 cont = ContainerAutoSize(align=uiconst.TOPLEFT) 46 icon = Sprite(parent=cont, align=uiconst.TOPLEFT, texturePath=industryUIConst.ICON_BY_INDUSTRYGROUP[materialGroupID], pos=(4, 0, 12, 12), color=industryUIConst.COLOR_FRAME) 47 label = IndustryCaptionLabel(parent=cont, align=uiconst.TOPLEFT, text=localization.GetByLabel(industryUIConst.LABEL_BY_INDUSTRYGROUP[materialGroupID]), left=24) 48 panel.AddCell(cont, colSpan=3, cellPadding=(0, 0, 0, 5)) 49 50 51 def AddItemRow(panel, materialData): 52 panel.AddCell(MaterialIconAndLabel(materialData=materialData), cellPadding=(0, 0, 0, 3)) 53 available = FormatNumeric(materialData.available, useGrouping=True) 54 quantity = FormatNumeric(materialData.quantity, useGrouping=True) 55 color = industryUIConst.COLOR_NOTREADY if materialData.errors else industryUIConst.COLOR_READY 56 colorHex = Color.RGBtoHex(*color) 57 label = EveLabelMedium(align=uiconst.CENTERRIGHT, text='<color=%s>%s / %s' % (colorHex, available, quantity)) 58 panel.AddCell(label, cellPadding=(8, 0, 0, 3)) 59 60 61 def AddOutcomeRow(panel, product): 62 panel.AddCell(MaterialIconAndLabel(materialData=product), cellPadding=(0, 0, 0, 0)) 63 label = EveLabelMedium(align=uiconst.CENTERRIGHT, text='x %s' % product.quantity) 64 panel.AddCell(label, cellPadding=(8, 0, 0, 0)) 65 panel.AddSpacer(width=0, height=8, colSpan=2) 66 67 68 def AddPriceRow(panel, price): 69 if not price: 70 iskPrice = localization.GetByLabel('UI/Inventory/PriceUnavailable') 71 else: 72 iskPrice = FmtISK(price) 73 label = EveLabelMedium(text=localization.GetByLabel('UI/Industry/TotalEstimatedPrice'), color=Color.GRAY) 74 panel.AddCell(label) 75 label = EveLabelMedium(align=uiconst.TOPRIGHT, text=iskPrice) 76 panel.AddCell(label, cellPadding=(8, 0, 0, 0)) 77 panel.AddCell(cellPadding=PADBOTTOM, colSpan=2) 78 79 80 def AddVolumeRow(panel, value): 81 label = EveLabelMedium(text=localization.GetByLabel('UI/Common/Volume'), color=Color.GRAY) 82 panel.AddCell(label) 83 text = localization.GetByLabel('UI/Inventory/ContainerCapacity', capacity=value) 84 label = EveLabelMedium(align=uiconst.TOPRIGHT, text=text) 85 panel.AddCell(label, cellPadding=(8, 0, 0, 0)) 86 panel.AddCell(cellPadding=PADBOTTOM, colSpan=2) 87 88 89 def AddTypeBonusRow(panel, text, bonusME = None, bonusTE = None): 90 label = EveLabelMedium(text=text, color=Color.GRAY) 91 panel.AddCell(label) 92 if bonusME: 93 label = EveLabelMedium(align=uiconst.TOPRIGHT, text=bonusME) 94 panel.AddCell(label, cellPadding=(8, 0, 0, 0)) 95 if bonusTE: 96 label = EveLabelMedium(align=uiconst.TOPRIGHT, text=bonusTE) 97 panel.AddCell(label, cellPadding=(8, 0, 0, 0)) 98 panel.FillRow() 99 panel.AddCell(cellPadding=PADBOTTOM, colSpan=2) 100 101 102 def AddDescriptionRow(panel, text, cellPadding = PADBOTTOM): 103 if text: 104 description = EveLabelMedium(text=text, color=Color.GRAY, align=uiconst.TOTOP) 105 panel.AddCell(description, colSpan=2, cellPadding=cellPadding) 106 107 108 def AddSkillRow(panel, typeID, level = None, cellPadding = PADBOTTOM): 109 if level is None: 110 showLevel = False 111 level = 1 112 else: 113 showLevel = True 114 panel.AddRow(rowClass=SkillEntry, typeID=typeID, level=level, showLevel=showLevel) 115 116 117 def AddErrorRow(panel, error, errorArgs): 118 text = industryCommon.GetErrorLabel(error, *errorArgs) 119 if not text: 120 text = error.name 121 description = EveLabelMedium(text=text, align=uiconst.TOPLEFT) 122 cell = panel.AddCell(description, colSpan=2, cellPadding=(8, 4, 8, 4)) 123 frame = ErrorFrame(bgParent=cell) 124 frame.Show() 125 126 127 def AddModifierRow(name, value, panel, hint = None): 128 state = uiconst.UI_NORMAL if hint else uiconst.UI_DISABLED 129 label = panel.AddLabelMedium(text=name, align=uiconst.TOPLEFT, cellPadding=(0, 0, 0, 2), state=state) 130 label.hint = hint 131 panel.AddLabelMedium(text=value, align=uiconst.TOPRIGHT, cellPadding=(12, 0, 0, 2)) 132 133 134 def AddModifierRows(caption, modifiers, panel): 135 label = IndustryCaptionLabel(text=caption, width=220) 136 panel.AddCell(label, colSpan=panel.columns, cellPadding=(0, 0, 0, 2)) 137 for modifier in modifiers: 138 AddModifierRow(modifier.GetName(), modifier.GetPercentageLabel(), panel) 139 140 141 def AddJobModifierRows(panel, modifierCls, jobData): 142 modifiers = jobData.GetModifiers(modifierCls) 143 if not modifiers: 144 return 145 caption = jobData.GetModifierCaption(modifierCls) 146 AddModifierRows(caption, modifiers, panel) 147 panel.AddSpacer(0, 6, colSpan=2) 148 149 150 def AddSystemCostIndexRow(activityID, facilityData, tooltipPanel, cellPadding = (8, 0, 0, 8)): 151 text = '<color=gray>' + localization.GetByLabel('UI/Industry/SystemCostIndex') 152 tooltipPanel.AddLabelMedium(text=text, align=uiconst.TOPLEFT, cellPadding=(0, 0, 0, 0)) 153 height = 13 154 gauge = SystemCostIndexGauge(gaugeHeight=height, align=uiconst.TOPRIGHT, pos=(0, 155 2, 156 50, 157 height), facilityData=facilityData, activityID=activityID) 158 tooltipPanel.AddCell(gauge, cellPadding=cellPadding) 159 160 161 def AddTaxRateRows(panel, taxRates): 162 for serviceID, taxRate in taxRates.iteritems(): 163 if taxRate is None: 164 continue 165 text = '<color=gray>%s %s:' % (localization.GetByLabel(structures.GetServiceLabel(serviceID)), localization.GetByLabel('UI/Industry/Tax')) 166 panel.AddLabelMedium(text=text, align=uiconst.TOPLEFT, cellPadding=(0, 0, 0, 0)) 167 color = '<color=red>' if taxRate > 0 else '<color=green>' 168 panel.AddLabelSmall(text='%s%.2f%%' % (color, taxRate), align=uiconst.TOPRIGHT, cellPadding=(0, 0, 0, 0)) 169 170 171 class MaterialTooltipPanel: 172 173 def __init__(self, jobData, materialData, tooltipPanel): 174 self.jobData = jobData 175 self.materialData = materialData 176 self.tooltipPanel = tooltipPanel 177 tooltipPanel.margin = MARGIN 178 tooltipPanel.columns = 2 179 self.Reconstruct() 180 self.jobData.on_updated.connect(self.Reconstruct) 181 182 def Reconstruct(self, *args): 183 if self.tooltipPanel.destroyed: 184 return 185 self.tooltipPanel.Flush() 186 AddItemRow(self.tooltipPanel, self.materialData) 187 self.tooltipPanel.AddCell(cellPadding=(0, 0, 0, 4), colSpan=2) 188 price = self.materialData.GetEstimatedUnitPrice() * self.materialData.quantity 189 AddPriceRow(self.tooltipPanel, price) 190 191 192 class OutcomeTooltipPanel: 193 194 def __init__(self, jobData, tooltipPanel): 195 self.jobData = jobData 196 self.tooltipPanel = tooltipPanel 197 tooltipPanel.state = uiconst.UI_NORMAL 198 tooltipPanel.margin = MARGIN 199 tooltipPanel.columns = 2 200 if self.jobData.IsProductSelectable() and not self.jobData.IsInstalled(): 201 AddDescriptionRow(self.tooltipPanel, GetByLabel('UI/Industry/SelectOutcome')) 202 scroll = Scroll(align=uiconst.TOPLEFT, width=250) 203 scroll.OnSelectionChange = self.OnScrollSelectionChange 204 scrollList = self.GetScrollContent() 205 scroll.Load(contentList=scrollList) 206 scroll.ScrollToSelectedNode() 207 scroll.height = min(len(scrollList) * 29 + 2, 200) 208 scroll.Confirm = self.Confirm 209 self.tooltipPanel.AddCell(scroll, colSpan=3, cellPadding=PADBOTTOM) 210 else: 211 AddOutcomeRow(self.tooltipPanel, self.jobData.product) 212 price = self.jobData.product.GetEstimatedUnitPrice() * self.jobData.product.quantity 213 AddPriceRow(self.tooltipPanel, price) 214 if hasattr(self.jobData.product, 'GetPackagedVolume'): 215 volume = self.jobData.product.GetPackagedVolume() * self.jobData.product.quantity 216 AddVolumeRow(self.tooltipPanel, volume) 217 218 def GetScrollContent(self): 219 entries = [] 220 for product in self.jobData.products: 221 entry = GetFromClass(Item, {'typeID': product.typeID, 222 'label': evetypes.GetName(product.typeID), 223 'getIcon': True, 224 'isCopy': not product.original, 225 'hint': evetypes.GetDescription(product.typeID), 226 'isSelected': self.jobData.GetProductTypeID() == product.typeID, 227 'OnDblClick': self.OnNodeDblClick}) 228 entries.append(entry) 229 230 entries = sorted(entries, key=lambda x: (x.typeID is not None, x.label)) 231 return entries 232 233 def Confirm(self, *args): 234 self.tooltipPanel.Close() 235 236 def OnNodeDblClick(self, node): 237 self.tooltipPanel.Close() 238 239 def OnScrollSelectionChange(self, nodes): 240 if not nodes: 241 return 242 self.jobData.product = nodes[0].typeID 243 244 245 class MaterialGroupTooltipPanel: 246 247 def __init__(self, materialsByGroupID, tooltipPanel, jobData): 248 tooltipPanel.margin = MARGIN 249 tooltipPanel.state = uiconst.UI_NORMAL 250 tooltipPanel.columns = 2 251 self.materialsByGroupID = materialsByGroupID 252 self.jobData = jobData 253 self.tooltipPanel = tooltipPanel 254 self.Reconstruct() 255 self.jobData.on_updated.connect(self.Reconstruct) 256 257 def Reconstruct(self, *args): 258 if self.tooltipPanel.destroyed: 259 return 260 self.tooltipPanel.Flush() 261 for materialGroupID, materials in self.materialsByGroupID: 262 AddMaterialGroupRow(materialGroupID, self.tooltipPanel) 263 materials = filter(lambda m: m.typeID is not None, materials) 264 if materials: 265 materials.sort(key=lambda x: x.GetName()) 266 for materialData in materials: 267 AddItemRow(self.tooltipPanel, materialData) 268 269 self.tooltipPanel.AddCell(cellPadding=(0, 0, 0, 10), colSpan=2) 270 else: 271 label = EveLabelMedium(align=uiconst.CENTERLEFT, left=16, text=localization.GetByLabel('UI/Industry/NoItemSelected')) 272 self.tooltipPanel.AddCell(label, cellPadding=(8, 0, 0, 10), colSpan=2) 273 274 estPrice, volume = self.GetTotalEstimatedPriceAndVolume() 275 AddPriceRow(self.tooltipPanel, estPrice) 276 AddVolumeRow(self.tooltipPanel, volume) 277 AddJobModifierRows(self.tooltipPanel, industry.MaterialModifier, self.jobData) 278 279 def GetTotalEstimatedPriceAndVolume(self): 280 totalPrice = 0.0 281 totalVolume = 0.0 282 for _, materials in self.materialsByGroupID: 283 for material in materials: 284 if material.typeID: 285 totalPrice += material.GetEstimatedUnitPrice() * material.quantity 286 totalVolume += material.GetPackagedVolume() * material.quantity 287 288 return (totalPrice, totalVolume) 289 290 291 class MaterialIconAndLabel(ContainerAutoSize): 292 default_state = uiconst.UI_NORMAL 293 294 def ApplyAttributes(self, attributes): 295 ContainerAutoSize.ApplyAttributes(self, attributes) 296 self.materialData = attributes.materialData 297 if isinstance(self.materialData, industry.Blueprint): 298 bpData = self.materialData 299 else: 300 bpData = None 301 icon = ItemIcon(parent=self, align=uiconst.CENTERLEFT, state=uiconst.UI_DISABLED, pos=(0, 0, 20, 20), typeID=self.materialData.typeID, bpData=bpData, showOmegaOverlay=False) 302 label = EveLabelMedium(parent=self, align=uiconst.CENTERLEFT, text=self.materialData.GetName(), left=24) 303 304 def GetMenu(self): 305 menu = GetMenuService().GetMenuFromItemIDTypeID(None, self.materialData.typeID, includeMarketDetails=True) 306 menu.insert(0, (MenuLabel('UI/Inventory/ItemActions/BuyThisType'), GetMenuService().QuickBuy, (self.materialData.typeID, self.materialData.missing))) 307 return menu 308 309 def GetHint(self): 310 return evetypes.GetDescription(self.materialData.typeID) 311 312 313 class SkillTooltipPanel: 314 315 def __init__(self, skills, tooltipPanel): 316 tooltipPanel.margin = 8 317 tooltipPanel.state = uiconst.UI_NORMAL 318 tooltipPanel.columns = 2 319 self.tooltipPanel = tooltipPanel 320 if not skills: 321 description = EveLabelMedium(text=localization.GetByLabel('UI/Industry/NoSkillRequirements'), color=Color.GRAY, align=uiconst.TOPLEFT) 322 tooltipPanel.AddCell(description, colSpan=2, cellPadding=(0, 0, 0, 8)) 323 return 324 AddDescriptionRow(tooltipPanel, localization.GetByLabel('UI/Industry/RequiredSkills'), cellPadding=(0, 0, 0, 2)) 325 for typeID, level in skills: 326 AddSkillRow(tooltipPanel, typeID, level, cellPadding=(0, 0, 0, 1)) 327 328 if self.IsCloneStateRestricted(skills): 329 tooltipPanel.state = uiconst.UI_NORMAL 330 tooltipPanel.AddRow(rowClass=OmegaTooltipPanelCell, cellPadding=(0, 6, 0, 6), text=GetByLabel('UI/CloneState/RequiresOmegaClone'), origin=ORIGIN_INDUSTRY) 331 332 def IsCloneStateRestricted(self, skills): 333 for typeID, level in skills: 334 if get_clone_grade_svc().is_skill_level_restricted(typeID, level): 335 return True 336 337 return False 338 339 340 class SubmitButtonTooltipPanel: 341 342 def __init__(self, status, errors, tooltipPanel): 343 self.tooltipPanel = tooltipPanel 344 self.Reconstruct(status, errors) 345 346 def Reconstruct(self, status, errors): 347 if self.tooltipPanel.destroyed: 348 return 349 self.tooltipPanel.margin = MARGIN 350 numColumns = 2 351 self.tooltipPanel.columns = numColumns 352 self.tooltipPanel.Flush() 353 if status == industry.STATUS_INSTALLED: 354 self.tooltipPanel.AddLabelMedium(text=localization.GetByLabel('UI/Industry/StopJobHint'), wrapWidth=200, colSpan=numColumns) 355 spacerHeight = 8 356 else: 357 if not errors: 358 return 359 errors = {error[0].value:error for error in errors}.values() 360 self.tooltipPanel.cellSpacing = (0, 4) 361 for error, errorArgs in errors: 362 AddErrorRow(self.tooltipPanel, error, errorArgs) 363 364 spacerHeight = 4 365 self.tooltipPanel.AddSpacer(width=0, height=spacerHeight, colSpan=numColumns) 366 367 368 class JobsSummaryTooltipPanel: 369 370 def __init__(self, jobData, tooltipPanel): 371 self.tooltipPanel = tooltipPanel 372 tooltipPanel.state = uiconst.UI_NORMAL 373 tooltipPanel.margin = 8 374 tooltipPanel.columns = 2 375 rangeLabel = industryUIConst.GetControlRangeLabel(jobData.max_distance) 376 activityType = industryUIConst.GetActivityType(jobData.activityID) 377 usedSlots = sm.GetService('industrySvc').GetJobCountForActivity(jobData.activityID) 378 if activityType == industryUIConst.TYPE_MANUFACTURING: 379 text = localization.GetByLabel('UI/Industry/JobSummaryManufacturing', used=usedSlots, max=jobData.max_slots) 380 tooltipPanel.AddLabelMedium(text=text, width=320, cellPadding=(0, 0, 0, 2), colSpan=2) 381 AddSkillRow(tooltipPanel, const.typeMassProduction, cellPadding=(0, 0, 0, 1)) 382 AddSkillRow(tooltipPanel, const.typeAdvancedMassProduction, cellPadding=(0, 0, 0, 1)) 383 text = localization.GetByLabel('UI/Industry/ControlRangeManufacturing', range=rangeLabel) 384 tooltipPanel.AddLabelMedium(text=text, width=320, cellPadding=(0, 8, 0, 2), colSpan=2) 385 AddSkillRow(tooltipPanel, const.typeSupplyChainManagement, cellPadding=(0, 0, 0, 1)) 386 elif activityType == industryUIConst.TYPE_SCIENCE: 387 text = localization.GetByLabel('UI/Industry/JobSummaryScience', used=usedSlots, max=jobData.max_slots) 388 tooltipPanel.AddLabelMedium(text=text, width=320, cellPadding=(0, 0, 0, 2), colSpan=2) 389 AddSkillRow(tooltipPanel, const.typeLaboratoryOperation, cellPadding=(0, 0, 0, 1)) 390 AddSkillRow(tooltipPanel, const.typeAdvancedLaboratoryOperation, cellPadding=(0, 0, 0, 1)) 391 text = localization.GetByLabel('UI/Industry/ControlRangeScience', range=rangeLabel) 392 tooltipPanel.AddLabelMedium(text=text, width=320, cellPadding=(0, 8, 0, 2), colSpan=2) 393 AddSkillRow(tooltipPanel, const.typeScientificNetworking, cellPadding=(0, 0, 0, 1)) 394 elif activityType == industryUIConst.TYPE_REACTION: 395 text = localization.GetByLabel('UI/Industry/JobSummaryReactions', used=usedSlots, max=jobData.max_slots) 396 tooltipPanel.AddLabelMedium(text=text, width=320, cellPadding=(0, 0, 0, 2), colSpan=2) 397 AddSkillRow(tooltipPanel, const.typeMassReactions, cellPadding=(0, 0, 0, 1)) 398 AddSkillRow(tooltipPanel, const.typeAdvancedMassReactions, cellPadding=(0, 0, 0, 1)) 399 text = localization.GetByLabel('UI/Industry/ControlRangeReactions', range=rangeLabel) 400 tooltipPanel.AddLabelMedium(text=text, width=320, cellPadding=(0, 8, 0, 2), colSpan=2) 401 AddSkillRow(tooltipPanel, const.typeRemoteReactions, cellPadding=(0, 0, 0, 1)) 402 403 404 class AllJobsSummaryTooltipPanel: 405 406 def __init__(self, tooltipPanel): 407 self.tooltipPanel = tooltipPanel 408 tooltipPanel.state = uiconst.UI_NORMAL 409 tooltipPanel.margin = 8 410 tooltipPanel.columns = 2 411 dogmaLocation = sm.GetService('clientDogmaIM').GetDogmaLocation() 412 attributeValues = dogmaLocation.GetIndustryCharacterModifiers(session.charid) 413 industrySvc = sm.GetService('industrySvc') 414 for activityID, slotLimitAttributeID, labelPath, topPad, skills in [(industry.MANUFACTURING, 415 attributeManufactureSlotLimit, 416 'UI/Industry/JobSummaryManufacturing', 417 0, 418 (const.typeMassProduction, const.typeAdvancedMassProduction)), (industry.RESEARCH_TIME, 419 attributeMaxLaborotorySlots, 420 'UI/Industry/JobSummaryScience', 421 8, 422 (const.typeLaboratoryOperation, const.typeAdvancedLaboratoryOperation)), (industry.REACTION, 423 attributeReactionSlotLimit, 424 'UI/Industry/JobSummaryReactions', 425 8, 426 (const.typeMassReactions, const.typeAdvancedMassReactions))]: 427 usedSlots = industrySvc.GetJobCountForActivity(activityID) 428 maxSlots = int(attributeValues[slotLimitAttributeID]) 429 text = localization.GetByLabel(labelPath, used=usedSlots, max=maxSlots) 430 tooltipPanel.AddLabelMedium(text=text, width=320, cellPadding=(0, 431 topPad, 432 0, 433 2), colSpan=2) 434 for eachSkillID in skills: 435 AddSkillRow(tooltipPanel, eachSkillID, cellPadding=(0, 0, 0, 1)) 436 437 438 class TimeContainerTooltipPanel: 439 440 def __init__(self, jobData, tooltipPanel): 441 tooltipPanel.state = uiconst.UI_NORMAL 442 tooltipPanel.margin = (8, 8, 8, 7) 443 tooltipPanel.columns = 2 444 AddJobModifierRows(tooltipPanel, industry.TimeModifier, jobData) 445 for typeID in jobData.GetTimeSkillTypes() or []: 446 AddSkillRow(tooltipPanel, typeID, cellPadding=(0, 0, 0, 1)) 447 448 449 class CostContainerTooltipPanel: 450 LABEL_OFFSET = 4 451 452 def __init__(self, jobData, tooltipPanel): 453 tooltipPanel.state = uiconst.UI_NORMAL 454 tooltipPanel.margin = MARGIN 455 numColumns = 3 456 tooltipPanel.columns = numColumns 457 tooltipPanel.cellPadding = (0, 0) 458 header, abbrLabel, costPercentage = self.GetHeaderAndAbbreviation(jobData) 459 percText = '' 460 if costPercentage: 461 estValueLabel = GetByLabel('UI/Industry/EstimatedItemValue', numRuns=jobData.runs) 462 costWithoutPercentage = FmtISK(jobData.base_cost / costPercentage, 0) 463 percText = '%.1f%%' % (costPercentage * 100.0) 464 percText = GetByLabel('UI/Industry/PercentageOfEIV', percentage=percText, startColorTag='') 465 self.AddAmountRow(tooltipPanel, estValueLabel, costWithoutPercentage, fontColor=TextColor.NORMAL) 466 tooltipPanel.AddSpacer(width=0, height=10, colSpan=tooltipPanel.columns) 467 baseCostAsText = FmtISK(jobData.base_cost, 0) 468 self.AddAmountRow(tooltipPanel, header, baseCostAsText, percText) 469 tooltipPanel.AddSpacer(width=0, height=10, colSpan=tooltipPanel.columns) 470 self.AddBodyFramedCont(tooltipPanel, GetByLabel('UI/Industry/JobGrossCost')) 471 tooltipPanel.AddSpacer(width=0, height=10, colSpan=tooltipPanel.columns) 472 systemIndex = jobData.facility.GetCostIndex(jobData.activityID) 473 systemIndexAsText = '%.2f%%' % (systemIndex * 100.0) 474 if abbrLabel: 475 systemIndexAsText = GetByLabel(abbrLabel, percentage=systemIndexAsText, startColorTag='') 476 systemIndexCost = systemIndex * jobData.base_cost 477 systemIndexCostAsText = FmtISK(systemIndexCost, 0) 478 self.AddRow(tooltipPanel, GetByLabel('UI/Industry/SystemCostIndex'), systemIndexAsText, systemIndexCostAsText) 479 jobModifiers = 1.0 480 mulModifiers = [ x for x in jobData.GetModifiers(industry.CostModifier) if not x.additive ] 481 if mulModifiers: 482 tooltipPanel.AddSpacer(width=0, height=14, colSpan=tooltipPanel.columns) 483 for m in mulModifiers: 484 jobModifiers *= m.amount 485 486 bonusValue = systemIndexCost * (jobModifiers - 1.0) 487 amountAsText, fontColor = self.GetAmountTextAndColor(bonusValue) 488 self.AddAmountRow(tooltipPanel, GetByLabel('UI/Industry/CostBonuses'), amountAsText, fontColor=fontColor) 489 for modifier in mulModifiers: 490 color = modifier.GetModifierColor() 491 self.AddRow(tooltipPanel, modifier.GetName(), modifier.GetPercentageLabel(), '', leftPadding=20, fontColor=color) 492 tooltipPanel.AddSpacer(width=0, height=2, colSpan=tooltipPanel.columns) 493 tooltipPanel.FillRow() 494 495 tooltipPanel.AddSpacer(width=0, height=14, colSpan=tooltipPanel.columns) 496 costWithoutAlphaTax = jobData.GetCostWithoutAlphaTax() 497 costWithoutAlphaTaxAsText = FmtISK(costWithoutAlphaTax, 1) 498 self.AddAmountRow(tooltipPanel, GetByLabel('UI/Industry/TotalJobGrossCost'), costWithoutAlphaTaxAsText, fontColor=TextColor.HIGHLIGHT) 499 facilityTaxAmt = jobData.GetFacilityTax() 500 taxRate = jobData.facility.tax 501 if taxRate is None and jobData.activity: 502 taxRate = jobData.activity.activity_tax(jobData.facility) 503 totalTax = facilityTaxAmt or 0 504 tooltipPanel.AddSpacer(width=0, height=10, colSpan=tooltipPanel.columns) 505 self.AddBodyFramedCont(tooltipPanel, GetByLabel('UI/Industry/Taxes')) 506 tooltipPanel.AddSpacer(width=0, height=10, colSpan=tooltipPanel.columns) 507 if taxRate: 508 taxLabel = '<color=%s>+%s%%</color>' % (Color.RGBtoHex(*eveColor.DANGER_RED), FormatNumeric(taxRate * 100, useGrouping=True, decimalPlaces=2)) 509 if abbrLabel: 510 taxLabel = GetByLabel(abbrLabel, percentage=taxLabel, startColorTag='') 511 self.AddIskRow(tooltipPanel, GetByLabel('UI/Industry/FacilityTax'), taxLabel, facilityTaxAmt) 512 tooltipPanel.AddSpacer(width=0, height=10, colSpan=tooltipPanel.columns) 513 cloneStateModifier = GetCloneStateModifier(jobData) 514 if cloneStateModifier: 515 alphaTax = jobData.base_cost * (cloneStateModifier.amount - 1.0) 516 totalTax += alphaTax 517 percText = cloneStateModifier.GetPercentageLabel(decimals=2) 518 if abbrLabel: 519 percText = GetByLabel(abbrLabel, percentage=percText, startColorTag='') 520 self.AddIskRow(tooltipPanel, GetByLabel('UI/Industry/AlphaCloneTax'), percText, alphaTax) 521 tooltipPanel.AddSpacer(width=0, height=10, colSpan=tooltipPanel.columns) 522 scc_surcharge = jobData.scc_surcharge 523 scc_surcharge_ratio = jobData.scc_surcharge_ratio 524 if scc_surcharge: 525 ratioText = '+%s%%' % FormatNumeric(scc_surcharge_ratio * 100, useGrouping=True, decimalPlaces=2) 526 if abbrLabel: 527 ratioText = GetByLabel(abbrLabel, percentage=ratioText, startColorTag='') 528 totalTax += scc_surcharge 529 self.AddIskRow(tooltipPanel, GetByLabel('UI/Industry/SccSurcharge'), ratioText, scc_surcharge) 530 tooltipPanel.AddSpacer(width=0, height=10, colSpan=tooltipPanel.columns) 531 industrySecurityTax = int(getattr(jobData, 'industry_security_tax', 0) or 0) 532 if industrySecurityTax: 533 ratioText = '+%s%%' % FormatNumeric(INDUSTRY_SECURITY_TAX_RATE * 100, useGrouping=True, decimalPlaces=2) 534 if abbrLabel: 535 ratioText = GetByLabel(abbrLabel, percentage=ratioText, startColorTag='') 536 totalTax += industrySecurityTax 537 self.AddIskRow(tooltipPanel, GetByLabel('UI/Industry/IndustrySecurityTax'), ratioText, industrySecurityTax) 538 tooltipPanel.AddSpacer(width=0, height=10, colSpan=tooltipPanel.columns) 539 totalTaxText = FmtISK(totalTax, 0) 540 self.AddAmountRow(tooltipPanel, GetByLabel('UI/Industry/TotalTaxes'), totalTaxText, fontColor=TextColor.HIGHLIGHT) 541 tooltipPanel.AddSpacer(width=0, height=6, colSpan=tooltipPanel.columns) 542 totalCost = jobData.total_cost 543 totalCostAsText = FmtISK(totalCost, 0) 544 self.AddTotalFramedCont(tooltipPanel, totalCostAsText) 545 546 def GetHeaderAndAbbreviation(self, jobData): 547 costPercentage = None 548 if jobData.activityID == industry.MANUFACTURING: 549 return (GetByLabel('UI/Industry/EstimatedItemValue', numRuns=jobData.runs), 'UI/Industry/PercentageOfEIV', costPercentage) 550 if jobData.activityID in (industry.RESEARCH_TIME, industry.RESEARCH_MATERIAL): 551 return (GetByLabel('UI/Industry/ProcessTimeValue'), 'UI/Industry/PercentageOfPTV', costPercentage) 552 if jobData.activityID in (industry.COPYING, industry.INVENTION): 553 costPercentage = industry.COST_PERCENTAGE 554 percText = FormatNumeric(industry.COST_PERCENTAGE * 100, useGrouping=True, decimalPlaces=1) + '%' 555 return (GetByLabel('UI/Industry/HeaderPercentageOfEIV'), 'UI/Industry/PercentageOfPEIV', costPercentage) 556 return (GetByLabel('UI/Industry/BaseItemCost'), '', costPercentage) 557 558 def AddAmountRow(self, tooltipPanel, textLeft, amountAsText, percentage = '', fontColor = TextColor.NORMAL): 559 return self.AddRow(tooltipPanel, textLeft, percentage, amountAsText, fontColor=fontColor) 560 561 def AddBodyFramedCont(self, tooltipPanel, textLeft): 562 fillColor = eveColor.WHITE[:3] + (0.1,) 563 c, maxTextHeight = self._AddFramedCont(tooltipPanel, textLeft, '', bold=False, fillColor=fillColor) 564 c.height = maxTextHeight + 10 565 566 def AddTotalFramedCont(self, tooltipPanel, textRight): 567 tooltipPanel.AddSpacer(width=0, height=4, colSpan=tooltipPanel.columns) 568 c, maxTextHeight = self._AddFramedCont(tooltipPanel, GetByLabel('UI/Industry/JobCost'), textRight, EveHeaderLarge, bold=True, fillColor=eveColor.SMOKE_BLUE) 569 c.height = maxTextHeight + 12 570 tooltipPanel.AddSpacer(width=0, height=4, colSpan=tooltipPanel.columns) 571 572 def _AddFramedCont(self, tooltipPanel, textLeft, textRight, rightLabelClass = EveLabelMedium, bold = False, fillColor = eveColor.WHITE): 573 c = Container(align=uiconst.TOTOP) 574 Fill(bgParent=c, color=fillColor) 575 leftLabel = EveLabelMedium(parent=c, align=uiconst.CENTERLEFT, left=self.LABEL_OFFSET, text=textLeft) 576 c.rightLabel = rightLabelClass(parent=c, align=uiconst.CENTERRIGHT, left=self.LABEL_OFFSET, text=textRight, bold=bold) 577 textWidth = leftLabel.textwidth + c.rightLabel.textwidth + 20 578 tooltipPanel.AddCell(cellObject=c, colSpan=tooltipPanel.columns) 579 tooltipPanel.AddSpacer(width=textWidth, height=0, colSpan=tooltipPanel.columns) 580 return (c, max(c.rightLabel.textheight, leftLabel.textheight)) 581 582 def AddIskRow(self, tooltipPanel, textLeft, textCenter, amount, fontColor = None): 583 amountAsText, fc = self.GetAmountTextAndColor(amount) 584 fontColor = fontColor or fc 585 return self.AddRow(tooltipPanel, textLeft, textCenter, amountAsText, fontColor=fontColor) 586 587 def GetAmountTextAndColor(self, amount): 588 amountAsText = FmtISK(amount, 0) 589 if amount > 0: 590 amountAsText = '+%s' % amountAsText 591 color = eveColor.DANGER_RED 592 elif amount == 0: 593 color = TextColor.NORMAL 594 else: 595 color = eveColor.SUCCESS_GREEN 596 return (amountAsText, color) 597 598 def AddRow(self, tooltipPanel, textLeft, textCenter, textRight, leftPadding = LABEL_OFFSET, fontColor = TextColor.NORMAL): 599 tooltipPanel.AddLabelMedium(text=textLeft, align=uiconst.CENTERLEFT, left=leftPadding, color=fontColor) 600 tooltipPanel.AddLabelMedium(text=textCenter, align=uiconst.CENTERRIGHT, cellPadding=(10, 0, 10, 1), color=fontColor) 601 rowTotalLabel = tooltipPanel.AddLabelMedium(text=textRight, align=uiconst.CENTERRIGHT, color=fontColor, left=self.LABEL_OFFSET) 602 tooltipPanel.FillRow() 603 return rowTotalLabel 604 605 606 def GetCloneStateModifier(jobData): 607 for modifier in jobData.input_modifiers: 608 if modifier.reference == industry.Reference.CLONE_STATE: 609 return modifier 610 611 612 class ProbabilityTooltipPanel: 613 614 def __init__(self, jobData, tooltipPanel): 615 tooltipPanel.state = uiconst.UI_NORMAL 616 tooltipPanel.margin = MARGIN 617 tooltipPanel.columns = 2 618 AddJobModifierRows(tooltipPanel, industry.ProbabilityModifier, jobData) 619 if jobData.activityID == industry.INVENTION: 620 for skill in jobData.activity.skills: 621 AddSkillRow(tooltipPanel, skill.typeID, cellPadding=(0, 0, 0, 2)) 622 623 tooltipPanel.AddSpacer(width=0, height=6) 624 625 626 class FacilityActivityTooltip: 627 628 def __init__(self, facilityData, activityID, tooltipPanel): 629 tooltipPanel.margin = MARGIN 630 tooltipPanel.columns = 2 631 tooltipPanel.state = uiconst.UI_NORMAL 632 text = localization.GetByLabel(industryUIConst.ACTIVITY_NAMES.get(activityID)) 633 tooltipPanel.AddLabelMedium(text=text, cellPadding=PADBOTTOM, colSpan=2, bold=True) 634 if activityID not in facilityData.activities: 635 text = localization.GetByLabel('UI/Industry/ActivityNotSupported') 636 tooltipPanel.AddLabelMedium(text=text, cellPadding=PADBOTTOM, colSpan=2) 637 return 638 if activityID in (industry.MANUFACTURING, industry.REACTION): 639 activity = facilityData.activities[activityID] 640 modifierData = self.GetTypesSupportedWithModifiers(activity, facilityData.modifiers) 641 if modifierData: 642 label = IndustryCaptionLabel(text=localization.GetByLabel('UI/Industry/ManufacturingTypesHint')) 643 tooltipPanel.AddCell(label, colSpan=2) 644 self.scroll = ScrollContainer(align=uiconst.TOTOP, showUnderlay=True) 645 for text, modifierME, modifierTE in modifierData: 646 Label(parent=self.scroll, align=uiconst.TOTOP, text=text, padding=2) 647 if modifierME: 648 Label(parent=self.scroll, align=uiconst.TOTOP, text='<color=gray>%s:</color> %s (%s)' % (localization.GetByLabel('UI/Industry/MaterialConsumption'), modifierME.GetPercentageLabel(), localization.GetByLabel('UI/Industry/Specialities/Rigs')), fontsize=fontconst.EVE_SMALL_FONTSIZE, padding=(2, 0, 2, 2)) 649 if modifierTE: 650 Label(parent=self.scroll, align=uiconst.TOTOP, text='<color=gray>%s</color> %s (%s)' % (localization.GetByLabel('UI/Industry/JobDuration'), modifierTE.GetPercentageLabel(), localization.GetByLabel('UI/Industry/Specialities/Rigs')), fontsize=fontconst.EVE_SMALL_FONTSIZE, padding=(2, -3, 2, 3)) 651 652 self.scroll.height = min(150, len(modifierData) * 20) 653 tooltipPanel.AddCell(self.scroll, cellPadding=PADBOTTOM, colSpan=2) 654 modifiers = facilityData.GetFacilityModifiersByActivityID().get(activityID, None) 655 if modifiers: 656 for modifierCls, label in ((industry.TimeModifier, 'UI/Industry/ModifierTimeCaption'), (industry.MaterialModifier, 'UI/Industry/ModifierMaterialCaption'), (industry.CostModifier, 'UI/Industry/ModifierCostCaption')): 657 clsModifiers = [ modifier for modifier in modifiers if isinstance(modifier, modifierCls) ] 658 if clsModifiers: 659 AddModifierRows(localization.GetByLabel(label), clsModifiers, tooltipPanel) 660 tooltipPanel.AddSpacer(0, 6, colSpan=2) 661 662 costIndexes = facilityData.GetCostIndexByActivityID() 663 costIndex = costIndexes.get(activityID, None) 664 if costIndex: 665 AddSystemCostIndexRow(activityID, facilityData, tooltipPanel) 666 taxRates = facilityData.GetServiceTaxes() 667 for serviceID in structures.INDUSTRY_SERVICES: 668 if structures.GetActivityID(serviceID) != activityID: 669 taxRates.pop(serviceID, None) 670 671 AddTaxRateRows(tooltipPanel, taxRates) 672 673 def GetMETEModifiers(self, modifiers): 674 modifierME = modifierTE = None 675 for modifier in modifiers: 676 if isinstance(modifier, industry.TimeModifier): 677 modifierTE = modifier 678 elif isinstance(modifier, industry.MaterialModifier): 679 modifierME = modifier 680 681 return (modifierME, modifierTE) 682 683 def GetTypesSupportedWithModifiers(self, activity, modifiers): 684 ret = [] 685 modifiersByCategoryID = self.GetModifiersByCategoryID(modifiers) 686 for categoryID in activity['categories']: 687 if categoryID == const.categoryBlueprint: 688 continue 689 text = evetypes.GetCategoryNameByCategory(categoryID) 690 modifierME, modifierTE = self.GetMETEModifiers(modifiersByCategoryID.get(categoryID, [])) 691 ret.append((text, modifierME, modifierTE)) 692 693 modifiersByGroupID = self.GetModifiersByGroupID(modifiers) 694 for groupID in activity['groups']: 695 text = evetypes.GetGroupNameByGroup(groupID) 696 modifierME, modifierTE = self.GetMETEModifiers(modifiersByGroupID.get(groupID, [])) 697 if (modifierTE, modifierME) == (None, None): 698 categoryID = evetypes.GetCategoryIDByGroup(groupID) 699 if categoryID in modifiersByCategoryID: 700 modifierME, modifierTE = self.GetMETEModifiers(modifiersByCategoryID.get(categoryID, [])) 701 ret.append((text, modifierME, modifierTE)) 702 703 ret.sort() 704 return ret 705 706 def GetModifiersByCategoryID(self, modifiers): 707 ret = defaultdict(list) 708 for modifier in modifiers: 709 if getattr(modifier, 'categoryID', None): 710 ret[modifier.categoryID].append(modifier) 711 712 return ret 713 714 def GetModifiersByGroupID(self, modifiers): 715 ret = defaultdict(list) 716 for modifier in modifiers: 717 if getattr(modifier, 'groupID', None): 718 ret[modifier.groupID].append(modifier) 719 720 return ret