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

targetInBar.py (44132B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\inflight\bracketsAndTargets\targetInBar.py
      2 import _weakref
      3 import math
      4 import appConst
      5 import eveicon
      6 import mining
      7 import random
      8 import blue
      9 import evetypes
     10 import localization
     11 import telemetry
     12 import trinity
     13 import uthread
     14 import uthread2
     15 import utillib
     16 from carbon.common.script.util import commonutils, timerstuff
     17 from carbon.common.script.util.format import FmtDist
     18 from carbonui import uiconst, Align, PickState
     19 from carbonui.primitives.container import Container
     20 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     21 from carbonui.primitives.frame import Frame
     22 from carbonui.primitives.sprite import Sprite
     23 from carbonui.primitives.transform import Transform
     24 from carbonui.uianimations import animations
     25 from carbonui.uiconst import BlendMode, OutputMode
     26 from carbonui.uicore import uicore
     27 from chroma import Color
     28 from eve.client.script.parklife import states as state
     29 from eve.client.script.ui import eveColor
     30 from eve.client.script.ui.control import eveIcon, eveLabel
     31 from eve.client.script.ui.inflight.bracketsAndTargets.bracketVarious import GetIconColor
     32 from eve.client.script.ui.inflight.bracketsAndTargets.activeTargetIndicator import ActiveTargetIndicator
     33 from eve.client.script.ui.inflight.bracketsAndTargets.weaponIcons import FighterAbilityWeapon, Weapon
     34 from eve.client.script.ui.inflight.squadrons.shipFighterState import GetShipFighterState
     35 from eve.client.script.ui.shared.stateFlag import AddAndSetFlagIcon
     36 from eve.client.script.ui.util import uix
     37 from eveservices.menu import GetMenuService
     38 from gametime import GetDurationInClient
     39 from mining.client import mining_signals
     40 from mining.client.asteroid_scanning_service import AsteroidScanningService
     41 from mining.client.ui.asteroid_quantity_gauge_circular import AsteroidQuantityGaugeCircular
     42 from spacecomponents.client.messages import MSG_ON_TARGET_BRACKET_ADDED, MSG_ON_TARGET_BRACKET_REMOVED
     43 from spacecomponents.common.helper import HasMineableComponent
     44 accuracyThreshold = 0.8
     45 SHIELD = 0
     46 ARMOR = 1
     47 HULL = 2
     48 HOVERTIME = 250
     49 
     50 class TargetInBar(ContainerAutoSize):
     51     __guid__ = 'uicls.TargetInBar'
     52     __notifyevents__ = ['ProcessShipEffect',
     53      'OnStateChange',
     54      'OnJamStart',
     55      'OnJamEnd',
     56      'OnSlimItemChange',
     57      'OnDroneStateChange2',
     58      'OnDroneControlLost',
     59      'OnStateSetupChange',
     60      'OnSetPlayerStanding',
     61      'OnItemNameChange',
     62      'OnUIRefresh',
     63      'OnFleetJoin_Local',
     64      'OnFleetLeave_Local',
     65      'OnSuspectsAndCriminalsUpdate',
     66      'OnDisapprovalUpdate',
     67      'OnCrimewatchEngagementUpdated']
     68 
     69     def ApplyAttributes(self, attributes):
     70         super(TargetInBar, self).ApplyAttributes(attributes)
     71         self.lastDistance = None
     72         self.sr.updateTimer = None
     73         self.drones = {}
     74         self.activeModules = set([])
     75         self.lastDataUsedForLabel = None
     76         self.lastTextUsedForLabel = None
     77         self.lastTextUsedDistance = None
     78         self.lastTextUsedForShipType = None
     79         self.itemID = None
     80         self.slimItem = None
     81         self.weaponsOnTarget = {}
     82         self.jammingModules = {}
     83         self.innerHealthBorder = pow(28, 2)
     84         self.outerHealthBorder = pow(42, 2)
     85         self._hoverThread = None
     86         self.fleetTag = None
     87         self.healthBar = None
     88         self.asteroid_gauge = None
     89         self.connect_signals()
     90 
     91     def Close(self):
     92         super(TargetInBar, self).Close()
     93         self.disconnect_signals()
     94 
     95     def connect_signals(self):
     96         mining_signals.on_mining_scan_completed.connect(self.on_mining_scan_completed)
     97         mining_signals.on_mining_overlay_disabled.connect(self.on_mining_overlay_disabled)
     98         mining_signals.on_mining_scan_data_cleared.connect(self.on_mining_scan_data_cleared)
     99 
    100     def disconnect_signals(self):
    101         mining_signals.on_mining_scan_completed.disconnect(self.on_mining_scan_completed)
    102         mining_signals.on_mining_overlay_disabled.disconnect(self.on_mining_overlay_disabled)
    103         mining_signals.on_mining_scan_data_cleared.disconnect(self.on_mining_scan_data_cleared)
    104 
    105     def on_mining_scan_data_cleared(self):
    106         self.check_show_asteroid_gauge()
    107 
    108     def on_mining_overlay_disabled(self):
    109         self.check_show_asteroid_gauge()
    110 
    111     def on_mining_scan_completed(self):
    112         self.check_show_asteroid_gauge()
    113 
    114     def OnUIRefresh(self):
    115         self.Flush()
    116         bp = sm.GetService('michelle').GetBallpark()
    117         if bp is not None:
    118             slimItem = bp.GetInvItem(self.id)
    119         self.Startup(slimItem)
    120 
    121     def GetTargetDragData(self, *args):
    122         if settings.user.ui.Get('targetPositionLocked', 0):
    123             return []
    124         return [self]
    125 
    126     def Startup(self, slimItem):
    127         sm.RegisterNotify(self)
    128         GetShipFighterState().ConnectFighterTargetUpdatedHandler(self._OnFighterTargetUpdate)
    129         self.ball = _weakref.ref(sm.GetService('michelle').GetBall(slimItem.itemID))
    130         self.slimItem = _weakref.ref(slimItem)
    131         self.id = slimItem.itemID
    132         self.itemID = slimItem.itemID
    133         self.typeID = slimItem.typeID
    134         self.AddUIObjects(slimItem, self.itemID)
    135         barAndImageCont = self.barAndImageCont
    136         barAndImageCont.isDragObject = True
    137         barAndImageCont.GetDragData = self.GetTargetDragData
    138         barAndImageCont.OnMouseDown = self.OnTargetMouseDown
    139         barAndImageCont.OnClick = self.OnTargetClick
    140         barAndImageCont.GetMenu = self.GetTargetMenu
    141         barAndImageCont.OnMouseEnter = self.OnTargetMouseEnter
    142         barAndImageCont.OnMouseExit = self.OnTargetMouseExit
    143         self.active_target_transform = Transform(parent=self.icon_container, scalingCenter=(0.5, 0.5), align=Align.CENTER, width=self.icon_container.width, height=self.icon_container.height)
    144         self.active_target_indicator = ActiveTargetIndicator(parent=self.active_target_transform, itemID=self.itemID)
    145         self.slimForFlag = slimItem
    146         self.SetStandingIcon()
    147         if slimItem.categoryID == appConst.categoryEntity:
    148             self.SetBracketIcon()
    149         self.SetFleetTag(sm.GetService('fleet').GetTargetTag(self.itemID))
    150         self.sr.hilite = Sprite(name='hiliteSprite', parent=self.icon_container, left=-3, top=-3, width=100, height=100, texturePath='res:/UI/Texture/classes/Target/targetUnderlay.png', color=(1.0, 1.0, 1.0, 0.05))
    151         self.active_target_indicator.RotateArrows()
    152         labelClass = eveLabel.EveLabelSmall
    153         labelContainer = ContainerAutoSize(parent=self, name='labelContainer', align=uiconst.TOTOP)
    154         self.labelContainer = labelContainer
    155         self.sr.label = labelClass(text=' ', parent=labelContainer, align=uiconst.TOTOP, state=uiconst.UI_DISABLED, maxLines=1)
    156         self.sr.label2 = labelClass(text=' ', parent=labelContainer, align=uiconst.TOTOP, state=uiconst.UI_DISABLED, maxLines=1)
    157         self.sr.shipLabel = labelClass(text=' ', parent=labelContainer, align=uiconst.TOTOP, state=uiconst.UI_DISABLED, maxLines=1)
    158         self.sr.distanceLabel = labelClass(text=' ', parent=labelContainer, align=uiconst.TOTOP, state=uiconst.UI_DISABLED, maxLines=1)
    159         self.SetTargetLabel()
    160         self.sr.assignedPar = Container(name='assignedPar', align=uiconst.TOTOP, parent=self, height=32)
    161         self.sr.assigned = Container(name='assigned', align=uiconst.CENTERTOP, parent=self.sr.assignedPar, height=32)
    162         self.sr.updateTimer = timerstuff.AutoTimer(random.randint(750, 1000), self.UpdateData)
    163         self.UpdateData()
    164         selected = sm.GetService('stateSvc').GetExclState(state.selected)
    165         self.Select(selected == slimItem.itemID)
    166         hilited = sm.GetService('stateSvc').GetExclState(state.mouseOver)
    167         self.Hilite(hilited == slimItem.itemID)
    168         activeTargetID = sm.GetService('target').GetActiveTargetID()
    169         self.ActiveTarget(activeTargetID == slimItem.itemID)
    170         drones = sm.GetService('michelle').GetDrones()
    171         for key in drones:
    172             droneState = drones[key]
    173             if droneState.targetID == self.id:
    174                 self.drones[droneState.droneID] = droneState.typeID
    175 
    176         self.UpdateDrones()
    177         for moduleInfo in sm.GetService('godma').GetStateManager().GetActiveModulesOnTargetID(slimItem.itemID):
    178             if moduleInfo:
    179                 moduleID = moduleInfo.itemID
    180                 if moduleID and moduleID not in self.activeModules:
    181                     self.AddWeapon(moduleInfo)
    182 
    183         self._AddActiveFighterAbilities()
    184 
    185     def has_damage_bar(self):
    186         if not self.slimItem:
    187             return False
    188         slimItem = self.slimItem()
    189         return slimItem.categoryID not in (appConst.categoryAsteroid, appConst.categoryFighter) and slimItem.groupID not in (appConst.groupHarvestableCloud, appConst.groupOrbitalTarget) and not HasMineableComponent(self.typeID)
    190 
    191     def AddUIDeathObjects(self, discSize):
    192         self.remove_animation_icon = Sprite(name='remove_animation_icon', parent=self.icon_container, align=uiconst.CENTER, display=False, width=64, height=64, blendMode=BlendMode.ADD, outputMode=OutputMode.COLOR_AND_GLOW, glowBrightness=0.0)
    193         self.discSprite = Sprite(name='discSprite', parent=self.icon_container, pickState=PickState.OFF, align=uiconst.CENTER, texturePath='res:/UI/Texture/Icons/target_killed.png', width=discSize, height=discSize)
    194         self.discSprite.display = False
    195         self.lineSprite = Sprite(name='lineSprite', parent=self.barAndImageCont, align=uiconst.CENTER, texturePath='res:/UI/Texture/Icons/target_killed_line.png', width=100, height=100)
    196         self.lineSprite.display = False
    197 
    198     def AddUIObjects(self, slimItem, itemID = None, **kwargs):
    199         barAndImageCont = Container(parent=self, name='barAndImageCont', align=uiconst.TOTOP, height=100, state=uiconst.UI_NORMAL)
    200         self.barAndImageCont = barAndImageCont
    201         self.iconSize = iconSize = 94
    202         self.icon_container = Transform(parent=barAndImageCont, name='iconPar', width=iconSize, height=iconSize, align=uiconst.CENTERTOP, state=uiconst.UI_DISABLED, scalingCenter=(0.5, 0.5))
    203         self.AddUIDeathObjects(94)
    204         maskSize = 50
    205         iconPadding = (iconSize - maskSize) / 2
    206         self.icon = eveIcon.Icon(parent=self.icon_container, left=iconPadding, top=iconPadding, width=maskSize, height=maskSize, typeID=slimItem.typeID, textureSecondaryPath='res:/UI/Texture/classes/Target/shipMask.png', color=(1.0, 1.0, 1.0, 1.0), blendMode=BlendMode.BLEND, spriteEffect=trinity.TR2_SFX_MODULATE, state=uiconst.UI_DISABLED, ignoreSize=True)
    207         if slimItem.groupID == appConst.groupOrbitalTarget:
    208             sm.GetService('photo').GetPortrait(slimItem.ownerID, 64, self.icon)
    209         if self.has_damage_bar():
    210             self.healthBar = TargetHealthBars(parent=self.icon_container, itemID=itemID)
    211         else:
    212             self.check_show_asteroid_gauge()
    213         self.circle = Sprite(name='circle', align=uiconst.CENTER, parent=self.icon_container, width=iconSize + 2, height=iconSize + 2, texturePath='res:/UI/Texture/classes/Target/outerCircle.png', color=(1.0, 1.0, 1.0, 0.5), state=uiconst.UI_DISABLED)
    214 
    215     def check_show_asteroid_gauge(self):
    216         if self.has_asteroid_gauge():
    217             if not self.asteroid_gauge:
    218                 self.construct_asteroid_quantity_gauge()
    219         elif self.asteroid_gauge:
    220             self.asteroid_gauge.Close()
    221             self.asteroid_gauge = None
    222 
    223     def construct_asteroid_quantity_gauge(self):
    224         self.asteroid_gauge = AsteroidQuantityGaugeCircular(parent=self.icon_container, asteroid_id=self.itemID, align=Align.CENTER, pickState=PickState.OFF)
    225 
    226     def has_asteroid_gauge(self):
    227         if not self.slimItem:
    228             return False
    229         slimItem = self.slimItem()
    230         if not slimItem:
    231             return False
    232         return mining.is_harvestable(slimItem.typeID) and AsteroidScanningService.get_instance().is_quantity_known(slimItem.itemID)
    233 
    234     def OnItemNameChange(self, *args):
    235         uthread.new(self.SetTargetLabel)
    236 
    237     def SetTargetLabel(self):
    238         self.label = uix.GetSlimItemName(self.slimForFlag)
    239         if self.slimForFlag.corpID:
    240             self.label = localization.GetByLabel('UI/Inflight/Target/TargetLabelWithTicker', target=uix.GetSlimItemName(self.slimForFlag), ticker=cfg.corptickernames.Get(self.slimForFlag.corpID).tickerName)
    241         if self.slimForFlag.corpID and self.slimForFlag.typeID and self.slimForFlag.categoryID == appConst.categoryShip:
    242             self.shipLabel = evetypes.GetName(self.slimForFlag.typeID)
    243         else:
    244             self.shipLabel = ''
    245         self.UpdateData()
    246 
    247     def OnSetPlayerStanding(self, *args):
    248         self.SetStandingIcon()
    249 
    250     def OnStateSetupChange(self, *args):
    251         self.SetStandingIcon()
    252 
    253     def SetStandingIcon(self):
    254         stateMgr = sm.GetService('stateSvc')
    255         flag = stateMgr.CheckStates(self.slimForFlag, 'flag')
    256         self.standingIcon = AddAndSetFlagIcon(parentCont=self.icon_container, flag=flag, align=uiconst.CENTERBOTTOM, top=8, left=0, showHint=False)
    257 
    258     def SetBracketIcon(self):
    259         slimItem = self.slimItem()
    260         if not slimItem:
    261             return
    262         bracketData = sm.GetService('bracket').GetBracketDataByTypeID(slimItem.typeID)
    263         if not bracketData:
    264             return
    265         texturePath = bracketData.texturePath
    266         if not texturePath:
    267             return
    268         iconColor = GetIconColor(slimItem)
    269         if not getattr(self, 'bracketIcon', None) or self.bracketIcon.destroyed:
    270             self.bracketIcon = Sprite(parent=self.icon_container, align=uiconst.CENTERBOTTOM, pos=(0, 5, 16, 16))
    271         self.bracketIcon.SetRGBA(*iconColor)
    272         self.bracketIcon.SetTexturePath(texturePath)
    273 
    274     def OnSuspectsAndCriminalsUpdate(self, criminalizedCharIDs, decriminalizedCharIDs):
    275         return self._UpdateOnSuspectCriminalAndDisapprovalChanges(criminalizedCharIDs, decriminalizedCharIDs)
    276 
    277     def OnDisapprovalUpdate(self, newCharIDs, removedCharIDs):
    278         return self._UpdateOnSuspectCriminalAndDisapprovalChanges(newCharIDs, removedCharIDs)
    279 
    280     def _UpdateOnSuspectCriminalAndDisapprovalChanges(self, newCharIDs, removedCharIDs):
    281         if self.slimForFlag.charID in newCharIDs or self.slimForFlag.charID in removedCharIDs:
    282             self.SetStandingIcon()
    283 
    284     def OnCrimewatchEngagementUpdated(self, otherCharId, timeout):
    285         if self.slimForFlag.charID == otherCharId:
    286             self.SetStandingIcon()
    287 
    288     def OnFleetJoin_Local(self, member, *args):
    289         if session.charid == member.charID or self.slimForFlag.charID == member.charID:
    290             self.SetStandingIcon()
    291 
    292     def OnFleetLeave_Local(self, member, *args):
    293         if session.charid == member.charID or self.slimForFlag.charID == member.charID:
    294             self.SetStandingIcon()
    295 
    296     def SetFleetTag(self, fleetTag):
    297         if not session.fleetid or fleetTag in (None, ''):
    298             if self.fleetTag:
    299                 self.fleetTag.Close()
    300                 self.fleetTag = None
    301             return
    302         if self.fleetTag is None or self.fleetTag.destroyed:
    303             self.fleetTag = eveLabel.EveLabelMediumBold(parent=self.icon_container, align=uiconst.CENTERBOTTOM, left=15, top=8, idx=0)
    304         self.fleetTag.text = fleetTag
    305 
    306     def OnSlimItemChange(self, oldSlim, newSlim):
    307         uthread.new(self._OnSlimItemChange, oldSlim, newSlim)
    308 
    309     def _OnSlimItemChange(self, oldSlim, newSlim):
    310         if self.itemID != oldSlim.itemID or self.destroyed:
    311             return
    312         self.itemID = newSlim.itemID
    313         self.slimItem = _weakref.ref(newSlim)
    314         if oldSlim.corpID != newSlim.corpID or oldSlim.charID != newSlim.charID:
    315             self.label = uix.GetSlimItemName(newSlim)
    316             self.UpdateData()
    317 
    318     def OnStateChange(self, itemID, flag, true, *args):
    319         if not self.destroyed:
    320             uthread.new(self._OnStateChange, itemID, flag, true)
    321 
    322     def _OnStateChange(self, itemID, flag, true):
    323         if self.destroyed or self.itemID != itemID:
    324             return
    325         if flag == state.mouseOver:
    326             self.Hilite(true)
    327         elif flag == state.selected:
    328             self.Select(true)
    329         elif flag == state.activeTarget:
    330             self.ActiveTarget(true)
    331 
    332     def Hilite(self, state):
    333         if self.sr.hilite:
    334             self.sr.hilite.state = [uiconst.UI_HIDDEN, uiconst.UI_DISABLED][state]
    335 
    336     def Select(self, state):
    337         pass
    338 
    339     def OnJamStart(self, sourceBallID, moduleID, targetBallID, jammingType, startTime, duration):
    340         if targetBallID != self.id:
    341             return
    342         durationInClient = GetDurationInClient(startTime, duration)
    343         if durationInClient < 0.0:
    344             return
    345         moduleInfo = self.GetModuleInfo(moduleID)
    346         if moduleInfo and moduleID not in self.activeModules:
    347             self.AddWeapon(moduleInfo)
    348         self.jammingModules[moduleID] = (sourceBallID,
    349          moduleID,
    350          targetBallID,
    351          startTime,
    352          duration)
    353         self.StartTimer(moduleID, durationInClient)
    354 
    355     def OnJamEnd(self, sourceBallID, moduleID, targetBallID, jammingType):
    356         if not self or self.destroyed:
    357             return
    358         if moduleID in self.jammingModules:
    359             moduleIconCont = self.GetWeapon(moduleID)
    360             if moduleIconCont:
    361                 if moduleIconCont.icon:
    362                     moduleIconCont.StopAnimations()
    363                     moduleIconCont.opacity = 1.0
    364                     moduleIconCont.icon.SetRGBA(1, 1, 1, 1.0)
    365                     moduleIconCont.icon.baseAlpha = 0.3
    366                 self.RemoveTimer(moduleID)
    367             del self.jammingModules[moduleID]
    368 
    369     def StartTimer(self, moduleID, duration, *args):
    370         moduleIconCont = self.GetWeapon(moduleID)
    371         if moduleIconCont and moduleIconCont.icon and moduleIconCont.timer:
    372             moduleIconCont.icon.SetRGBA(1, 1, 1, 1.0)
    373             moduleIconCont.icon.baseAlpha = 1.0
    374             moduleIconCont.timer.StartTimer(duration)
    375 
    376     def RemoveTimer(self, moduleID, *args):
    377         moduleIconCont = self.GetWeapon(moduleID)
    378         if moduleIconCont and moduleIconCont.icon and moduleIconCont.timer:
    379             moduleIconCont.icon.SetRGBA(1, 1, 1, moduleIconCont.icon.baseAlpha)
    380 
    381     def _HoverThread(self):
    382         while True:
    383             blue.synchro.SleepWallclock(HOVERTIME)
    384             self.OnTargetMouseHover()
    385 
    386     def KillHoverThread(self, *args):
    387         if self._hoverThread:
    388             self._hoverThread.kill()
    389             self._hoverThread = None
    390 
    391     def OnTargetMouseHover(self, *args):
    392         if not self.icon_container or self.icon_container.destroyed or not self.healthBar:
    393             self.KillHoverThread()
    394             return
    395         if self.healthBar.destroyed:
    396             self.KillHoverThread()
    397             return
    398         l, t, w, h = self.icon_container.GetAbsolute()
    399         cX = w / 2 + l
    400         cY = h / 2 + t
    401         x = uicore.uilib.x - cX
    402         y = uicore.uilib.y - cY
    403         if y > 55:
    404             self.barAndImageCont.SetHint('')
    405             return
    406         length2 = pow(x, 2) + pow(y, 2)
    407         if length2 < self.innerHealthBorder or length2 > self.outerHealthBorder:
    408             self.barAndImageCont.SetHint('')
    409             return
    410         rad = math.atan2(y, x)
    411         degrees = 180 * rad / math.pi
    412         if degrees < 0:
    413             degrees = 360 + degrees
    414         if degrees > 45 and degrees < 135:
    415             return
    416         self.SetHintText()
    417 
    418     def SetHintText(self):
    419         hintList = []
    420         percLeft = self.healthBar.GetDamageHint(SHIELD)
    421         if percLeft is not None:
    422             percLeft = math.floor(100 * percLeft)
    423             hintList.append(localization.GetByLabel('UI/Inflight/Target/GaugeShieldRemaining', percentage=percLeft))
    424         percLeft = self.healthBar.GetDamageHint(ARMOR)
    425         if percLeft is not None:
    426             percLeft = math.floor(100 * percLeft)
    427             hintList.append(localization.GetByLabel('UI/Inflight/Target/GaugeArmorRemaining', percentage=percLeft))
    428         percLeft = self.healthBar.GetDamageHint(HULL)
    429         if percLeft is not None:
    430             percLeft = math.floor(100 * percLeft)
    431             hintList.append(localization.GetByLabel('UI/Inflight/Target/GaugeStructureRemaining', percentage=percLeft))
    432         hint = '<br>'.join(hintList)
    433         self.barAndImageCont.SetHint(hint)
    434 
    435     def GetShipID(self):
    436         return self.itemID
    437 
    438     def GetIcon(self, icon, typeID, size):
    439         if not self.destroyed:
    440             icon.LoadIconByTypeID(typeID)
    441             icon.SetSize(size, size)
    442 
    443     def _OnClose(self, *args):
    444         sm.UnregisterNotify(self)
    445         self.sr.updateTimer = None
    446         GetShipFighterState().DisconnectFighterTargetUpdatedHandler(self._OnFighterTargetUpdate)
    447 
    448     def _AddActiveFighterAbilities(self):
    449         abilitiesOnTarget = GetShipFighterState().abilityTargetTracker.GetFighterAbilitiesForTarget(self.itemID)
    450         for fighterID, abilitySlotID in abilitiesOnTarget:
    451             self._AddFighterAbility(fighterID, abilitySlotID)
    452 
    453         self.ArrangeWeapons()
    454         self.SetSizeAutomatically()
    455         uthread.new(sm.GetService('target').AdjustRowSize)
    456 
    457     def _OnFighterTargetUpdate(self, fighterID, abilitySlotID, targetID):
    458         if targetID != self.itemID:
    459             return
    460         abilitiesOnTarget = GetShipFighterState().abilityTargetTracker.GetFighterAbilitiesForTarget(self.itemID)
    461         if (fighterID, abilitySlotID) in abilitiesOnTarget:
    462             if (fighterID, abilitySlotID) not in self.activeModules:
    463                 self._AddFighterAbility(fighterID, abilitySlotID)
    464         else:
    465             self._RemoveFighterAbility(fighterID, abilitySlotID)
    466         self.ArrangeWeapons()
    467         self.SetSizeAutomatically()
    468         uthread.new(sm.GetService('target').AdjustRowSize)
    469 
    470     def _AddFighterAbility(self, fighterID, abilitySlotID):
    471         cont = FighterAbilityWeapon(parent=self.sr.assigned, fighterID=fighterID, abilitySlotID=abilitySlotID)
    472         self.activeModules.add((fighterID, abilitySlotID))
    473 
    474     def _RemoveFighterAbility(self, fighterID, abilitySlotID):
    475         iconCont = self.GetWeapon((fighterID, abilitySlotID))
    476         if iconCont:
    477             iconCont.Close()
    478         self.activeModules.discard((fighterID, abilitySlotID))
    479 
    480     def ProcessShipEffect(self, godmaStm, effectState):
    481         slimItem = self.slimItem()
    482         if slimItem and effectState.environment[3] == slimItem.itemID:
    483             if effectState.start:
    484                 if self.GetWeapon(effectState.itemID):
    485                     return
    486                 moduleInfo = self.GetModuleInfo(effectState.itemID)
    487                 if moduleInfo:
    488                     self.AddWeapon(moduleInfo)
    489             else:
    490                 self.RemoveWeapon(effectState.itemID)
    491 
    492     def AddWeapon(self, moduleInfo):
    493         if self is None or self.destroyed:
    494             return
    495         cont = Weapon(parent=self.sr.assigned, moduleInfo=moduleInfo, getJammingInfoFunc=self.GetJammingModuleInfo)
    496         self.activeModules.add(moduleInfo.itemID)
    497         self.ArrangeWeapons()
    498         self.SetSizeAutomatically()
    499         uthread.new(sm.GetService('target').AdjustRowSize)
    500 
    501     def GetJammingModuleInfo(self, moduleID):
    502         if moduleID in self.jammingModules:
    503             sourceBallID, moduleID, targetBallID, startTime, duration = self.jammingModules[moduleID]
    504             return utillib.KeyVal(startTime=startTime, duration=duration)
    505 
    506     def IsEffectActivatible(self, effect):
    507         return effect.isDefault and effect.effectName != 'online' and effect.effectCategory in (appConst.dgmEffActivation, appConst.dgmEffTarget)
    508 
    509     def RemoveWeapon(self, moduleID):
    510         iconCont = self.GetWeapon(moduleID)
    511         if iconCont:
    512             iconCont.Close()
    513         self.activeModules.discard(moduleID)
    514         self.ArrangeWeapons()
    515         self.SetSizeAutomatically()
    516         uthread.new(sm.GetService('target').AdjustRowSize)
    517 
    518     def ArrangeWeapons(self):
    519         if self and not self.destroyed and self.sr.assigned:
    520             numWeapons = len(self.sr.assigned.children)
    521             if numWeapons > 2:
    522                 size = 24
    523             else:
    524                 size = 32
    525             left = 0
    526             top = 0
    527             row = 0
    528             column = -1
    529             maxColumns = 4
    530             for cont in self.sr.assigned.children:
    531                 if isinstance(cont, Frame):
    532                     continue
    533                 column += 1
    534                 if column >= maxColumns:
    535                     column = 0
    536                     row += 1
    537                 cont.width = cont.height = size
    538                 cont.left = column * size
    539                 cont.top = row * size
    540                 cont.state = uiconst.UI_PICKCHILDREN
    541 
    542             if row > 0:
    543                 self.sr.assigned.width = maxColumns * size
    544             else:
    545                 self.sr.assigned.width = size * (column + 1)
    546             self.sr.assigned.height = max(32, size * (row + 1))
    547             self.sr.assignedPar.height = self.sr.assigned.height
    548 
    549     def GetWeapon(self, moduleID):
    550         if self is None or self.destroyed:
    551             return
    552         if self.sr.assigned:
    553             for cont in self.sr.assigned.children:
    554                 if isinstance(cont, Frame):
    555                     continue
    556                 if cont.sr.moduleID == moduleID:
    557                     return cont
    558 
    559     def GetModuleInfo(self, moduleID):
    560         ship = sm.GetService('godma').GetItem(session.shipid)
    561         if ship is None:
    562             return
    563         for module in ship.modules:
    564             if module.itemID == moduleID:
    565                 return module
    566 
    567     def ResetModuleIcon(self, moduleID, *args):
    568         if moduleID in self.activeModules:
    569             weapon = self.GetWeapon(moduleID)
    570             icon = weapon.icon
    571             icon.SetAlpha(icon.baseAlpha)
    572 
    573     def OnTargetClick(self, *args):
    574         sm.GetService('stateSvc').SetState(self.itemID, state.selected, 1)
    575         sm.GetService('stateSvc').SetState(self.itemID, state.activeTarget, 1)
    576         GetMenuService().TacticalItemClicked(self.itemID)
    577 
    578     def GetTargetMenu(self):
    579         m = []
    580         m += GetMenuService().CelestialMenu(self.itemID)
    581         return m
    582 
    583     def OnTargetMouseDown(self, *args):
    584         if getattr(self, 'slimItem', None):
    585             if GetMenuService().TryExpandActionMenu(self.itemID, self.barAndImageCont):
    586                 return
    587 
    588     def OnBeginMoveTarget(self, *args):
    589         sm.GetService('target').OnMoveTarget(self)
    590 
    591     def OnTargetMouseEnter(self, *args):
    592         sm.GetService('stateSvc').SetState(self.id, state.mouseOver, 1)
    593         if self._hoverThread is None:
    594             self._hoverThread = uthread.new(self._HoverThread)
    595 
    596     def OnTargetMouseExit(self, *args):
    597         sm.GetService('stateSvc').SetState(self.itemID, state.mouseOver, 0)
    598         self.KillHoverThread()
    599 
    600     @telemetry.ZONE_METHOD
    601     def UpdateData(self):
    602         ball = self.ball()
    603         if not ball:
    604             return
    605         dist = ball.surfaceDist
    606         distanceInMeters = int(dist)
    607         if self.label != self.lastTextUsedForLabel:
    608             self.SetNameLabels(fullLabel=self.label)
    609             self.lastTextUsedForLabel = self.label
    610         if distanceInMeters != self.lastTextUsedDistance:
    611             self.sr.distanceLabel.text = '<center>' + FmtDist(dist)
    612             self.FadeText(self.sr.label2)
    613             self.lastTextUsedDistance = distanceInMeters
    614         if self.shipLabel != self.lastTextUsedForShipType:
    615             if self.shipLabel:
    616                 self.sr.shipLabel.display = True
    617                 self.sr.shipLabel.text = '<center>' + self.shipLabel
    618                 self.FadeText(self.sr.shipLabel)
    619                 self.lastTextUsedForShipType = self.shipLabel
    620             else:
    621                 self.sr.shipLabel.text = ''
    622                 self.sr.shipLabel.display = False
    623 
    624     def SetNameLabels(self, fullLabel, *args):
    625         hintMarkupStart = ''
    626         hintMarkupEnd = ''
    627         localizedHintPos = fullLabel.find('<localized hint')
    628         if localizedHintPos >= 0:
    629             strippedLabel = commonutils.StripTags(fullLabel, stripOnly=['localized'])
    630             hintEndIndex = fullLabel.find('">')
    631             if hintEndIndex > 0:
    632                 hintMarkupStart = fullLabel[localizedHintPos:hintEndIndex + 2]
    633                 hintMarkupEnd = '</localized>'
    634         else:
    635             strippedLabel = fullLabel
    636         self.sr.label.text = strippedLabel
    637         indexAtMaxLenght = self.sr.label.GetIndexUnderPos(self.width)
    638         if indexAtMaxLenght[0] < len(strippedLabel):
    639             lastBreak = strippedLabel.rfind(' ', 0, indexAtMaxLenght[0])
    640             if lastBreak != -1:
    641                 self.sr.label.text = strippedLabel[:lastBreak]
    642             self.sr.label2.text = '<center>' + hintMarkupStart + strippedLabel[lastBreak:].strip() + hintMarkupEnd
    643             self.FadeText(self.sr.label2)
    644             self.sr.label2.display = True
    645         else:
    646             self.sr.label2.text = ''
    647             self.sr.label2.display = False
    648         self.sr.label.text = '<center>' + hintMarkupStart + self.sr.label.text + hintMarkupEnd
    649         self.lastTextUsedForLabel = self.label
    650 
    651     def FadeText(self, textLabel, *args):
    652         maxFadeWidth = 10
    653         fadeEnd = self.width - maxFadeWidth
    654         textLabel.SetRightAlphaFade(fadeEnd=fadeEnd, maxFadeWidth=maxFadeWidth)
    655 
    656     def ActiveTarget(self, true):
    657         if self.destroyed:
    658             return
    659         targetSvc = sm.GetService('target')
    660         if true:
    661             if not targetSvc.disableSpinnyReticule:
    662                 self.active_target_indicator.state = uiconst.UI_DISABLED
    663             self.icon_container.opacity = 1.0
    664             self.circle.opacity = 0.5
    665         else:
    666             self.icon_container.width = self.icon_container.height = self.iconSize
    667             self.active_target_indicator.state = uiconst.UI_HIDDEN
    668             self.icon_container.opacity = 0.8
    669             self.circle.opacity = 0.25
    670 
    671     def OnDroneStateChange2(self, itemID, oldActivityState, activityState):
    672         michelle = sm.GetService('michelle')
    673         droneState = michelle.GetDroneState(itemID)
    674         if activityState in (appConst.entityCombat,
    675          appConst.entityEngage,
    676          appConst.entityMining,
    677          appConst.entitySalvaging):
    678             if droneState and droneState.targetID == self.id:
    679                 self.drones[itemID] = droneState.typeID
    680             elif itemID in self.drones:
    681                 del self.drones[itemID]
    682         elif itemID in self.drones:
    683             del self.drones[itemID]
    684         self.UpdateDrones()
    685 
    686     def OnDroneControlLost(self, droneID):
    687         if droneID in self.drones:
    688             del self.drones[droneID]
    689         self.UpdateDrones()
    690 
    691     def UpdateDrones(self):
    692         if not self.drones:
    693             self.RemoveWeapon('drones')
    694             return
    695         droneIconCont = self.GetWeapon('drones')
    696         if not droneIconCont:
    697             cont = Container(parent=self.sr.assigned, align=uiconst.RELATIVE, width=32, height=32, state=uiconst.UI_HIDDEN)
    698             icon = Sprite(parent=cont, align=uiconst.TOALL, width=0, height=0, state=uiconst.UI_NORMAL, texturePath='res:/UI/Texture/Icons/56_64_5.png')
    699             cont.sr.moduleID = 'drones'
    700             cont.icon = icon
    701             icon.sr.moduleID = 'drones'
    702             self.ArrangeWeapons()
    703         self.UpdateDroneHint()
    704 
    705     def UpdateDroneHint(self):
    706         dronesByTypeID = {}
    707         droneIcon = self.GetWeapon('drones')
    708         if droneIcon is None:
    709             return
    710         for droneID, droneTypeID in self.drones.iteritems():
    711             if droneTypeID not in dronesByTypeID:
    712                 dronesByTypeID[droneTypeID] = 0
    713             dronesByTypeID[droneTypeID] += 1
    714 
    715         hintLines = []
    716         for droneTypeID, number in dronesByTypeID.iteritems():
    717             hintLines.append(localization.GetByLabel('UI/Inflight/Target/DroneHintLine', drone=droneTypeID, count=number))
    718 
    719         droneIcon.icon.hint = localization.GetByLabel('UI/Inflight/Target/DroneHintLabel', droneHintLines='<br>'.join(hintLines))
    720 
    721     def anim_disappear(self):
    722         if self.has_asteroid_gauge():
    723             self.anim_asteroid_depleted()
    724         else:
    725             self.anim_death()
    726 
    727     def anim_death(self):
    728         self.state = uiconst.UI_DISABLED
    729         if self.healthBar:
    730             self.healthBar.SetDamage([0.0,
    731              0.0,
    732              0.0,
    733              0.0,
    734              0.0])
    735         uthread2.sleep_sim(random.random() * 0.2)
    736         sm.GetService('audio').SendUIEvent('target_destroy_play')
    737         self.discSprite.display = True
    738         discCurve = ((0.0, (1.0, 0.0, 0.0, 0.0)), (0.1, (1.0, 0.0, 0.0, 0.2)), (2.0, (1.0, 0.0, 0.0, 0.2)))
    739         animations.SpColorMorphTo(self.discSprite, curveType=discCurve, duration=0.1)
    740         self.remove_animation_icon.texturePath = 'res:/UI/Texture/Icons/target_killed_skull.png'
    741         self.remove_animation_icon.SetSize(64, 64)
    742         self.remove_animation_icon.display = True
    743         animations.BlinkIn(self, duration=0.2, loops=6, sleep=True)
    744         animations.Tr2DScaleTo(self.icon_container, startScale=(1.0, 1.0), endScale=(1.0, 0.0), sleep=True, duration=0.04, curveType=uiconst.ANIM_LINEAR)
    745         self.icon_container.display = False
    746 
    747     def anim_asteroid_depleted(self):
    748         self.state = uiconst.UI_DISABLED
    749         self.discSprite.display = True
    750         color = Color(a=0.4, *eveColor.SUCCESS_GREEN[:3])
    751         self.discSprite.color = Color(a=0.0, *eveColor.SUCCESS_GREEN[:3])
    752         animations.SpColorMorphTo(self.discSprite, endColor=color, duration=0.6)
    753         animations.BlinkOut(self.icon, loops=2)
    754         self.remove_animation_icon.texturePath = 'res:/UI/Texture/classes/Seasons/Agency/ContentCard/checkmark_claimReward.png'
    755         self.remove_animation_icon.SetSize(36, 36)
    756         self.remove_animation_icon.display = True
    757         animations.FadeTo(self.remove_animation_icon, 0.0, 1.0, duration=0.6, timeOffset=0.1)
    758         animations.SpMaskIn(self.remove_animation_icon, duration=0.3, timeOffset=0.1)
    759         animations.MorphScalar(self.remove_animation_icon, 'glowBrightness', 0.0, 0.6, duration=1.0, timeOffset=0.1, curveType=uiconst.ANIM_OVERSHOT5)
    760         animations.Tr2DScaleOut(self.active_target_transform, duration=0.3, timeOffset=0.1)
    761         uthread2.sleep(1.6)
    762         animations.FadeOut(self, duration=0.15, sleep=True)
    763         self.icon_container.display = False
    764 
    765 
    766 class TargetHealthBars(Container):
    767     __notifyevents__ = ['OnDamageMessage', 'OnDamageMessages']
    768     default_name = 'targetHealthBars'
    769     default_width = 94
    770     default_height = 94
    771     default_align = uiconst.CENTER
    772     allHealthTexture = 'res:/UI/Texture/classes/Target/targetBackground.png'
    773     allHealthMinusShieldTexture = 'res:/UI/Texture/classes/Target/targetBackgroundNoShield.png'
    774     shieldTextureLeft = 'res:/UI/Texture/classes/Target/shieldLeft.png'
    775     shieldTextureRight = 'res:/UI/Texture/classes/Target/shieldRight.png'
    776     armorTextureLeft = 'res:/UI/Texture/classes/Target/armorLeft.png'
    777     armorTextureRight = 'res:/UI/Texture/classes/Target/armorRight.png'
    778     hullTextureLeft = 'res:/UI/Texture/classes/Target/hullLeft.png'
    779     hullTextureRight = 'res:/UI/Texture/classes/Target/hullRight.png'
    780 
    781     def ApplyAttributes(self, attributes):
    782         self.damageValuseForTooltip = {}
    783         Container.ApplyAttributes(self, attributes)
    784         self.itemID = attributes.itemID
    785         self.sr.damageTimer = timerstuff.AutoTimer(random.randint(750, 1000), self.UpdateDamage)
    786         self.width = attributes.get('size', self.default_width)
    787         self.height = attributes.get('size', self.default_height)
    788         self.shieldBar = self.AddHealthBar(name='shieldBar', texturePathLeft=self.shieldTextureLeft, texturePathRight=self.shieldTextureRight)
    789         self.armorBar = self.AddHealthBar(name='armorBar', texturePathLeft=self.armorTextureLeft, texturePathRight=self.armorTextureRight)
    790         self.hullBar = self.AddHealthBar(name='hullBar', texturePathLeft=self.hullTextureLeft, texturePathRight=self.hullTextureRight)
    791         self.healthBarBackground = Sprite(name='healthBarBackground', parent=self, width=self.width, height=self.height, texturePath=self.allHealthTexture, align=uiconst.CENTER, state=uiconst.UI_DISABLED)
    792         self.UpdateDamage()
    793         sm.RegisterNotify(self)
    794         bp = sm.GetService('michelle').GetBallpark()
    795         bp.componentRegistry.SendMessageToItem(self.itemID, MSG_ON_TARGET_BRACKET_ADDED, self)
    796 
    797     def SetGaugeTextureForBar(self, name, texturePath):
    798         if texturePath is None:
    799             texturePath = 'res:/UI/Texture/classes/Target/gaugeColor.png'
    800         bar = getattr(self, name)
    801         bar.leftBar.SetSecondaryTexturePath(texturePath)
    802         bar.rightBar.SetSecondaryTexturePath(texturePath)
    803 
    804     def AddHealthBar(self, name, texturePathLeft, texturePathRight, *args):
    805         cont = Container(name=name, parent=self, width=self.width, height=self.height, align=uiconst.CENTER)
    806         leftBar = Sprite(name='%s_Left' % name, parent=cont, width=self.width, height=self.height, texturePath=texturePathLeft, textureSecondaryPath='res:/UI/Texture/classes/Target/gaugeColor.png', idx=0, blendMode=1, spriteEffect=trinity.TR2_SFX_MODULATE, state=uiconst.UI_DISABLED)
    807         leftBar.baseRotation = 0
    808         leftBar.rotationSecondary = leftBar.baseRotation
    809         rightBar = Sprite(name='%s_Right' % name, parent=cont, width=self.width, height=self.height, texturePath=texturePathRight, textureSecondaryPath='res:/UI/Texture/classes/Target/gaugeColor.png', idx=0, blendMode=1, spriteEffect=trinity.TR2_SFX_MODULATE, state=uiconst.UI_DISABLED)
    810         rightBar.baseRotation = -3 / 4.0 * math.pi
    811         rightBar.rotationSecondary = rightBar.baseRotation
    812         cont.leftBar = leftBar
    813         cont.rightBar = rightBar
    814         return cont
    815 
    816     def UpdateDamage(self):
    817         bp = sm.GetService('michelle').GetBallpark()
    818         if bp is None:
    819             self.sr.damageTimer = None
    820             return
    821         dmg = bp.GetDamageState(self.itemID)
    822         if dmg is not None:
    823             self.PrepareHint(dmg)
    824             self.SetDamage(dmg)
    825 
    826     def PrepareHint(self, state):
    827         for i, layer in enumerate([SHIELD, ARMOR, HULL]):
    828             if state[i] is None:
    829                 self.damageValuseForTooltip[layer] = None
    830             else:
    831                 self.damageValuseForTooltip[layer] = max(0, state[i])
    832 
    833     def SetDamage(self, state, *args):
    834         visible = 0
    835         healthBars = [self.shieldBar, self.armorBar, self.hullBar]
    836         fullAnimationTime = 0.4
    837         for i, healthBar in enumerate(healthBars):
    838             if state[i] is None:
    839                 healthBar.display = False
    840             else:
    841                 healthState = state[i]
    842                 healthState = max(0, healthState)
    843                 lastState = getattr(healthBar, 'lastState', None)
    844                 healthBar.lastState = healthState
    845                 leftBar = healthBar.leftBar
    846                 rightBar = healthBar.rightBar
    847                 if lastState:
    848                     totalChange = healthState - lastState
    849                     animationTime = max(0.1, fullAnimationTime * abs(totalChange))
    850                 else:
    851                     animationTime = None
    852                 if healthState <= 0.5:
    853                     portionOfBar = (0.5 - healthState) / 0.5
    854                     rotation = leftBar.baseRotation + portionOfBar * 0.75 * math.pi
    855                     if lastState and lastState > 0.5:
    856                         below50Damage = lastState - 0.5
    857                         below50Percentage = float(below50Damage) / abs(totalChange)
    858                         if animationTime is None:
    859                             rightBar.rotationSecondary = 0.0
    860                             leftBar.rotationSecondary = rotation
    861                         else:
    862                             curvePoints = ([0, rightBar.rotationSecondary or 0.0], [below50Percentage or 0.0, 0.0])
    863                             uicore.animations.MorphScalar(rightBar, 'rotationSecondary', duration=animationTime, curveType=curvePoints)
    864                             curvePoints = ([0, leftBar.rotationSecondary or 0.0], [below50Percentage or 0.0, leftBar.rotationSecondary or 0.0], [1.0, rotation])
    865                             uicore.animations.MorphScalar(leftBar, 'rotationSecondary', duration=animationTime, curveType=curvePoints)
    866                     else:
    867                         rightBar.rotationSecondary = 0
    868                         if animationTime is None:
    869                             leftBar.rotationSecondary = rotation
    870                         else:
    871                             uicore.animations.MorphScalar(leftBar, 'rotationSecondary', startVal=leftBar.rotationSecondary or 0.0, endVal=rotation, duration=animationTime, curveType=uiconst.ANIM_LINEAR)
    872                 else:
    873                     portionOfBar = (1 - healthState) / 0.5
    874                     rotation = rightBar.baseRotation + portionOfBar * 0.75 * math.pi
    875                     if lastState and lastState <= 0.5:
    876                         above50Damage = 0.5 - lastState
    877                         above50Percentage = float(above50Damage) / abs(totalChange)
    878                         if animationTime is None:
    879                             leftBar.rotationSecondary = leftBar.baseRotation - 0.02
    880                             rightBar.rotationSecondary = rotation
    881                         else:
    882                             curvePoints = ([0, leftBar.rotationSecondary], [above50Percentage, leftBar.baseRotation - 0.02])
    883                             uicore.animations.MorphScalar(leftBar, 'rotationSecondary', duration=animationTime, curveType=curvePoints)
    884                             curvePoints = ([0, rightBar.rotationSecondary], [above50Percentage, rightBar.rotationSecondary], [1.0, rotation])
    885                             uicore.animations.MorphScalar(rightBar, 'rotationSecondary', duration=animationTime, curveType=curvePoints)
    886                     else:
    887                         if animationTime is None:
    888                             rightBar.rotationSecondary = rotation
    889                         else:
    890                             uicore.animations.MorphScalar(rightBar, 'rotationSecondary', startVal=rightBar.rotationSecondary, endVal=rotation, duration=animationTime, curveType=uiconst.ANIM_LINEAR)
    891                         leftBar.rotationSecondary = leftBar.baseRotation - 0.02
    892                 healthBar.display = True
    893                 visible += 1
    894 
    895         if visible == 0:
    896             self.healthBarBackground.display = False
    897         else:
    898             if visible == 2:
    899                 self.healthBarBackground.SetTexturePath(self.allHealthMinusShieldTexture)
    900             else:
    901                 self.healthBarBackground.SetTexturePath(self.allHealthTexture)
    902             self.healthBarBackground.display = True
    903 
    904     def _OnClose(self, *args):
    905         self.sr.damageTimer = None
    906         bp = sm.GetService('michelle').GetBallpark()
    907         bp.componentRegistry.SendMessageToItem(self.itemID, MSG_ON_TARGET_BRACKET_REMOVED)
    908 
    909     def GetDamageHint(self, whichHealthBar, *args):
    910         return self.damageValuseForTooltip.get(whichHealthBar, 1.0)
    911 
    912     def OnDamageMessages(self, dmgmsgs):
    913         for msg in dmgmsgs:
    914             didBlink = self.OnDamageMessage(*msg[1:])
    915             if didBlink:
    916                 break
    917 
    918     def OnDamageMessage(self, damageMessagesArgs):
    919         attackType = damageMessagesArgs.get('attackType', 'me')
    920         if attackType != 'me':
    921             return False
    922         damage = damageMessagesArgs.get('damage', 0)
    923         if damage == 0:
    924             return False
    925         target = damageMessagesArgs.get('target', None)
    926         if target is None:
    927             return False
    928         if isinstance(target, long):
    929             if target == self.itemID:
    930                 self.DoBlink()
    931                 return True
    932         if isinstance(target, basestring):
    933             targetID = damageMessagesArgs.get('target_ID', None)
    934             if targetID == self.itemID:
    935                 self.DoBlink()
    936                 return True
    937         return False
    938 
    939     def DoBlink(self, *args):
    940         uicore.animations.FadeTo(self, startVal=1.3, endVal=1.0, duration=0.75, loops=1, curveType=uiconst.ANIM_OVERSHOT)