NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

overviewScrollEntry.py (29177B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\inflight\overview\overviewScrollEntry.py
      2 import math
      3 import blue
      4 import evetypes
      5 import gametime
      6 import localization
      7 import telemetry
      8 import uthread
      9 from carbonui import uiconst
     10 from carbonui.control.scrollentries import SE_BaseClassCore
     11 from carbonui.primitives.container import Container
     12 from carbonui.primitives.fill import Fill
     13 from carbonui.uianimations import animations
     14 from carbonui.uicore import uicore
     15 from carbonui.util.color import Color
     16 from eve.client.script.parklife import states as state
     17 from eve.client.script.ui.control.eveIcon import Icon
     18 from eve.client.script.ui.control.themeColored import FillThemeColored
     19 from eve.client.script.ui.inflight.bracketsAndTargets.bracketVarious import GetIconColor
     20 from eve.client.script.ui.inflight.overViewLabel import OverviewLabel
     21 from eve.client.script.ui.inflight.overview.overviewConst import COLUMNMARGIN, COLUMN_ANGULARVELOCITY, COLUMN_DISTANCE, COLUMN_ICON, COLUMN_RADIALVELOCITY, COLUMN_TRANSVERSALVELOCITY, COLUMN_VELOCITY, FAINT_ENTRY_CATEGORIES, INVISIBLE_SPACEOBJECT_ICON, KILOMETERS10, KILOMETERS10000000, RIGHTALIGNEDCOLUMNS
     22 from eve.client.script.ui.inflight.overview.overviewUtil import IsFleetMember
     23 from eve.client.script.ui.inflight.overview.spaceObjectIcon import SpaceObjectIcon
     24 from eve.client.script.ui.shared.fleet.fleetBroadcastConst import flagToName, iconsByBroadcastType
     25 from eve.client.script.ui.shared.stateFlag import GetExtraInfoForNode
     26 from eve.client.script.util.bubble import InBubble
     27 from eve.common.lib import appConst as const
     28 from eveexceptions import ExceptionEater
     29 from eveservices.menu import GetMenuService
     30 from homestation import client as homestation
     31 from inventorycommon.util import IsNPC
     32 from mining import is_harvestable
     33 from mining.client import mining_util
     34 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     35 from spacecomponents.common.componentConst import ORBITAL_SKYHOOK
     36 from spacecomponents.common.helper import HasEntityStandingsComponent
     37 from stargate.client.const import EMANATION_GATE_AVAILABLE, EMANATION_GATE_UNAVAILABLE
     38 
     39 class OverviewScrollEntry(SE_BaseClassCore):
     40     __guid__ = 'listentry.OverviewScrollEntry'
     41     __notifyevents__ = []
     42     ENTRYHEIGHT = 24
     43     typeID = None
     44     hostileIndicator = None
     45     attackingMeIndicator = None
     46     myActiveTargetIndicator = None
     47     targetingIndicator = None
     48     flagIcon = None
     49     flagIconBackground = None
     50     flagBackground = None
     51     fleetBroadcastIcon = None
     52     fleetBroadcastID = None
     53     loadedIconAndBackgroundFlags = None
     54     loadedEwarGraphicIDs = None
     55     rightAlignedIconContainer = None
     56     selectionSprite = None
     57     globalMaxWidth = None
     58     hasLoaded = False
     59 
     60     def ApplyAttributes(self, attributes):
     61         super(OverviewScrollEntry, self).ApplyAttributes(attributes)
     62         self.mainIcon = None
     63         self.sr.flag = None
     64         self.sr.bgColor = None
     65         self.columnLabels = []
     66         self.ewarIcons = {}
     67 
     68     @telemetry.ZONE_METHOD
     69     def Startup(self, *args):
     70         node = self.sr.node
     71         self.updateItem = node.updateItem
     72         self.itemID = node.itemID
     73         self.stateItemID = node.itemID
     74         slimItem = node.slimItem()
     75         ball = node.ball()
     76         if not (slimItem and ball):
     77             return
     78         self.typeID = slimItem.typeID
     79         self._ConstructMainIcon(ball, slimItem)
     80         selected, hilited = sm.GetService('stateSvc').GetStates(self.stateItemID, [state.selected, state.mouseOver])
     81         if selected:
     82             self.ShowSelected()
     83         if hilited:
     84             self.ShowHilite()
     85         elif uicore.uilib.mouseOver is not self:
     86             self.HideHilite()
     87         self.UpdateFleetBroadcast()
     88 
     89     def _ConstructMainIcon(self, ball, slimItem):
     90         self.mainIcon = SpaceObjectIcon(name='mainIcon', parent=self, align=uiconst.CENTERLEFT, left=3, typeID=self.typeID)
     91         self.mainIcon.top = -(self.height % 2)
     92         self.mainIcon.LoadTooltipPanel = self.LoadIconTooltipPanel
     93         self.mainIcon.GetTooltipPointer = self.GetIconTooltipPointer
     94         self.mainIcon.DelegateEvents(self)
     95         self.mainIcon.UpdateSpaceObjectIcon(slimItem, ball)
     96         self.mainIcon.UpdateSpaceObjectState(slimItem, ball)
     97 
     98     @telemetry.ZONE_METHOD
     99     def Load(self, node):
    100         with ExceptionEater("Exception during overview's Load"):
    101             self.hasLoaded = True
    102             self.UpdateColumns()
    103             if (node.iconAndBackgroundFlags,
    104              node.useSmallColorTags,
    105              node.hasDockingRights,
    106              node.isHomeStation,
    107              node.gateLockValue) != self.loadedIconAndBackgroundFlags:
    108                 slimItem = node.slimItem()
    109                 if not slimItem:
    110                     return
    111                 self.UpdateFlagAndBackground(slimItem)
    112             if node.ewarGraphicIDs != self.loadedEwarGraphicIDs:
    113                 self.UpdateEwar()
    114 
    115     def _OnSizeChange_NoBlock(self, displayWidth, displayHeight):
    116         self.SetGlobalMaxWidth()
    117 
    118     def SetGlobalMaxWidth(self):
    119         if self.rightAlignedIconContainer and self.rightAlignedIconContainer.width:
    120             globalMaxWidth = self.width - self.rightAlignedIconContainer.width - 6
    121         else:
    122             globalMaxWidth = None
    123         self.globalMaxWidth = globalMaxWidth
    124         for each in self.columnLabels:
    125             each.globalMaxWidth = globalMaxWidth
    126 
    127     def CreateRightAlignedIconContainer(self):
    128         if self.rightAlignedIconContainer is None:
    129             self.rightAlignedIconContainer = Container(parent=self, name='rightAlignedIconContainer', align=uiconst.CENTERRIGHT, width=200, height=16, state=uiconst.UI_PICKCHILDREN, idx=0)
    130         return self.rightAlignedIconContainer
    131 
    132     def UpdateRightAlignedIconContainerSize(self):
    133         if self.rightAlignedIconContainer:
    134             preWidth = self.rightAlignedIconContainer.width
    135             self.rightAlignedIconContainer.width = newWidth = sum([ each.width for each in self.rightAlignedIconContainer.children if each.display ])
    136             if preWidth != newWidth:
    137                 self.SetGlobalMaxWidth()
    138 
    139     @telemetry.ZONE_METHOD
    140     def UpdateFleetBroadcast(self):
    141         broadcastID, broadcastFlag, broadcastData = sm.GetService('fleet').GetCurrentFleetBroadcastOnItem(self.itemID)
    142         if broadcastID != self.fleetBroadcastID:
    143             if broadcastID is None:
    144                 if self.fleetBroadcastIcon:
    145                     self.fleetBroadcastIcon.Close()
    146                     self.fleetBroadcastIcon = None
    147                     self.UpdateRightAlignedIconContainerSize()
    148                 self.fleetBroadcastType = self.fleetBroadcastID = None
    149                 return
    150             broadcastType = flagToName[broadcastFlag]
    151             if broadcastType in ('EnemySpotted', 'NeedBackup', 'InPosition', 'HoldPosition'):
    152                 inBubble = InBubble(self.itemID)
    153                 if not inBubble:
    154                     if self.fleetBroadcastID is not None:
    155                         if self.fleetBroadcastIcon:
    156                             self.fleetBroadcastIcon.Close()
    157                             self.fleetBroadcastIcon = None
    158                         self.fleetBroadcastType = self.fleetBroadcastID = None
    159                     return
    160             self.fleetBroadcastType = broadcastType
    161             self.fleetBroadcastID = broadcastID
    162             if not self.fleetBroadcastIcon:
    163                 self.fleetBroadcastIcon = Icon(name='fleetBroadcastIcon', parent=self.CreateRightAlignedIconContainer(), align=uiconst.TORIGHT, pos=(0, 0, 16, 16), state=uiconst.UI_DISABLED)
    164             icon = iconsByBroadcastType[broadcastType]
    165             self.fleetBroadcastIcon.LoadIcon(icon)
    166             self.UpdateRightAlignedIconContainerSize()
    167 
    168     def UpdateName(self, slimItem):
    169         typeID = getattr(slimItem, 'typeID', None)
    170         if typeID:
    171             self.name = 'scrollentry_{typeID}'.format(typeID=typeID)
    172 
    173     @telemetry.ZONE_METHOD
    174     def UpdateFlagAndBackground(self, slimItem, *args):
    175         if self.destroyed or not self.updateItem or slimItem is None:
    176             return
    177         node = self.sr.node
    178         self.loadedIconAndBackgroundFlags = (node.iconAndBackgroundFlags,
    179          node.useSmallColorTags,
    180          node.hasDockingRights,
    181          node.isHomeStation,
    182          node.gateLockValue)
    183         self.UpdateName(slimItem)
    184         try:
    185             if slimItem.groupID != const.groupAgentsinSpace and (slimItem.ownerID and IsNPC(slimItem.ownerID) or slimItem.charID and IsNPC(slimItem.charID)) and not node.isHomeStation and not node.hasDockingRights and not node.gateLockValue:
    186                 self.mainIcon.SetIconFlag(-1)
    187                 if self.flagBackground:
    188                     self.flagBackground.Close()
    189                     self.flagBackground = None
    190             else:
    191                 node = self.sr.node
    192                 stateSvc = sm.GetService('stateSvc')
    193                 iconFlag, backgroundFlag = node.iconAndBackgroundFlags
    194                 self.mainIcon.SetIconFlag(iconFlag, extraInfo=GetExtraInfoForNode(node))
    195                 if backgroundFlag and backgroundFlag != -1:
    196                     r, g, b, a = stateSvc.GetStateBackgroundColor(backgroundFlag)
    197                     opacityModifier = 0.125 if slimItem.categoryID in FAINT_ENTRY_CATEGORIES else 0.5
    198                     a = a * opacityModifier
    199                     if not self.flagBackground:
    200                         self.flagBackground = Fill(name='bgColor', parent=self, state=uiconst.UI_DISABLED, color=(r,
    201                          g,
    202                          b,
    203                          a))
    204                     else:
    205                         self.flagBackground.SetRGBA(r, g, b, a)
    206                     blink = stateSvc.GetStateBackgroundBlink(backgroundFlag)
    207                     if blink:
    208                         if not self.flagBackground.HasAnimation('color'):
    209                             uicore.animations.FadeTo(self.flagBackground, startVal=0.0, endVal=a, duration=0.75, loops=uiconst.ANIM_REPEAT, curveType=uiconst.ANIM_WAVE)
    210                     else:
    211                         self.flagBackground.StopAnimations()
    212                 elif self.flagBackground:
    213                     self.flagBackground.Close()
    214                     self.flagBackground = None
    215                 self.TryCorrectHostileUI()
    216         except AttributeError:
    217             if not self.destroyed:
    218                 raise
    219 
    220     @telemetry.ZONE_METHOD
    221     def UpdateFlagPositions(self, *args, **kwds):
    222         pass
    223 
    224     @telemetry.ZONE_METHOD
    225     def UpdateColumns(self):
    226         node = self.sr.node
    227         haveIcon = False
    228         currentLabels = []
    229         columnOffset = 0
    230         currentColumns = node.columns
    231         for columnID in currentColumns:
    232             columnWidth = node.columnWidths[columnID]
    233             if columnID == COLUMN_ICON:
    234                 if self.mainIcon:
    235                     self.mainIcon.left = columnOffset + 3
    236                     self.UpdateIconColor()
    237                     self.mainIcon.state = uiconst.UI_NORMAL
    238                 columnOffset += columnWidth
    239                 haveIcon = True
    240                 continue
    241             displayValue = self.GetColumnDisplayValue(node, columnID)
    242             if not displayValue:
    243                 columnOffset += columnWidth
    244                 continue
    245             label = None
    246             if self.columnLabels:
    247                 label = self.columnLabels.pop(0)
    248                 if label.destroyed:
    249                     label = None
    250             if not label:
    251                 label = OverviewLabel(parent=self, align=uiconst.CENTERLEFT, state=uiconst.UI_DISABLED, idx=0, fontSize=node.fontSize, typeID=self.typeID)
    252             columnHint = node.get('hint_' + columnID, None)
    253             if columnHint:
    254                 label.state = uiconst.UI_NORMAL
    255             else:
    256                 label.state = uiconst.UI_DISABLED
    257             label.columnWidth = columnWidth - COLUMNMARGIN * 2
    258             label.text = displayValue
    259             label.rightAligned = columnID in RIGHTALIGNEDCOLUMNS
    260             label.columnPosition = columnOffset + COLUMNMARGIN
    261             label.globalMaxWidth = self.globalMaxWidth
    262             label.hint = columnHint
    263             label.stateItemID = self.stateItemID
    264             columnOffset += columnWidth
    265             currentLabels.append(label)
    266 
    267         if not haveIcon and self.mainIcon:
    268             self.mainIcon.state = uiconst.UI_HIDDEN
    269         if self.columnLabels:
    270             while self.columnLabels:
    271                 label = self.columnLabels.pop()
    272                 label.Close()
    273 
    274         self.columnLabels = currentLabels
    275 
    276     def GetRadialMenuIndicator(self, create = True, *args):
    277         indicator = getattr(self, 'radialMenuIndicator', None)
    278         if indicator and not indicator.destroyed:
    279             return indicator
    280         if not create:
    281             return
    282         self.radialMenuIndicator = FillThemeColored(bgParent=self, name='radialMenuIndicator', colorType=uiconst.COLORTYPE_UIHILIGHT)
    283         return self.radialMenuIndicator
    284 
    285     def ShowRadialMenuIndicator(self, slimItem, *args):
    286         indicator = self.GetRadialMenuIndicator(create=True)
    287         indicator.display = True
    288 
    289     def HideRadialMenuIndicator(self, slimItem, *args):
    290         indicator = self.GetRadialMenuIndicator(create=False)
    291         if indicator:
    292             indicator.display = False
    293 
    294     @classmethod
    295     def GetColumnDisplayValue(cls, node, columnID):
    296         if columnID == COLUMN_DISTANCE:
    297             return cls._GetColumnValueDistance(node)
    298         elif columnID == COLUMN_ANGULARVELOCITY:
    299             return cls._GetColumnValueAngularVelocity(node)
    300         elif columnID == COLUMN_VELOCITY:
    301             return cls._GetColumnValueVelocity(node)
    302         elif columnID == COLUMN_RADIALVELOCITY:
    303             return cls._GetColumnValueRadialVelocity(node)
    304         elif columnID == COLUMN_TRANSVERSALVELOCITY:
    305             return cls._GetColumnValueTransversalVelocity(node)
    306         else:
    307             return node.Get('display_' + columnID, None)
    308 
    309     @classmethod
    310     def _GetColumnValueTransversalVelocity(cls, node):
    311         sortValue = node.rawTransveralVelocity
    312         if sortValue is not None:
    313             currentTransveralVelocity = int(sortValue)
    314             if currentTransveralVelocity != node.lastFormattedTransveralVelocity:
    315                 node.display_TRANSVERSALVELOCITY = FMTFUNCTION(currentTransveralVelocity, useGrouping=True)
    316                 node.lastFormattedTransveralVelocity = currentTransveralVelocity
    317         return node.display_TRANSVERSALVELOCITY or u'-'
    318 
    319     @classmethod
    320     def _GetColumnValueRadialVelocity(cls, node):
    321         sortValue = node.rawRadialVelocity
    322         if sortValue is not None:
    323             currentRadialVelocity = int(sortValue)
    324             if currentRadialVelocity != node.lastFormattedRadialVelocity:
    325                 node.display_RADIALVELOCITY = FMTFUNCTION(currentRadialVelocity, useGrouping=True)
    326                 node.lastFormattedRadialVelocity = currentRadialVelocity
    327         return node.display_RADIALVELOCITY or u'-'
    328 
    329     @classmethod
    330     def _GetColumnValueVelocity(cls, node):
    331         sortValue = node.rawVelocity
    332         if sortValue is not None:
    333             currentVelocity = int(sortValue)
    334             if currentVelocity != node.lastFormattedVelocity:
    335                 node.display_VELOCITY = FMTFUNCTION(currentVelocity, useGrouping=True)
    336                 node.lastFormattedVelocity = currentVelocity
    337         return node.display_VELOCITY or u'-'
    338 
    339     @classmethod
    340     def _GetColumnValueAngularVelocity(cls, node):
    341         sortValue = node.rawAngularVelocity
    342         if sortValue is not None:
    343             currentAngularVelocity = round(sortValue, 7)
    344             value = currentAngularVelocity * 180.0 / math.pi
    345             node.display_ANGULARVELOCITY = FMTFUNCTION(value, useGrouping=True)
    346             node.lastFormattedAngularVelocity = currentAngularVelocity
    347         return node.display_ANGULARVELOCITY or u'-'
    348 
    349     @classmethod
    350     def _GetColumnValueDistance(cls, node):
    351         surfaceDist = OverviewScrollEntry._GetSurfaceDistance(node)
    352         if surfaceDist is None:
    353             return u''
    354         if surfaceDist < KILOMETERS10:
    355             currentDist = int(round(surfaceDist))
    356             if currentDist != node.lastFormattedDistance:
    357                 distanceText = get_distance_in_meters(FMTFUNCTION(currentDist, useGrouping=True))
    358                 node.display_DISTANCE = distanceText
    359                 node.lastFormattedDistance = currentDist
    360         elif surfaceDist < KILOMETERS10000000:
    361             currentDist = long(round(surfaceDist / 1000.0))
    362             if currentDist != node.lastFormattedDistance:
    363                 distanceText = get_distance_in_kilometers(FMTFUNCTION(currentDist, useGrouping=True))
    364                 node.display_DISTANCE = distanceText
    365                 node.lastFormattedDistance = currentDist
    366         else:
    367             currentDist = round(surfaceDist / const.AU, 1)
    368             if currentDist != node.lastFormattedDistance:
    369                 distanceText = get_distance_in_au(FMTFUNCTION(currentDist, useGrouping=True, decimalPlaces=1))
    370                 node.display_DISTANCE = distanceText
    371                 node.lastFormattedDistance = currentDist
    372         return node.display_DISTANCE or u''
    373 
    374     @classmethod
    375     def _GetSurfaceDistance(cls, node):
    376         ball = node.ball()
    377         if ball and ball.ballpark:
    378             dist = ball.GetVectorAt(gametime.GetSimTime()).Length()
    379             egoBall = ball.ballpark.GetBall(ball.ballpark.ego)
    380             return max(dist - ball.radius - egoBall.radius, 0)
    381         else:
    382             return node.rawDistance
    383 
    384     @telemetry.ZONE_METHOD
    385     def UpdateEwar(self):
    386         node = self.sr.node
    387         ewarGraphicIDs = node.ewarGraphicIDs
    388         self.loadedEwarGraphicIDs = ewarGraphicIDs
    389         for graphicID, icon in self.ewarIcons.iteritems():
    390             if not ewarGraphicIDs or graphicID not in ewarGraphicIDs:
    391                 icon.state = uiconst.UI_HIDDEN
    392 
    393         if ewarGraphicIDs:
    394             for graphicID in ewarGraphicIDs:
    395                 if graphicID in self.ewarIcons:
    396                     self.ewarIcons[graphicID].state = uiconst.UI_NORMAL
    397                 else:
    398                     icon = Icon(parent=self.CreateRightAlignedIconContainer(), align=uiconst.TORIGHT, state=uiconst.UI_NORMAL, width=16, hint=node.ewarHints[graphicID], graphicID=graphicID, ignoreSize=True)
    399                     self.ewarIcons[graphicID] = icon
    400 
    401         self.UpdateRightAlignedIconContainerSize()
    402 
    403     def OnStateChange(self, itemID, flag, status, *args):
    404         if self.stateItemID != itemID:
    405             return
    406         if flag == state.mouseOver:
    407             self.Hilite(status)
    408         elif flag == state.selected:
    409             if status:
    410                 self.ShowSelected()
    411             else:
    412                 self.ShowDeselected()
    413         elif flag == state.threatTargetsMe:
    414             attacking, = sm.StartService('stateSvc').GetStates(itemID, [state.threatAttackingMe])
    415             if attacking:
    416                 self.Attacking(True)
    417             else:
    418                 self.Hostile(status)
    419         elif flag == state.threatAttackingMe:
    420             self.Attacking(status)
    421             if not status:
    422                 hostile, = sm.StartService('stateSvc').GetStates(itemID, [state.threatTargetsMe])
    423                 self.Hostile(hostile)
    424         elif flag == state.targeted:
    425             self.Targeted(status)
    426         elif flag == state.targeting:
    427             self.Targeting(status)
    428         elif flag == state.activeTarget:
    429             self.ActiveTarget(status)
    430         elif flag == state.flagWreckAlreadyOpened:
    431             self.UpdateIconColor()
    432         elif flag == state.flagWreckEmpty:
    433             self.UpdateIcon()
    434         else:
    435             broadcastDataName = flagToName.get(flag, None)
    436             if broadcastDataName is not None:
    437                 self.UpdateFleetBroadcast()
    438 
    439     def TryCorrectHostileUI(self):
    440         if not self.mainIcon or not self.mainIcon.hostileIndicator:
    441             return
    442         isFleetMember = IsFleetMember(self.sr.node.slimItem())
    443         self.mainIcon.SetHostileIndicatorColor(isFleetMember)
    444 
    445     @telemetry.ZONE_METHOD
    446     def Hostile(self, state, *args, **kwds):
    447         fleetMember = IsFleetMember(self.sr.node.slimItem())
    448         self.mainIcon.SetHostileState(state, fleetMember)
    449 
    450     def Attacking(self, state):
    451         self.mainIcon.SetAttackingState(state)
    452         self.UpdateIconColor()
    453 
    454     @telemetry.ZONE_METHOD
    455     def Targeting(self, state):
    456         self.mainIcon.SetTargetingState(state)
    457 
    458     def Targeted(self, activestate, *args, **kwds):
    459         if activestate and self.targetingIndicator:
    460             self.targetingIndicator.Close()
    461             self.targetingIndicator = None
    462         self.mainIcon.SetTargetedByMeState(activestate)
    463 
    464     def ActiveTarget(self, activestate):
    465         if activestate and self.targetingIndicator:
    466             self.targetingIndicator.Close()
    467             self.targetingIndicator = None
    468         self.mainIcon.SetActiveTargetState(activestate)
    469 
    470     def Hilite(self, isHovered):
    471         if isHovered:
    472             self.ShowHilite()
    473         else:
    474             self.HideHilite()
    475 
    476     def Select(self, *args):
    477         pass
    478 
    479     def Deselect(self, *args):
    480         pass
    481 
    482     def ShowSelected(self, *args):
    483         SE_BaseClassCore.Select(self, *args)
    484 
    485     def ShowDeselected(self, *args):
    486         SE_BaseClassCore.Deselect(self, *args)
    487 
    488     @telemetry.ZONE_METHOD
    489     def UpdateIcon(self, *args, **kwds):
    490         slimItem = self.sr.node.slimItem()
    491         ball = self.sr.node.ball()
    492         if slimItem and ball:
    493             self.mainIcon.UpdateSpaceObjectIcon(slimItem, ball)
    494 
    495     @telemetry.ZONE_METHOD
    496     def UpdateIconColor(self):
    497         if self.destroyed:
    498             return
    499         node = self.sr.node
    500         slimItem = node.slimItem()
    501         if not slimItem:
    502             return
    503         if node.iconColor and not HasEntityStandingsComponent(slimItem.typeID):
    504             iconColor = node.iconColor
    505         else:
    506             iconColor, colorSortValue = GetIconColor(slimItem, getSortValue=True)
    507             if node.sortIconIndex is not None:
    508                 node.sortValue[node.sortIconIndex][1] = colorSortValue
    509             node.iconColor = iconColor
    510         if slimItem.groupID in (const.groupWreck, const.groupSpawnContainer) and sm.GetService('wreck').IsViewedWreck(slimItem.itemID):
    511             iconColor = Color(*iconColor).SetBrightness(0.55).GetRGBA()
    512         self.mainIcon.SetIconColor(iconColor)
    513 
    514     def OnDblClick(self, *args):
    515         if uicore.cmd.IsSomeCombatCommandLoaded():
    516             return
    517         slimItem = self.sr.node.slimItem()
    518         if slimItem:
    519             GetMenuService().Activate(slimItem)
    520 
    521     def OnMouseEnter(self, *args):
    522         SE_BaseClassCore.OnMouseEnter(self, *args)
    523         sm.GetService('stateSvc').SetState(self.sr.node.itemID, state.mouseOver, 1)
    524 
    525     def OnMouseExit(self, *args):
    526         SE_BaseClassCore.OnMouseExit(self, *args)
    527         sm.GetService('stateSvc').SetState(self.sr.node.itemID, state.mouseOver, 0)
    528 
    529     def LoadIconTooltipPanel(self, tooltipPanel, *args):
    530         if not self.sr.node.slimItem:
    531             return
    532         slimItem = self.sr.node.slimItem()
    533         ball = self.sr.node.ball()
    534         if not (slimItem and ball):
    535             return
    536         stateService = sm.GetService('stateSvc')
    537         tooltipPanel.LoadGeneric3ColumnTemplate()
    538         iconObj = SpaceObjectIcon(typeID=slimItem.typeID)
    539         iconObj.UpdateSpaceObjectIcon(slimItem, ball)
    540         iconObj.UpdateSpaceObjectIconColor(slimItem)
    541         iconObj.UpdateSpaceObjectState(slimItem, ball)
    542         iconObj.UpdateSpaceObjectFlagAndBackgroundColor(slimItem, ball)
    543         uthread.new(self.UpdateTooltipIconThread, iconObj)
    544         if iconObj.iconSprite.texturePath != INVISIBLE_SPACEOBJECT_ICON:
    545             tooltipPanel.AddCell(iconObj, cellPadding=(-5, 0, 6, 0))
    546         else:
    547             tooltipPanel.AddSpacer(width=1, height=1)
    548         tooltipPanel.AddLabelMedium(text=evetypes.GetGroupNameByGroup(slimItem.groupID), align=uiconst.CENTERLEFT, bold=True, colSpan=tooltipPanel.columns - 1)
    549         attacking, hostile = stateService.GetStates(slimItem.itemID, [state.threatAttackingMe, state.threatTargetsMe])
    550         if attacking:
    551             tooltipPanel.AddCell()
    552             tooltipPanel.AddLabelMedium(text=localization.GetByLabel('Tooltips/Overview/HostileAction'), align=uiconst.CENTERLEFT, colSpan=tooltipPanel.columns - 1)
    553         elif hostile:
    554             tooltipPanel.AddCell()
    555             tooltipPanel.AddLabelMedium(text=localization.GetByLabel('Tooltips/Overview/TargetLock'), align=uiconst.CENTERLEFT, colSpan=tooltipPanel.columns - 1)
    556         iconHint = iconObj.iconHint
    557         if iconHint:
    558             tooltipPanel.AddCell()
    559             tooltipPanel.AddLabelMedium(text=iconHint, align=uiconst.CENTERLEFT, colSpan=tooltipPanel.columns - 1)
    560         flagStateOwnerHint = iconObj.flagStateOwnerHint if slimItem.categoryID == const.categoryStructure else None
    561         flagStateHint = flagStateOwnerHint or iconObj.flagStateHint
    562         if flagStateHint:
    563             tooltipPanel.AddCell()
    564             tooltipPanel.AddLabelMedium(text=flagStateHint, align=uiconst.CENTERLEFT, colSpan=tooltipPanel.columns - 1)
    565         colorHint = iconObj.iconColorHint
    566         if colorHint:
    567             tooltipPanel.AddCell()
    568             tooltipPanel.AddLabelMedium(text=colorHint, align=uiconst.CENTERLEFT, colSpan=tooltipPanel.columns)
    569         self.AddTypeSpecificInfoToTooltip(slimItem, tooltipPanel)
    570         if self.sr.node.isHomeStation:
    571             tooltipPanel.AddCell()
    572             tooltipPanel.AddLabelMedium(text=homestation.text.bracket_hint(), align=uiconst.CENTERLEFT, colSpan=tooltipPanel.columns - 1)
    573         elif self.sr.node.gateLockValue:
    574             tooltipPanel.AddCell()
    575             text = ''
    576             if self.sr.node.gateLockValue == EMANATION_GATE_AVAILABLE:
    577                 text = localization.GetByLabel('Tooltips/Overview/LockedToThisGate')
    578             elif self.sr.node.gateLockValue == EMANATION_GATE_UNAVAILABLE:
    579                 text = localization.GetByLabel('Tooltips/Overview/LockedToAnotherGate')
    580             tooltipPanel.AddLabelMedium(text=text, align=uiconst.CENTERLEFT, colSpan=tooltipPanel.columns - 1)
    581         if is_harvestable(slimItem.typeID):
    582             tooltipPanel.AddCell()
    583             text = mining_util.get_volume_est_price_formatted(slimItem.typeID)
    584             tooltipPanel.AddLabelMedium(text=text, align=uiconst.CENTERLEFT, colSpan=tooltipPanel.columns - 1)
    585 
    586     def AddTypeSpecificInfoToTooltip(self, slimItem, tooltipPanel):
    587         if slimItem.groupID == const.groupSkyhook:
    588             try:
    589                 comp = sm.GetService('michelle').GetBallpark().componentRegistry.GetComponentForItem(slimItem.itemID, ORBITAL_SKYHOOK)
    590                 text = comp.GetProducingText()
    591                 if text:
    592                     tooltipPanel.AddCell()
    593                     tooltipPanel.AddLabelMedium(text=text, align=uiconst.CENTERLEFT, colSpan=tooltipPanel.columns - 1)
    594             except Exception as e:
    595                 pass
    596 
    597     def UpdateTooltipIconThread(self, iconObj):
    598         while not iconObj.destroyed:
    599             slimItem = self.sr.node.slimItem()
    600             ball = self.sr.node.ball()
    601             if not (slimItem and ball):
    602                 break
    603             iconObj.UpdateSpaceObjectState(slimItem, ball)
    604             blue.synchro.Sleep(200)
    605 
    606     def GetIconTooltipPointer(self):
    607         currentColumns = self.sr.node.columns
    608         if currentColumns and currentColumns[0] == 'ICON':
    609             return uiconst.POINT_RIGHT_2
    610 
    611     def OnClick(self, *args):
    612         prompt_player_fsd_dialog('ListEntryClick')
    613         uicore.cmd.ExecuteCombatCommand(self.sr.node.itemID, uiconst.UI_CLICK)
    614 
    615     def OnMouseDown(self, *args):
    616         self.sr.node.scroll.SelectNode(self.sr.node)
    617         GetMenuService().TryExpandActionMenu(self.itemID, self)
    618 
    619     def GetMenu(self, *args):
    620         return GetMenuService().CelestialMenu(self.sr.node.itemID)
    621 
    622     def SetLabelAlpha(self, alpha):
    623         self.sr.label.opacity = alpha
    624 
    625     def UpdateTutorialHighlight(self, isActive):
    626         frame = getattr(self, 'tutorialHighlight', None)
    627         if isActive:
    628             from eve.client.script.ui.services.tutoriallib import TutorialColor
    629             if frame is None:
    630                 self.tutorialHighlight = Fill(parent=self, color=TutorialColor.HINT_FRAME, opacity=0.0)
    631                 animations.FadeTo(self.tutorialHighlight, 0.0, 0.8, duration=1.6, curveType=uiconst.ANIM_WAVE, loops=uiconst.ANIM_REPEAT)
    632         elif frame is not None:
    633             self.tutorialHighlight.Close()
    634             self.tutorialHighlight = None
    635 
    636 
    637 def get_distance_in_meters(meters):
    638     return localization.GetByLabel('/Carbon/UI/Common/FormatDistance/fmtDistInMeters', distance=meters)
    639 
    640 
    641 def get_distance_in_kilometers(kilometers):
    642     return localization.GetByLabel('/Carbon/UI/Common/FormatDistance/fmtDistInKiloMeters', distance=kilometers)
    643 
    644 
    645 def get_distance_in_au(au):
    646     return localization.GetByLabel('/Carbon/UI/Common/FormatDistance/fmtDistInAU', distance=au)
    647 
    648 
    649 FMTFUNCTION = localization.formatters.FormatNumeric