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

characterSlots.py (73127B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\login\charSelection\characterSlots.py
      2 import math
      3 import blue
      4 import carbonui.const as uiconst
      5 import carbonui.fontconst
      6 import eve.client.script.ui.login.charSelection.characterSelectionColors as csColors
      7 import eve.client.script.ui.login.charSelection.characterSelectionUtils as csUtil
      8 import evetypes
      9 import inventorycommon.typeHelpers
     10 import localization
     11 import log
     12 import trinity
     13 import uthread
     14 from achievement_system.client.ui.chip.achievement_info import AchievementInfoChips
     15 from caching.memoize import Memoize
     16 from carbon.client.script.environment.AudioUtil import PlaySound
     17 from carbon.common.script.util import timerstuff
     18 from carbon.common.script.util.format import IntToRoman
     19 from carbonui.primitives.container import Container
     20 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     21 from carbonui.primitives.fill import Fill
     22 from carbonui.primitives.frame import Frame
     23 from carbonui.primitives.line import Line
     24 from carbonui.primitives.sprite import Sprite
     25 from carbonui.primitives.transform import Transform
     26 from carbonui.uicore import uicore
     27 from carbonui.util.color import Color
     28 from eve.client.script.ui.control import eveIcon, eveLabel
     29 from eve.client.script.ui.control.eveIcon import CorpIcon
     30 from eve.client.script.ui.login.charSelection.characterSelectionUtils import SetColor, MakeTransparent, SetEffectOpacity, SetSaturation
     31 from eve.client.script.ui.shared.neocom.corporation.war.atWarTooltip import LoadAtWarTooltipPanel
     32 from eve.client.script.ui.shared.radialMenu.radialMenu import ThreePartContainer
     33 from eve.common.script.sys.idCheckers import IsAbyssalSpaceSystem, IsHiddenSpaceSystem, IsVoidSpaceSystem
     34 from eve.common.script.util import eveFormat
     35 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     36 from security.client.fonticons import get_font_icon_text
     37 SHIP_BOUNDING_BOXES = {}
     38 
     39 class SmallSlot(Container):
     40     __notifyevents__ = ['OnExternalDragInitiated', 'OnExternalDragEnded', 'OnTokensRedeemed']
     41     default_align = uiconst.TOLEFT
     42     default_width = 200
     43     default_state = uiconst.UI_NORMAL
     44     maxImageSize = 256
     45     paddingName = 20
     46     outerFrameWidth = 2
     47     innerFrameWidth = 1
     48     distanceFromOuterToInnerFrame_side = 4
     49     distanceFromOuterToInnerFrame_bottom = 4
     50     distanceFromInnerFrameToContent_sides = 6
     51     distanceFromInnerFrameToContent_bottom = 6
     52     isEmptySlot = False
     53 
     54     def ApplyAttributes(self, attributes):
     55         Container.ApplyAttributes(self, attributes)
     56         self.callback = attributes.get('callback', None)
     57         self.doubleClickCallback = attributes.get('doubleClickCallback', None)
     58         self.slotIdx = attributes.get('slotIdx')
     59         self.charID = None
     60         self.mouseOverState = False
     61         self.enteringGameWithSlot = False
     62         innerslotPadding = self.outerFrameWidth + self.distanceFromOuterToInnerFrame_side
     63         self.innerSlotCont = Container(parent=self, name='innerSlotCont', padding=innerslotPadding)
     64         self.slotBackground = Fill(bgParent=self.innerSlotCont, color=csColors.SLOT_BACKGROUND, padding=0)
     65         frameCornerSize = 2 + self.innerFrameWidth
     66         glowFrameTexturePath = 'res:/UI/Texture/classes/CharacterSelection/glowDotFrame.png'
     67         self.normalGlowFrame = Frame(parent=self.innerSlotCont, name='glowFrame', color=csColors.FRAME_GLOW_ACTIVE, frameConst=(glowFrameTexturePath,
     68          5,
     69          -2,
     70          0), padding=0)
     71         self.normalFrame = Frame(parent=self.innerSlotCont, name='normalFrame', padding=0, color=csColors.INNER_FRAME_INACTIVE, frameConst=('ui_1_16_161',
     72          frameCornerSize,
     73          -2,
     74          0))
     75         self.drawLineLeft = ThreePartContainer(parent=self.innerSlotCont, name='endDots', align=uiconst.TOLEFT_NOPUSH, state=uiconst.UI_DISABLED, pos=(0, 0, 2, 0), idx=0, leftTexturePath='res:/UI/Texture/classes/CharacterSelection/topDot.png', rightTexturePath='res:/UI/Texture/classes/CharacterSelection/bottomDots.png', sideSize=20, color=csColors.FRAME_GLOW_ACTIVE, orientation='vertical')
     76         self.drawLineLeft.opacity = 0
     77         self.drawLineRight = ThreePartContainer(parent=self.innerSlotCont, name='endDots', align=uiconst.TORIGHT_NOPUSH, state=uiconst.UI_DISABLED, pos=(0, 0, 2, 0), idx=0, leftTexturePath='res:/UI/Texture/classes/CharacterSelection/topDot.png', rightTexturePath='res:/UI/Texture/classes/CharacterSelection/bottomDots.png', sideSize=20, color=csColors.FRAME_GLOW_ACTIVE, orientation='vertical')
     78         self.drawLineRight.opacity = 0
     79         offSetBottom = self.outerFrameWidth + self.distanceFromOuterToInnerFrame_bottom
     80         texturePath = 'res:/UI/Texture/classes/CharacterSelection/selectFrame.png'
     81         self.selectionFrameGlow = Frame(parent=self.innerSlotCont, name='selectionFrame', color=csColors.FRAME_GLOW_ACTIVE, frameConst=(texturePath,
     82          22,
     83          0,
     84          0), padding=(-innerslotPadding,
     85          -innerslotPadding,
     86          -innerslotPadding,
     87          -offSetBottom))
     88         self.selectionFrameGlow.opacity = 0
     89         frameCornerSize = 2 + self.outerFrameWidth
     90         self.selectionFrame = Frame(parent=self.innerSlotCont, name='selectionFrame', color=csColors.OUTER_FRAME, frameConst=('ui_1_16_161',
     91          frameCornerSize,
     92          -2,
     93          0), padding=(-innerslotPadding,
     94          -innerslotPadding,
     95          -innerslotPadding,
     96          -offSetBottom))
     97         self.selectionFrame.opacity = 0
     98         infoContPadding = self.distanceFromInnerFrameToContent_sides + self.innerFrameWidth
     99         self.infoCont = ContainerAutoSize(parent=self.innerSlotCont, name='infoCont', padding=infoContPadding, align=uiconst.TOTOP, alignMode=uiconst.TOTOP)
    100         self.nameCont = Container(parent=self, name='nameCont', align=uiconst.TOTOP, height=28, padLeft=0, padRight=0, idx=0)
    101         inactivePadding = (innerslotPadding,
    102          0,
    103          innerslotPadding,
    104          4)
    105         self.nameSelectionFillActive = Fill(bgParent=self.nameCont, padding=(0, 0, 0, 4), color=csColors.NAME_CONT_FILL_ACTIVE)
    106         self.nameSelectionFillInactive = Fill(bgParent=self.nameCont, padding=inactivePadding, color=csColors.NAME_CONT_FILL_INACTIVE)
    107         self.nameSelectionFillRedeemMode = Fill(bgParent=self.nameCont, padding=inactivePadding, color=csColors.NAME_CONT_FILL_ACTIVE)
    108         self.innerNameCont = Container(parent=self.nameCont, padRight=innerslotPadding, clipChildren=True)
    109         self.characterNameLabel = eveLabel.EveLabelLargeBold(parent=self.innerNameCont, name='characterNameLabel', align=uiconst.CENTERLEFT, text='', padLeft=8 + innerslotPadding, top=-2)
    110         self.characterNameLabel.letterspace = 1
    111         self.characterNameLabel.SetTextColor(csColors.NAME_LABEL_ACTIVE)
    112         extraPadding = self.GetExtraWidth()
    113         self.portraitCont = Container(parent=self.infoCont, name='portraitCont', align=uiconst.TOTOP, height=self.width - extraPadding, clipChildren=True)
    114         self.portraitInnerCont = Container(parent=self.portraitCont, name='portraitInnerCont', align=uiconst.TOALL, pos=(0, 0, 0, 0), clipChildren=True, state=uiconst.UI_PICKCHILDREN)
    115         chip_container = Container(name='chip_container', parent=self.portraitInnerCont, align=uiconst.TOTOP_NOPUSH, height=AchievementInfoChips.default_height, padding=(4, 4, 0, 0))
    116         self.titleAndAchievementChips = AchievementInfoChips(parent=chip_container, name='titleAndAchievementChips', align=uiconst.TOLEFT, character_id=self.charID, display_score=False)
    117         self.portraitSprite = Sprite(parent=self.portraitInnerCont, name='portraitSprite', align=uiconst.TOALL, texturePath='res:/UI/Texture/classes/CharacterSelection/silhuette.png', pos=(0, 0, 0, 0), state=uiconst.UI_PICKCHILDREN, color=(0.5, 0.5, 0.5, 1.0), saturation=csColors.PORTRAIT_INACTIVE_SATURATION, spriteEffect=trinity.TR2_SFX_SOFTLIGHT)
    118         self.portraitGrid = Sprite(parent=self.portraitInnerCont, texturePath='res:/UI/Texture/classes/CharacterSelection/Grid_ships_plus2.png', align=uiconst.TOALL, pos=(0, 0, 0, 0), color=csColors.GRID_ACTIVE, state=uiconst.UI_DISABLED, tileX=True, tileY=True)
    119         offset = self.distanceFromInnerFrameToContent_bottom + self.innerFrameWidth
    120         self.shipAndLocationCont = CharacterDetailsLocation(parent=self.innerSlotCont, padding=(infoContPadding,
    121          infoContPadding,
    122          infoContPadding,
    123          offset), callback=self.OnClick, isEmptySlot=self.isEmptySlot, clipChildren=True)
    124         self.skillQueueCont = SkillQueueCont(parent=self.infoCont, padTop=self.distanceFromInnerFrameToContent_sides)
    125         self.AddCharacterDetailsLines()
    126         sm.RegisterNotify(self)
    127 
    128     def AddCharacterDetailsLines(self):
    129         self.skillContainer = CharacterDetailsLine(parent=self.infoCont, iconPath='res:/UI/Texture/classes/CharacterSelection/skills.png', text='')
    130         self.walletContainer = CharacterDetailsLine(parent=self.infoCont, iconPath='res:/UI/Texture/classes/CharacterSelection/isk.png', text='')
    131         self.mailContainer = CharacterDetailsLine(parent=self.infoCont, iconPath='res:/UI/Texture/classes/CharacterSelection/mail.png', text='', addLine=False)
    132 
    133     def SetMouseExitState(self, animate = False):
    134         if self.enteringGameWithSlot:
    135             return
    136         self.mouseOverState = False
    137         self.SetDisabled(animate=animate)
    138 
    139     def SetMouseOverState(self, animate = False):
    140         self.mouseOverState = True
    141         self.SetEnabled(animate=animate)
    142         SetColor(self.selectionFrame, csColors.OUTER_FRAME, animate=animate)
    143         SetColor(self.selectionFrameGlow, csColors.FRAME_GLOW_ACTIVE, animate=animate)
    144         SetColor(self.normalGlowFrame, csColors.FRAME_GLOW_ACTIVE, animate=animate)
    145         SetColor(self.normalFrame, csColors.INNER_FRAME_ACTIVE, animate=animate)
    146 
    147     def SetEnabled(self, redeemMode = False, animate = False):
    148         if redeemMode:
    149             MakeTransparent(self.nameSelectionFillActive, animate=animate)
    150             SetColor(self.nameSelectionFillRedeemMode, csColors.NAME_CONT_FILL_ACTIVE, animate=animate)
    151         else:
    152             SetColor(self.nameSelectionFillActive, csColors.NAME_CONT_FILL_ACTIVE, animate=animate)
    153             MakeTransparent(self.nameSelectionFillRedeemMode, animate=animate)
    154         MakeTransparent(self.nameSelectionFillInactive, animate=animate)
    155         self.shipAndLocationCont.SetSelected(animate=animate)
    156         self.SetInfoLineActiveState(isActive=True, animate=animate)
    157         self.shipAndLocationCont.SetActiveState(isActive=True, animate=animate)
    158         if not csUtil.IsMonochromeStyleEnabled():
    159             SetColor(self.portraitSprite, (1, 1, 1, 1), animate=animate)
    160             SetEffectOpacity(self.portraitSprite, newOpacity=0, animate=animate)
    161             SetSaturation(self.portraitSprite, newSaturation=1.0, animate=animate)
    162         self.skillQueueCont.SetSelected(animate=animate)
    163 
    164     def SetDisabled(self, animate = False):
    165         SetColor(self.normalFrame, csColors.INNER_FRAME_INACTIVE, animate=animate)
    166         SetColor(self.normalGlowFrame, csColors.FRAME_GLOW_INACTIVE, animate=animate)
    167         MakeTransparent(self.selectionFrame, animate=animate)
    168         MakeTransparent(self.selectionFrameGlow, animate=animate)
    169         MakeTransparent(self.nameSelectionFillActive, animate=animate)
    170         MakeTransparent(self.nameSelectionFillRedeemMode, animate=animate)
    171         SetColor(self.nameSelectionFillInactive, csColors.NAME_CONT_FILL_INACTIVE, animate=animate)
    172         self.shipAndLocationCont.SetDeselected(animate=animate)
    173         self.SetInfoLineActiveState(isActive=False, animate=animate)
    174         self.shipAndLocationCont.SetActiveState(isActive=False, animate=animate)
    175         SetColor(self.portraitSprite, csColors.PORTRAIT_INACTIVE, animate=animate)
    176         SetEffectOpacity(self.portraitSprite, newOpacity=csColors.PORTRAIT_INACTIVE_EFFECT_OPACITY, animate=animate)
    177         SetSaturation(self.portraitSprite, newSaturation=csColors.PORTRAIT_INACTIVE_SATURATION, animate=animate)
    178         self.skillQueueCont.SetDeselected(animate=animate)
    179 
    180     def SetInfoLineActiveState(self, isActive = True, animate = False):
    181         for eachCont in (self.skillContainer, self.walletContainer, self.mailContainer):
    182             eachCont.SetActiveState(isActive=isActive, animate=animate)
    183 
    184     def GetShipAndLocationContHeight(self):
    185         return self.shipAndLocationCont.GetHeight()
    186 
    187     def SetShipContHeight(self, height):
    188         self.shipAndLocationCont.SetShipContHeight(height)
    189 
    190     def OnClick(self, *_):
    191         if self.callback:
    192             self.callback(self)
    193 
    194     def OnDblClick(self, *_):
    195         if self.doubleClickCallback:
    196             self.doubleClickCallback(self)
    197 
    198     @classmethod
    199     def GetExtraWidth(cls):
    200         outerFrameToInnerFrame = cls.outerFrameWidth + cls.distanceFromOuterToInnerFrame_side
    201         innerFrameToConent = cls.innerFrameWidth + cls.distanceFromInnerFrameToContent_sides
    202         totalPadding = outerFrameToInnerFrame + innerFrameToConent
    203         return 2 * totalPadding
    204 
    205     def GetSlotHeight(self, shipVisible = True):
    206         w, infoContHeight = self.infoCont.GetAbsoluteSize()
    207         shipContHeight = self.shipAndLocationCont.GetHeight(shipVisible=shipVisible)
    208         nameContHeight = self.nameCont.height
    209         innerContPadding = self.innerSlotCont.padTop + self.innerSlotCont.padBottom
    210         infoContPadding = self.infoCont.padTop + self.infoCont.padBottom
    211         shipContPadding = self.shipAndLocationCont.padBottom
    212         totalPadding = innerContPadding + infoContPadding + shipContPadding
    213         contentHeight = infoContHeight + shipContHeight + nameContHeight + totalPadding
    214         return contentHeight
    215 
    216     def ExpandSlot(self, animate = True):
    217         if animate:
    218             uicore.animations.MorphScalar(self, 'opacity', startVal=self.opacity, endVal=1.0, duration=csUtil.COLLAPSE_TIME)
    219         else:
    220             self.opacity = 1.0
    221         self.shipAndLocationCont.ExpandShipSection(animate=animate)
    222 
    223     def SetActiveInRedeeemMode(self):
    224         pass
    225 
    226     def CollapseSlot(self, animate = True):
    227         self.shipAndLocationCont.CollapseShipSection(animate=animate)
    228 
    229     def OnIconMouseEnter(self, icon, buttonIconOnMouseEnter):
    230         preparingForDelete = self.characterDetails and bool(self.characterDetails.GetDeletePrepareTime())
    231         if not preparingForDelete:
    232             self.SetMouseOverState(animate=False)
    233         buttonIconOnMouseEnter()
    234 
    235     def OnExternalDragInitiated(self, dragSource, dragData):
    236         self.SetActiveInRedeeemMode()
    237 
    238     def OnExternalDragEnded(self, *args):
    239         if uicore.uilib.mouseOver == self or uicore.uilib.mouseOver.IsUnder(self):
    240             self.SetMouseOverState(animate=True)
    241         else:
    242             self.SetMouseExitState(animate=True)
    243 
    244     def OnTokensRedeemed(self, charID, stationID, tokensRedeemed, numItemsCreated):
    245         if charID != self.charID:
    246             return
    247         uicore.animations.BlinkOut(self, startVal=1.0, endVal=0.5, duration=0.3, loops=1, curveType=uiconst.ANIM_BOUNCE)
    248 
    249     def AnimateSlotIn(self, animationOffset = 0.0, soundFunction = None, charContHeight = 100):
    250         self.enteringGameWithSlot = False
    251         minBlinkValue = 0.2
    252         blinkDuration = 0.1
    253         lineAnimationOffset = animationOffset
    254         lineAnimationDuration = 0.4
    255         lineFadeOutOffset = lineAnimationOffset + lineAnimationDuration
    256         lineFadeOutDuration = 0.2
    257         uicore.animations.MorphScalar(self.drawLineLeft, 'padTop', startVal=(charContHeight - 30) / 2.0, endVal=0.0, duration=lineAnimationDuration, timeOffset=lineAnimationOffset)
    258         uicore.animations.MorphScalar(self.drawLineLeft, 'padBottom', startVal=(charContHeight - 30) / 2.0, endVal=0.0, duration=lineAnimationDuration, timeOffset=lineAnimationOffset)
    259         uicore.animations.MorphScalar(self.drawLineLeft, 'opacity', startVal=0.8, endVal=0, duration=lineFadeOutDuration, timeOffset=lineFadeOutOffset)
    260         uicore.animations.MorphScalar(self.drawLineRight, 'padTop', startVal=(charContHeight - 30) / 2.0, endVal=0.0, duration=lineAnimationDuration, timeOffset=lineAnimationOffset)
    261         uicore.animations.MorphScalar(self.drawLineRight, 'padBottom', startVal=(charContHeight - 30) / 2.0, endVal=0.0, duration=lineAnimationDuration, timeOffset=lineAnimationOffset)
    262         uicore.animations.MorphScalar(self.drawLineRight, 'opacity', startVal=0.8, endVal=0, duration=lineFadeOutDuration, timeOffset=lineFadeOutOffset)
    263         normalFrameFadeOffset = lineFadeOutDuration + lineFadeOutOffset - 0.2
    264         normalFrameFadeDuration = 0.4
    265         uthread.new(soundFunction, event='character_selection_animobject', sleepTime=normalFrameFadeOffset)
    266         uicore.animations.MorphScalar(self.normalFrame, 'opacity', startVal=0, endVal=csColors.INNER_FRAME_INACTIVE[3], duration=normalFrameFadeDuration, timeOffset=normalFrameFadeOffset)
    267         nameContDuration = 0.2
    268         uicore.animations.MorphScalar(self.nameCont, 'opacity', startVal=0.0, endVal=1.0, duration=nameContDuration, timeOffset=normalFrameFadeOffset)
    269         uicore.animations.BlinkIn(self.nameSelectionFillActive, startVal=0.0, endVal=1.0, duration=blinkDuration, loops=2, curveType=uiconst.ANIM_BOUNCE, callback=None, sleep=False, timeOffset=normalFrameFadeOffset)
    270         portraitOffset = normalFrameFadeOffset + normalFrameFadeDuration - 0.2
    271         portraitDuration = 0.2
    272         uicore.animations.MorphScalar(self.portraitInnerCont, 'padTop', startVal=self.portraitCont.height / 2.0, endVal=0, duration=portraitDuration, timeOffset=portraitOffset)
    273         uicore.animations.MorphScalar(self.portraitInnerCont, 'padBottom', startVal=self.portraitCont.height / 2.0, endVal=0, duration=portraitDuration, timeOffset=portraitOffset)
    274         uicore.animations.BlinkIn(self.portraitInnerCont, startVal=1.0, endVal=minBlinkValue, duration=blinkDuration, curveType=uiconst.ANIM_BOUNCE, timeOffset=portraitOffset + portraitDuration)
    275         uicore.animations.SpColorMorphTo(self.slotBackground, startColor=(0, 0, 0, 0), endColor=csColors.SLOT_BACKGROUND, duration=1.0, timeOffset=portraitOffset)
    276         skillQueueOffset = portraitOffset + portraitDuration
    277         skillQueueDuration = 0.1
    278         uicore.animations.MorphScalar(self.skillQueueCont, 'opacity', startVal=0.0, endVal=1.0, duration=skillQueueDuration, timeOffset=skillQueueOffset)
    279         uthread.new(soundFunction, event='character_selection_animobject', sleepTime=skillQueueOffset)
    280         contOffset = skillQueueOffset + skillQueueDuration
    281         contDuration = 0.03
    282         for contIdx, eachCont in enumerate([self.skillContainer, self.walletContainer, self.mailContainer]):
    283             contOffset += contIdx * contDuration
    284             uicore.animations.BlinkIn(eachCont.icon, startVal=csColors.LINES_ICON_INACTIVE[3], endVal=minBlinkValue, duration=blinkDuration, loops=2, curveType=uiconst.ANIM_BOUNCE, timeOffset=contOffset)
    285             uicore.animations.BlinkIn(eachCont.textLabel, startVal=1.0, endVal=minBlinkValue, duration=blinkDuration, loops=2, curveType=uiconst.ANIM_BOUNCE, timeOffset=contOffset)
    286             uicore.animations.MorphScalar(eachCont, 'opacity', startVal=0.0, endVal=1.0, duration=contDuration, loops=2, timeOffset=contOffset)
    287             bigTextLabel = getattr(eachCont, 'bigTextLabel', None)
    288             if bigTextLabel:
    289                 uicore.animations.BlinkIn(bigTextLabel, startVal=1.0, endVal=minBlinkValue, duration=blinkDuration, loops=2, curveType=uiconst.ANIM_BOUNCE, timeOffset=contOffset)
    290 
    291         shipLocationOffset = contOffset + contDuration
    292         shipLocationBlinkOffset = shipLocationOffset + 0.05
    293         shipLocationDuration = 0.2
    294         uicore.animations.MorphScalar(self.shipAndLocationCont, 'opacity', startVal=0.0, endVal=1.0, duration=shipLocationDuration, loops=1, timeOffset=shipLocationBlinkOffset)
    295         uicore.animations.BlinkIn(self.shipAndLocationCont.locationCont, startVal=1.0, endVal=minBlinkValue, duration=blinkDuration, loops=2, curveType=uiconst.ANIM_BOUNCE, timeOffset=shipLocationBlinkOffset)
    296         uicore.animations.BlinkIn(self.shipAndLocationCont.shipParentCont, startVal=1.0, endVal=minBlinkValue, duration=blinkDuration, loops=2, curveType=uiconst.ANIM_BOUNCE, timeOffset=shipLocationOffset)
    297 
    298     def AnimateSlotOut(self, animationOffset = 0.0, soundFunction = None, charContHeight = 100):
    299         minBlinkValue = 0.2
    300         blinkDuration = 0.1
    301         uthread.new(soundFunction, event='character_selection_animobject', sleepTime=animationOffset)
    302         shipLocationOffset = animationOffset
    303         shipLocationBlinkOffset = shipLocationOffset + 0.05
    304         shipLocationDuration = 0.2
    305         uicore.animations.MorphScalar(self.shipAndLocationCont, 'opacity', startVal=1.0, endVal=0.0, duration=shipLocationDuration, loops=1, timeOffset=shipLocationBlinkOffset)
    306         uicore.animations.BlinkOut(self.shipAndLocationCont.locationCont, startVal=1.0, endVal=minBlinkValue, duration=blinkDuration, loops=2, curveType=uiconst.ANIM_BOUNCE, timeOffset=shipLocationBlinkOffset)
    307         uicore.animations.BlinkOut(self.shipAndLocationCont.shipParentCont, startVal=1.0, endVal=minBlinkValue, duration=blinkDuration, loops=2, curveType=uiconst.ANIM_BOUNCE, timeOffset=shipLocationOffset)
    308         contOffset = shipLocationOffset + shipLocationDuration
    309         contDuration = 0.03
    310         for contIdx, eachCont in enumerate([self.mailContainer, self.walletContainer, self.skillContainer]):
    311             contOffset += contIdx * contDuration
    312             uicore.animations.BlinkOut(eachCont.icon, startVal=eachCont.icon.opacity, endVal=minBlinkValue, duration=blinkDuration, loops=2, curveType=uiconst.ANIM_BOUNCE, timeOffset=contOffset)
    313             uicore.animations.BlinkOut(eachCont.textLabel, startVal=eachCont.icon.opacity, endVal=minBlinkValue, duration=blinkDuration, loops=2, curveType=uiconst.ANIM_BOUNCE, timeOffset=contOffset)
    314             uicore.animations.MorphScalar(eachCont, 'opacity', startVal=1.0, endVal=0.0, duration=contDuration, loops=2, timeOffset=contOffset)
    315             bigTextLabel = getattr(eachCont, 'bigTextLabel', None)
    316             if bigTextLabel:
    317                 uicore.animations.BlinkOut(bigTextLabel, startVal=1.0, endVal=minBlinkValue, duration=blinkDuration, loops=2, curveType=uiconst.ANIM_BOUNCE, timeOffset=contOffset)
    318 
    319         skillQueueOffset = contOffset + contDuration
    320         skillQueueDuration = 0.1
    321         uicore.animations.MorphScalar(self.skillQueueCont, 'opacity', startVal=1.0, endVal=0.0, duration=skillQueueDuration, timeOffset=skillQueueOffset)
    322         uthread.new(soundFunction, event='character_selection_animobject', sleepTime=skillQueueOffset)
    323         portraitOffset = skillQueueOffset + skillQueueDuration
    324         portraitDuration = 0.2
    325         uicore.animations.MorphScalar(self.portraitInnerCont, 'padTop', startVal=0, endVal=self.portraitCont.height / 2.0, duration=portraitDuration, timeOffset=portraitOffset)
    326         uicore.animations.MorphScalar(self.portraitInnerCont, 'padBottom', startVal=0, endVal=self.portraitCont.height / 2.0, duration=portraitDuration, timeOffset=portraitOffset)
    327         uicore.animations.BlinkOut(self.portraitInnerCont, startVal=1.0, endVal=minBlinkValue, duration=blinkDuration, curveType=uiconst.ANIM_BOUNCE, timeOffset=portraitOffset + portraitDuration)
    328         uicore.animations.SpColorMorphTo(self.slotBackground, startColor=csColors.SLOT_BACKGROUND, endColor=(0, 0, 0, 0), duration=0.5, timeOffset=portraitOffset)
    329         normalFrameFadeOffset = portraitOffset + portraitDuration
    330         normalFrameFadeDuration = 0.4
    331         uicore.animations.MorphScalar(self.normalFrame, 'opacity', startVal=csColors.INNER_FRAME_INACTIVE[3], endVal=0, duration=normalFrameFadeDuration, timeOffset=normalFrameFadeOffset)
    332         nameContDuration = 0.2
    333         uicore.animations.MorphScalar(self.nameCont, 'opacity', startVal=1.0, endVal=0.0, duration=nameContDuration, timeOffset=normalFrameFadeOffset)
    334         uicore.animations.BlinkOut(self.nameSelectionFillActive, startVal=0.0, endVal=1.0, duration=blinkDuration, loops=2, curveType=uiconst.ANIM_BOUNCE, callback=None, sleep=False, timeOffset=normalFrameFadeOffset)
    335         lineAnimationOffset = normalFrameFadeOffset + nameContDuration
    336         lineAnimationDuration = 0.4
    337         lineFadeOutOffset = lineAnimationOffset + lineAnimationDuration
    338         lineFadeOutDuration = 0.2
    339         uicore.animations.MorphScalar(self.drawLineLeft, 'padTop', startVal=0, endVal=(charContHeight - 30) / 2.0, duration=lineAnimationDuration, timeOffset=lineAnimationOffset)
    340         uicore.animations.MorphScalar(self.drawLineLeft, 'padBottom', startVal=0, endVal=(charContHeight - 30) / 2.0, duration=lineAnimationDuration, timeOffset=lineAnimationOffset)
    341         uicore.animations.MorphScalar(self.drawLineLeft, 'opacity', startVal=0.8, endVal=0.0, duration=lineFadeOutDuration, timeOffset=lineFadeOutOffset)
    342         uicore.animations.MorphScalar(self.drawLineRight, 'padTop', startVal=0, endVal=(charContHeight - 30) / 2.0, duration=lineAnimationDuration, timeOffset=lineAnimationOffset)
    343         uicore.animations.MorphScalar(self.drawLineRight, 'padBottom', startVal=0, endVal=(charContHeight - 30) / 2.0, duration=lineAnimationDuration, timeOffset=lineAnimationOffset)
    344         uicore.animations.MorphScalar(self.drawLineRight, 'opacity', startVal=0.8, endVal=0, duration=lineFadeOutDuration, timeOffset=lineFadeOutOffset, curveType=uiconst.ANIM_BOUNCE)
    345 
    346     def PlaySelectedAnimation(self):
    347         self.enteringGameWithSlot = True
    348         uicore.animations.BlinkIn(self.selectionFrame, startVal=csColors.OUTER_FRAME[3], endVal=0.0, duration=0.1, loops=2, curveType=uiconst.ANIM_BOUNCE, timeOffset=0.2)
    349         uicore.animations.BlinkIn(self.nameSelectionFillActive, startVal=csColors.NAME_CONT_FILL_ACTIVE[3], endVal=0.0, duration=0.1, loops=2, curveType=uiconst.ANIM_BOUNCE, timeOffset=0.2)
    350         uicore.animations.BlinkIn(self.shipAndLocationCont.locationBg, startVal=csColors.LOCATION_FILL_ACTIVE[3], endVal=0.0, duration=0.1, loops=2, curveType=uiconst.ANIM_BOUNCE, timeOffset=0.2)
    351         uicore.animations.BlinkIn(self.skillQueueCont.fill, startVal=csColors.SKILLQUEUE_FILL_ACTIVE[3], endVal=0.0, duration=0.1, loops=2, curveType=uiconst.ANIM_BOUNCE, timeOffset=0.2)
    352         sm.GetService('audio').SendUIEvent('character_select_character')
    353 
    354 
    355 class SmallCharacterSlot(SmallSlot):
    356     default_name = 'smallCharacterSlot'
    357     __notifyevents__ = ['OnExternalDragInitiated', 'OnExternalDragEnded', 'OnTokensRedeemed']
    358 
    359     def ApplyAttributes(self, attributes):
    360         SmallSlot.ApplyAttributes(self, attributes)
    361         self.slotLoaded = False
    362         self.characterDetails = None
    363         self.deleteCallback = attributes.get('deleteCallback', None)
    364         self.undoDeleteCallback = attributes.get('undoDeleteCallback', None)
    365         self.terminateCallback = attributes.get('terminateCallback', None)
    366         self.corpCont = Container(parent=self.portraitInnerCont, name='corpLabel', align=uiconst.BOTTOMLEFT, pos=(0, 0, 48, 48), idx=0)
    367         self.allianceLogo = Sprite(parent=self.portraitInnerCont, name='allianceLogo', align=uiconst.BOTTOMRIGHT, state=uiconst.UI_NORMAL, pos=(0, 0, 48, 48), idx=0, spriteEffect=trinity.TR2_SFX_SOFTLIGHT)
    368         self.allianceLogo.OnClick = self.OnClick
    369         atWarLeft = self.corpCont.left + self.corpCont.width
    370         atWarTop = self.corpCont.top + self.corpCont.height - 20
    371         self.atWarSprite = Sprite(parent=self.portraitInnerCont, name='characterIsAtWar', align=uiconst.BOTTOMLEFT, state=uiconst.UI_NORMAL, texturePath='res:/UI/Texture/classes/war/atWar_24.png', pos=(atWarLeft,
    372          atWarTop,
    373          20,
    374          20), spriteEffect=trinity.TR2_SFX_SOFTLIGHT, idx=0)
    375         self.atWarSprite.SetRGBA(1.0, 0.0, 0.0, 1.0)
    376         self.deleteCont = ContainerAutoSize(parent=self.nameCont, name='deleteCont', align=uiconst.TORIGHT, alignMode=uiconst.TORIGHT, pos=(12, -2, 32, 16), state=uiconst.UI_PICKCHILDREN, idx=0)
    377         self.deleteCont.display = False
    378         self.deleteButton1 = DeleteButton(parent=self.deleteCont, name='deleteButton', texturePath='res:/UI/Texture/Icons/Plus_Small.png', state=uiconst.UI_NORMAL, color=(1.0, 0.0, 0.0, 1.0), callback=self.DeleteButton1Clicked, hint=localization.GetByLabel('UI/CharacterSelection/CompleteTermination'), rotation=math.pi / 4.0, onMouseEnterCallback=self.OnMouseEnter, onMouseExitCallback=self.OnMouseExit)
    379         iconOnMouseEnter = self.deleteButton1.OnMouseEnter
    380         self.deleteButton1.OnMouseEnter = (self.OnIconMouseEnter, self.deleteButton1, iconOnMouseEnter)
    381         self.deleteButton2 = DeleteButton(parent=self.deleteCont, name='cancelDeteleButton', texturePath='res:/UI/Texture/Icons/Plus_Small.png', state=uiconst.UI_NORMAL, callback=self.DeleteButton2Clicked, color=(1.0, 1.0, 1.0, 1.0), hint=localization.GetByLabel('UI/CharacterSelection/RemoveFromBiomass'))
    382         iconOnMouseEnter = self.deleteButton2.OnMouseEnter
    383         self.deleteButton2.OnMouseEnter = (self.OnIconMouseEnter, self.deleteButton2, iconOnMouseEnter)
    384         self.timeCont = Container(parent=self.deleteCont, name='timeCont', align=uiconst.TORIGHT, width=20)
    385         self.timeLabel = eveLabel.EveLabelLargeBold(parent=self.timeCont, name='textLabel', align=uiconst.CENTERLEFT, text='00:00:00', state=uiconst.UI_DISABLED)
    386         self.timeCont.width = self.timeLabel.textwidth + 6
    387         sm.RegisterNotify(self)
    388 
    389     def LoadSlot(self, charID, characterDetails):
    390         self.charID = charID
    391         self.characterDetails = characterDetails
    392         sm.GetService('photo').GetPortrait(charID, 512, self.portraitSprite)
    393         self.portraitGrid.display = False
    394         self.characterNameLabel.text = cfg.eveowners.Get(charID).name
    395         corpID, allianceID = characterDetails.GetCorporationInfo()
    396         self.corpCont.Flush()
    397         self.corpLogo = eveIcon.GetLogoIcon(itemID=corpID, parent=self.corpCont, align=uiconst.TOPLEFT, name='corpLogo', state=uiconst.UI_NORMAL, size=48, ignoreSize=True, dontUseThread=True)
    398         self.corpLogo.OnClick = self.OnClick
    399         self.corpLogo.OnMouseEnter = lambda *args: PlaySound(uiconst.SOUND_BUTTON_HOVER)
    400         if isinstance(self.corpLogo, CorpIcon):
    401             for eachLogo in self.corpLogo.children:
    402                 eachLogo.originalColor = eachLogo.GetRGBA()
    403                 if eachLogo.spriteEffect == trinity.TR2_SFX_MASK:
    404                     newColor = self.FindPlayerCorpLogoColor(eachLogo)
    405                     SetColor(eachLogo, newColor, animate=False)
    406                 else:
    407                     eachLogo.spriteEffect = trinity.TR2_SFX_SOFTLIGHT
    408                     SetColor(eachLogo, csColors.PORTRAIT_INACTIVE, animate=False)
    409                     SetEffectOpacity(eachLogo, csColors.PORTRAIT_INACTIVE_EFFECT_OPACITY, animate=False)
    410                     SetSaturation(eachLogo, 0.0, animate=False)
    411 
    412         else:
    413             self.corpLogo.spriteEffect = trinity.TR2_SFX_SOFTLIGHT
    414             SetColor(self.corpLogo, csColors.PORTRAIT_INACTIVE, animate=False)
    415             SetEffectOpacity(self.corpLogo, csColors.PORTRAIT_INACTIVE_EFFECT_OPACITY, animate=False)
    416             SetSaturation(self.corpLogo, 0.0, animate=False)
    417         self.corpLogo.hint = cfg.eveowners.Get(corpID).name
    418         if csUtil.IsMonochromeStyleEnabled():
    419             if isinstance(self.corpLogo, CorpIcon):
    420                 for eachLogo in self.corpLogo.children:
    421                     csUtil.SetMonochromeStyle(eachLogo, True)
    422 
    423             else:
    424                 csUtil.SetMonochromeStyle(self.corpLogo, True)
    425         self.allianceLogo.SetTexturePath('')
    426         if allianceID is not None:
    427             uthread.new(self.LoadAllianceLogo, self.allianceLogo, allianceID)
    428         self.shipAndLocationCont.LoadInfo(characterDetails)
    429         newlyFinishedSkills = characterDetails.GetFinishedSkills()
    430         if newlyFinishedSkills:
    431             skillText = localization.GetByLabel('UI/CharacterSelection/NumSkillsCompleted', skillCount=newlyFinishedSkills)
    432         else:
    433             sp = characterDetails.GetSkillInfo() or 0
    434             skillText = localization.formatters.FormatNumeric(sp, useGrouping=True)
    435         self.skillContainer.SetTextAndEnableContainer(skillText)
    436         balance = characterDetails.GetWalletBalance()
    437         balance = eveFormat.FmtISK(balance, showFractionsAlways=0)
    438         walletChange = characterDetails.GetWalletChanged()
    439         if walletChange > 0:
    440             iconPath2 = 'res:/UI/Texture/classes/CharacterSelection/up.png'
    441         elif walletChange < 0:
    442             iconPath2 = 'res:/UI/Texture/classes/CharacterSelection/down.png'
    443         else:
    444             iconPath2 = None
    445         self.walletContainer.SetTextAndEnableContainer(balance)
    446         if walletChange:
    447             value = eveFormat.FmtISK(walletChange, showFractionsAlways=bool(abs(walletChange) < 1))
    448             prefix = '<color=#FFFF1919>' if walletChange < 0 else '<color=#FF19FF19>+'
    449             walletHint = '%s<br>%s%s</color>' % (localization.GetByLabel('UI/Neocom/Blink/ISKBalanceChanged'), prefix, value)
    450         else:
    451             walletHint = ''
    452         self.walletContainer.SetSecondIcon(iconPath2, walletHint)
    453         unreadMails = characterDetails.GetUnreaddMailCount()
    454         if unreadMails:
    455             unreadMailsText = localization.GetByLabel('UI/CharacterSelection/NumUnreadMails', mailCount=unreadMails)
    456         else:
    457             unreadMailsText = localization.GetByLabel('UI/CharacterSelection/NoUnreadMails')
    458         self.mailContainer.SetTextAndEnableContainer(unreadMailsText)
    459         characterIsAtWar = characterDetails.IsCharacterAtWar()
    460         self.atWarSprite.display = characterIsAtWar
    461         self.atWarSprite.LoadTooltipPanel = lambda tooltipPanel, *args: self.LoadAtWarTooltipPanel(tooltipPanel, characterDetails)
    462         trainingInfo = characterDetails.GetSkillInTrainingInfo()
    463         currentSkill = trainingInfo.get('currentSkill', None)
    464         if currentSkill is not None:
    465             level = trainingInfo.get('level', 1)
    466             romanNumber = IntToRoman(min(5, int(level)))
    467             startTime = trainingInfo.get('trainingStartTime')
    468             finishTime = trainingInfo.get('trainingEndTime')
    469             now = blue.os.GetWallclockTime()
    470             timeLeft = max(0, finishTime - now)
    471             fromSP = trainingInfo.get('fromSP')
    472             finishSP = trainingInfo.get('finishSP')
    473             trainedSP = trainingInfo.get('trainedSP')
    474             currentTimeProgress = min(1.0, float(now - startTime) / (finishTime - startTime))
    475             currentTrained = currentTimeProgress * (finishSP - fromSP) + (trainedSP - fromSP)
    476             progress = currentTrained / finishSP
    477             progress = min([progress, 1.0])
    478             progress = max([progress, 0.0])
    479             skillText = localization.GetByLabel('UI/CharacterSelection/SkillAndLevel', skill=currentSkill, levelInRoman=romanNumber)
    480             timeText = localization.formatters.FormatTimeIntervalShortWritten(long(timeLeft), showFrom='day', showTo='minute')
    481             queueEndTime = trainingInfo.get('queueEndTime', 0)
    482             if queueEndTime != finishTime:
    483                 queueTimeLeft = max(0, queueEndTime - now)
    484                 queueTimeText = localization.formatters.FormatTimeIntervalShortWritten(long(queueTimeLeft), showFrom='day', showTo='minute')
    485                 timeText = '%s +' % timeText
    486                 hint = '%s<br>%s' % (localization.GetByLabel('UI/SkillQueue/TrainingQueue'), queueTimeText)
    487             else:
    488                 hint = ''
    489             self.skillQueueCont.SetProgress(progress=progress)
    490             self.skillQueueCont.SetText(skillText, timeText, hint)
    491         self.skillQueueCont.SetSkillQueueActivityState(bool(currentSkill))
    492         self.SetDeleteUI(animate=False)
    493         self.titleAndAchievementChips.character_id = charID
    494         self.slotLoaded = True
    495 
    496     def CountDown_thread(self):
    497         deletePrepareTime = self.characterDetails.GetDeletePrepareTime()
    498         if deletePrepareTime is None:
    499             self.countDownThread = None
    500             self.deleteButton1.display = False
    501             return
    502         now = blue.os.GetWallclockTime()
    503         timeLeft = deletePrepareTime - now
    504         timeLeftText = localization.formatters.FormatTimeIntervalShort(long(max(0, timeLeft)), showFrom='hour', showTo='second')
    505         self.timeLabel.text = timeLeftText
    506         if timeLeft < 0:
    507             self.countDownThread = None
    508             self.deleteButton1.display = True
    509             self.deleteButton1.ExpandButton()
    510             uicore.animations.BlinkOut(self.timeLabel, startVal=1.0, endVal=0.0, duration=0.3, loops=3, curveType=uiconst.ANIM_WAVE)
    511 
    512     def LoadAllianceLogo(self, logo, allianceID):
    513         sm.GetService('photo').GetAllianceLogo(allianceID, 64, logo, orderIfMissing=True)
    514         logo.hint = cfg.eveowners.Get(allianceID).ownerName
    515         logo.OnMouseEnter = lambda *args: PlaySound(uiconst.SOUND_BUTTON_HOVER)
    516 
    517     def SetMouseExitState(self, animate = False):
    518         if self.enteringGameWithSlot or not self.slotLoaded:
    519             return
    520         preparingForDelete = self.characterDetails and bool(self.characterDetails.GetDeletePrepareTime())
    521         if not preparingForDelete:
    522             self.deleteCont.display = False
    523         SmallSlot.SetMouseExitState(self, animate=animate)
    524         self.SetIconsColorInactive(animate=animate)
    525         self.AdjustNameLabel()
    526 
    527     def SetMouseOverState(self, animate = False):
    528         if not self.slotLoaded:
    529             return
    530         SmallSlot.SetMouseOverState(self, animate=animate)
    531         if not csUtil.IsMonochromeStyleEnabled():
    532             self.SetIconsColorActive(animate=animate)
    533         self.deleteCont.display = True
    534         self.AdjustNameLabel()
    535 
    536     def AdjustNameLabel(self):
    537         if self.characterNameLabel.textwidth > self.width - 100:
    538             slotWidth, h = self.innerNameCont.GetAbsoluteSize()
    539             fadeEnd = slotWidth - 20 - self.characterNameLabel.left
    540             self.characterNameLabel.SetRightAlphaFade(fadeEnd, maxFadeWidth=20)
    541 
    542     def SetDisabled(self, animate = False):
    543         SmallSlot.SetDisabled(self, animate)
    544         if self.characterDetails.IsPreparingForDeletion():
    545             SetColor(self.portraitSprite, csColors.BIOMASS_PORTRAIT, animate=animate)
    546             SetEffectOpacity(self.portraitSprite, newOpacity=csColors.PORTRAIT_INACTIVE_EFFECT_OPACITY, animate=animate)
    547             SetSaturation(self.portraitSprite, newSaturation=csColors.PORTRAIT_INACTIVE_SATURATION, animate=animate)
    548         self.shipAndLocationCont.SetDeselected(animate=animate)
    549 
    550     def SetIconsColorActive(self, animate = False):
    551         SetEffectOpacity(self.allianceLogo, 0, animate=animate)
    552         SetSaturation(self.allianceLogo, 1.0, animate=animate)
    553         if isinstance(self.corpLogo, CorpIcon):
    554             self.SetPlayerCorpLogoColor(self.corpLogo, isActive=True, animate=animate)
    555         else:
    556             SetEffectOpacity(self.corpLogo, 0, animate=animate)
    557         SetColor(self.atWarSprite, csColors.AT_WAR_ACTIVE, animate=animate)
    558 
    559     def SetIconsColorInactive(self, animate = False):
    560         SetEffectOpacity(self.allianceLogo, csColors.PORTRAIT_INACTIVE_EFFECT_OPACITY, animate=animate)
    561         SetSaturation(self.allianceLogo, 0.0, animate=animate)
    562         if isinstance(self.corpLogo, CorpIcon):
    563             self.SetPlayerCorpLogoColor(self.corpLogo, isActive=False, animate=animate)
    564         else:
    565             SetEffectOpacity(self.corpLogo, csColors.PORTRAIT_INACTIVE_EFFECT_OPACITY, animate=animate)
    566         SetColor(self.atWarSprite, csColors.AT_WAR_INACTIVE, animate=animate)
    567 
    568     def SetPlayerCorpLogoColor(self, logo, isActive = True, animate = False):
    569         for layerNum, eachSprite in enumerate(logo.children):
    570             if eachSprite.spriteEffect == trinity.TR2_SFX_MASK:
    571                 if isActive:
    572                     newColor = eachSprite.originalColor
    573                 else:
    574                     newColor = self.FindPlayerCorpLogoColor(eachSprite)
    575             else:
    576                 if isActive:
    577                     effectOpacity = 1.0
    578                     saturation = 1.0
    579                     newColor = eachSprite.originalColor
    580                     spriteEffect = trinity.TR2_SFX_COPY
    581                 else:
    582                     effectOpacity = csColors.PORTRAIT_INACTIVE_EFFECT_OPACITY
    583                     saturation = 0.0
    584                     newColor = csColors.PORTRAIT_INACTIVE
    585                     spriteEffect = trinity.TR2_SFX_SOFTLIGHT
    586                 SetEffectOpacity(eachSprite, effectOpacity, animate=animate)
    587                 SetSaturation(eachSprite, saturation, animate=animate)
    588                 eachSprite.spriteEffect = spriteEffect
    589             SetColor(eachSprite, newColor, animate=animate)
    590 
    591     def FindPlayerCorpLogoColor(self, sprite):
    592         currentColor = sprite.originalColor
    593         currentColor = [ min(1.0, value) for value in currentColor ]
    594         newColor = Color(*currentColor).SetSaturation(0.05).SetAlpha(0.9).GetRGBA()
    595         return newColor
    596 
    597     def OnDropData(self, dragSource, dragData):
    598         if self.characterDetails.IsPreparingForDeletion():
    599             return
    600         tokens = [ {'tokenID': eachData['item'].tokenID,
    601          'massTokenID': eachData['item'].massTokenID,
    602          'typeID': eachData['item'].typeID} for eachData in dragData ]
    603         useHomeStation = True
    604         if self.characterDetails and self.characterDetails.GetCurrentStation():
    605             useHomeStation = False
    606         if useHomeStation:
    607             message = localization.GetByLabel('UI/Redeem/ConfirmRedeemToHomeStation', charID=self.characterDetails.charID)
    608             ret = prompt_player_fsd_dialog('AskAreYouSure', {'cons': message}, uiconst.YESNO)
    609             if ret != uiconst.ID_YES:
    610                 return
    611         redeemInfo = sm.GetService('redeem').ClaimRedeemTokens(tokens, self.charID, useHomeStation=useHomeStation)
    612         if redeemInfo and redeemInfo['isk_balance'] is not None:
    613             balanceText = eveFormat.FmtISK(redeemInfo['isk_balance'], showFractionsAlways=0)
    614             self.walletContainer.SetTextAndEnableContainer(balanceText)
    615 
    616     def SetActiveInRedeeemMode(self):
    617         SmallSlot.SetActiveInRedeeemMode(self)
    618         if self.characterDetails and not self.characterDetails.IsPreparingForDeletion():
    619             self.SetEnabled(redeemMode=True)
    620         else:
    621             self.SetDisabled()
    622 
    623     def RefreshCharacterDetails(self, characterDetails):
    624         self.characterDetails = characterDetails
    625 
    626     def SetDeleteUI(self, animate = True):
    627         deletePrepareTime = self.characterDetails.GetDeletePrepareTime()
    628         if deletePrepareTime:
    629             self.SetMouseExitState()
    630             self.deleteCont.display = True
    631             self.timeCont.display = True
    632             self.deleteButton2.hint = localization.GetByLabel('UI/CharacterSelection/RemoveFromBiomass')
    633             now = blue.os.GetWallclockTime()
    634             timeLeft = deletePrepareTime - now
    635             timeLeftText = localization.formatters.FormatTimeIntervalShort(long(max(0, timeLeft)), showFrom='hour', showTo='second')
    636             self.timeLabel.text = timeLeftText
    637             self.portraitSprite.saturation = csColors.PORTRAIT_INACTIVE_SATURATION
    638             self.portraitSprite.effectOpacity = csColors.PORTRAIT_INACTIVE_EFFECT_OPACITY
    639             if animate:
    640                 uicore.animations.MorphScalar(self.deleteButton2.iconCont, 'rotation', startVal=self.deleteButton2.iconCont.rotation, endVal=0, duration=2.0)
    641                 uicore.animations.SpColorMorphTo(self.deleteButton2.icon, self.deleteButton2.icon.GetRGB(), csColors.BIOMASS_RED, csUtil.COLLAPSE_TIME)
    642                 uicore.animations.SpColorMorphTo(self.portraitSprite, self.portraitSprite.GetRGB(), csColors.BIOMASS_PORTRAIT, csUtil.COLLAPSE_TIME)
    643             else:
    644                 self.deleteButton2.iconCont.rotation = 0
    645                 self.deleteButton2.icon.SetRGBA(*csColors.BIOMASS_RED)
    646                 self.portraitSprite.SetRGBA(*csColors.BIOMASS_PORTRAIT)
    647             if timeLeft < 0:
    648                 self.deleteButton1.ExpandButton(animate=animate)
    649                 if animate:
    650                     uicore.animations.SpColorMorphTo(self.deleteButton2.icon, self.deleteButton2.icon.GetRGB(), csColors.BIOMASS_RED, csUtil.COLLAPSE_TIME)
    651                 else:
    652                     self.deleteButton2.icon.SetRGBA(*csColors.BIOMASS_RED)
    653             else:
    654                 self.deleteButton1.CollapseButton(animate=animate)
    655                 self.countDownThread = timerstuff.AutoTimer(1000, self.CountDown_thread)
    656         else:
    657             self.timeCont.display = False
    658             self.deleteButton1.CollapseButton(animate=animate)
    659             self.deleteButton2.hint = localization.GetByLabel('UI/CharacterSelection/Terminate')
    660             iconRotation = -math.pi / 4.0
    661             if animate:
    662                 uicore.animations.SpColorMorphTo(self.deleteButton2.icon, self.deleteButton2.icon.GetRGB(), csColors.BIOMASS_WHITE, csUtil.COLLAPSE_TIME)
    663                 uicore.animations.MorphScalar(self.deleteButton2.iconCont, 'rotation', startVal=self.deleteButton1.iconCont.rotation, endVal=iconRotation, duration=2.0)
    664                 self.SetMouseExitState()
    665             else:
    666                 self.deleteButton2.iconCont.rotation = iconRotation
    667                 self.deleteButton2.icon.SetRGBA(*csColors.BIOMASS_WHITE)
    668         self.AdjustNameLabel()
    669 
    670     def DeleteButton2Clicked(self):
    671         deletePrepTime = self.characterDetails.GetDeletePrepareTime()
    672         if self.deleteCallback and deletePrepTime is None:
    673             self.deleteCallback(self.charID)
    674             return
    675         if deletePrepTime and self.undoDeleteCallback:
    676             self.undoDeleteCallback(self.charID)
    677 
    678     def DeleteButton1Clicked(self):
    679         if self.terminateCallback:
    680             self.terminateCallback(self.charID)
    681 
    682     def LoadAtWarTooltipPanel(self, tooltipPanel, characterDetails, *args):
    683         wars = characterDetails.GetCharacterWars()
    684         corpID, allianceID = characterDetails.GetCorporationInfo()
    685         ownerID = allianceID or corpID
    686         LoadAtWarTooltipPanel(tooltipPanel, ownerID, wars)
    687 
    688 
    689 class SmallEmptySlot(SmallSlot):
    690     default_name = 'smallCharacterSlot'
    691     isEmptySlot = True
    692     isDropLocation = False
    693 
    694     def InCohort(self):
    695         return False
    696 
    697     def ApplyAttributes(self, attributes):
    698         SmallSlot.ApplyAttributes(self, attributes)
    699         self.nameSelectionFillActive.opacity = 0
    700         self.ownSlot = attributes.get('ownSlot', True)
    701         if self.ownSlot:
    702             text = localization.GetByLabel('UI/CharacterSelection/AddCharacter')
    703             texturePath = 'res:/UI/Texture/classes/CharacterSelection/plus2.png'
    704         else:
    705             text = localization.GetByLabel('UI/CharacterSelection/AddSlot')
    706             texturePath = 'res:/UI/Texture/classes/CharacterSelection/padlock.png'
    707         self.characterNameLabel.text = text
    708         self.characterNameLabel.SetAlign(uiconst.CENTER)
    709         self.characterNameLabel.left = -12
    710         self.plus = Sprite(parent=self.portraitInnerCont, align=uiconst.CENTER, texturePath=texturePath, idx=0, width=64, height=64, state=uiconst.UI_DISABLED, color=csColors.PLUS_INACTIVE)
    711         self.walletContainer.SetBigText(text)
    712         self.shipAndLocationCont.SetDisabled()
    713         self.skillQueueCont.SetSkillqueueForEmpty()
    714         self.SetMouseExitState()
    715 
    716     def SetMouseExitState(self, animate = False):
    717         SmallSlot.SetMouseExitState(self, animate=animate)
    718         SetColor(self.plus, csColors.PLUS_INACTIVE, animate=animate)
    719 
    720     def SetMouseOverState(self, animate = False):
    721         SmallSlot.SetMouseOverState(self, animate=animate)
    722         SetColor(self.plus, csColors.PLUS_ACTIVE, animate=animate)
    723 
    724 
    725 class SkillQueueCont(Container):
    726     default_align = uiconst.TOTOP
    727     default_height = 30
    728     default_padBottom = 8
    729     default_clipChildren = True
    730     paddingTimeText = 8
    731     paddingSkillText = 8
    732 
    733     def ApplyAttributes(self, attributes):
    734         Container.ApplyAttributes(self, attributes)
    735         self.glowFrame, self.normalFrame, self.fill = csUtil.AddFrameWithFillAndGlow(parent=self, fillColor=csColors.SKILLQUEUE_BACKGROUND_INACTIVE)
    736         self.isActive = True
    737         textCont = Container(name='textCont', parent=self)
    738         self.timeText = eveLabel.EveLabelMedium(parent=ContainerAutoSize(parent=textCont, align=uiconst.TORIGHT), name='textLabel', align=uiconst.CENTERRIGHT, text='', left=self.paddingTimeText, state=uiconst.UI_NORMAL)
    739         self.skillText = eveLabel.EveLabelMedium(parent=Container(parent=textCont, padRight=5), name='textLabel', align=uiconst.CENTERLEFT, text='', left=self.paddingSkillText, autoFadeSides=15)
    740         self.skillFill = Fill(parent=self, align=uiconst.TOLEFT_PROP, width=0.0, color=csColors.SKILLQUEUE_FILL_ACTIVE)
    741         self.skillEdge = Fill(parent=self, align=uiconst.TOLEFT, width=1, color=csColors.SKILLQUEUE_BRIGHT_EDGE)
    742 
    743     def SetText(self, skillText, timeText, hint):
    744         self.skillText.SetText('<b>%s</b>' % skillText)
    745         self.timeText.SetText(timeText)
    746         self.timeText.hint = hint
    747         width, h = self.GetAbsoluteSize()
    748         availableWidth = width - self.timeText.textwidth - self.paddingSkillText - self.paddingTimeText
    749         if self.skillText.textwidth > availableWidth:
    750             fadeEnd = availableWidth - 10
    751             self.skillText.SetRightAlphaFade(fadeEnd, maxFadeWidth=10)
    752 
    753     def SetSkillQueueActivityState(self, isActive = True):
    754         self.isActive = isActive
    755         if isActive:
    756             self.skillText.display = True
    757             self.timeText.display = True
    758             self.skillText.SetRGBA(*csColors.SKILLQUEUE_TEXT_TRAINING_INACTIVE)
    759             self.timeText.SetRGBA(*csColors.SKILLQUEUE_TEXT2_TRAINING_INACTIVE)
    760             self.fill.SetRGBA(*csColors.SKILLQUEUE_BACKGROUND_ACTIVE)
    761             self.normalFrame.SetRGBA(*csColors.SKILLQUEUE_FRAME_TRAINING_ACTIVE)
    762             self.skillFill.display = True
    763             self.skillEdge.display = True
    764         else:
    765             self.skillText.SetText(localization.GetByLabel('UI/CharacterSelection/NoSkillTraining'))
    766             self.skillText.SetRGBA(*csColors.SKILLQUEUE_TEXT_NOT_TRAINING_INACTIVE)
    767             self.timeText.SetRGBA(*csColors.SKILLQUEUE_TEXT_NOT_TRAINING_INACTIVE)
    768             self.timeText.display = False
    769             self.fill.SetRGBA(*csColors.SKILLQUEUE_BACKGROUND_INACTIVE)
    770             self.normalFrame.SetRGBA(*csColors.SKILLQUEUE_FRAME_NOT_TRAINING_ACTIVE)
    771             self.skillFill.display = False
    772             self.skillEdge.display = False
    773 
    774     def SetSkillqueueForEmpty(self):
    775         self.fill.SetRGBA(*csColors.SKILLQUEUE_FILL_INACTIVE)
    776         self.skillFill.display = False
    777         self.skillEdge.display = False
    778         self.normalFrame.SetRGBA(*csColors.SKILLQUEUE_FRAME_NOT_TRAINING_INACTIVE)
    779 
    780     def SetProgress(self, progress = 0.0):
    781         self.skillFill.width = progress
    782 
    783     def SetSelected(self, animate = False):
    784         SetColor(self.glowFrame, csColors.FRAME_GLOW_ACTIVE, animate=animate)
    785         SetColor(self.fill, csColors.SKILLQUEUE_BACKGROUND_ACTIVE, animate=animate)
    786         if self.isActive:
    787             SetColor(self.normalFrame, csColors.SKILLQUEUE_FRAME_TRAINING_ACTIVE, animate=animate)
    788             SetColor(self.skillFill, csColors.SKILLQUEUE_FILL_ACTIVE, animate=animate)
    789             SetColor(self.skillText, csColors.SKILLQUEUE_TEXT_TRAINING_ACTIVE, animate=animate)
    790             SetColor(self.timeText, csColors.SKILLQUEUE_TEXT2_TRAINING_ACTIVE, animate=animate)
    791         else:
    792             SetColor(self.normalFrame, csColors.SKILLQUEUE_FRAME_NOT_TRAINING_ACTIVE, animate=animate)
    793             SetColor(self.skillText, csColors.SKILLQUEUE_TEXT_NOT_TRAINING_ACTIVE, animate=animate)
    794             SetColor(self.timeText, csColors.SKILLQUEUE_TEXT_NOT_TRAINING_ACTIVE, animate=animate)
    795 
    796     def SetDeselected(self, animate = False):
    797         SetColor(self.glowFrame, csColors.FRAME_GLOW_INACTIVE, animate=animate)
    798         SetColor(self.fill, csColors.SKILLQUEUE_BACKGROUND_INACTIVE, animate=animate)
    799         if self.isActive:
    800             SetColor(self.normalFrame, csColors.SKILLQUEUE_FRAME_TRAINING_INACTIVE, animate=animate)
    801             SetColor(self.skillFill, csColors.SKILLQUEUE_FILL_INACTIVE, animate=animate)
    802             SetColor(self.skillText, csColors.SKILLQUEUE_TEXT_TRAINING_INACTIVE, animate=animate)
    803             SetColor(self.timeText, csColors.SKILLQUEUE_TEXT2_TRAINING_INACTIVE, animate=animate)
    804         else:
    805             SetColor(self.normalFrame, csColors.SKILLQUEUE_FRAME_NOT_TRAINING_INACTIVE, animate=animate)
    806             SetColor(self.skillText, csColors.SKILLQUEUE_TEXT_NOT_TRAINING_INACTIVE, animate=animate)
    807             SetColor(self.timeText, csColors.SKILLQUEUE_TEXT_NOT_TRAINING_INACTIVE, animate=animate)
    808 
    809 
    810 class CharacterDetailsLocation(Container):
    811     default_align = uiconst.TOBOTTOM
    812     default_alignMode = uiconst.TOTOP
    813     paddingShipAlignmentTop = 20
    814     paddingShipAlignmentBottom = 40
    815     locationContHeight = 60
    816     minShipSize = 40
    817     topOffset = (paddingShipAlignmentTop - paddingShipAlignmentBottom) / 2
    818 
    819     def ApplyAttributes(self, attributes):
    820         Container.ApplyAttributes(self, attributes)
    821         self.glowFrame, self.normalFrame, fill = csUtil.AddFrameWithFillAndGlow(parent=self, showFill=False, frameColor=csColors.LOCATION_FRAME_INACTIVE)
    822         self.characterDetails = None
    823         self.fullHeight = self.height
    824         self.isEmptySlot = attributes.get('isEmptySlot', False)
    825         self.callback = attributes.get('callback')
    826         self.locationCont = Container(parent=self, name='locationCont', height=self.locationContHeight, align=uiconst.TOBOTTOM)
    827         self.shipParentCont = Container(parent=self, name='shipParentCont', align=uiconst.TOALL, clipChildren=True)
    828         self.shipNameLabel = eveLabel.EveLabelSmall(parent=self.shipParentCont, name='shipText', align=uiconst.CENTERBOTTOM, top=4)
    829         self.shipCont = Container(parent=self.shipParentCont, name='shipCont', align=uiconst.TOALL, clipChildren=True)
    830         self.locationBg = Fill(bgParent=self.locationCont, color=csColors.LOCATION_FILL_ACTIVE)
    831         self.shipbg = Fill(bgParent=self.shipParentCont, color=(0, 0, 0, 0.7))
    832         self.vignette = Sprite(parent=self.shipCont, texturePath='res:/UI/Texture/classes/CharacterSelection/vignette.png', align=uiconst.TOALL, pos=(0,
    833          self.topOffset,
    834          0,
    835          0), padding=10, color=csColors.VIGNETTE_INACTIVE, state=uiconst.UI_DISABLED)
    836         self.shipGrid = Sprite(parent=self.shipCont, texturePath='res:/UI/Texture/classes/CharacterSelection/bigGrid.png', align=uiconst.CENTER, pos=(0,
    837          self.topOffset,
    838          256,
    839          256), color=csColors.GRID_ACTIVE, state=uiconst.UI_DISABLED)
    840         self.shipScaleXCont = ShipScale(parent=self.shipCont, name='shipScaleXCont', align=uiconst.CENTER, top=self.topOffset)
    841         self.shipScaleYCont = ShipScale(parent=self.shipCont, name='shipScaleYCont', align=uiconst.CENTER, isVertical=True, top=self.topOffset)
    842         self.shipScaleXCont.display = False
    843         self.shipScaleYCont.display = False
    844         self.shipIconCont = Container(parent=self.shipCont, name='shipIconCont', align=uiconst.CENTER, idx=0, top=self.topOffset)
    845         self.shipIcon = Sprite(parent=self.shipIconCont, name='shipIcon', align=uiconst.CENTER, pos=(0, 0, 128, 128), state=uiconst.UI_DISABLED, blendMode=trinity.TR2_SBM_ADD, spriteEffect=trinity.TR2_SFX_SOFTLIGHT, color=csColors.SHIP_ICON_ACTIVE)
    846         locationText = attributes.get('locationText', '')
    847         extraText = attributes.get('extraText', '')
    848         self.locationTextCont = Container(parent=self.locationCont, name='locationTextCont', align=uiconst.TOALL)
    849         self.textLabel = eveLabel.EveLabelLargeBold(parent=self.locationTextCont, name='textLabel', align=uiconst.CENTER, state=uiconst.UI_NORMAL, text=locationText, top=-10)
    850         self.textLabel.OnClick = self.OnClick
    851         self.extraTextLabel = eveLabel.EveLabelMedium(parent=self.locationTextCont, name='textLabel', align=uiconst.CENTER, text=extraText, top=10)
    852 
    853     def OnClick(self, *args):
    854         if self.callback:
    855             self.callback()
    856 
    857     def LoadInfo(self, characterDetails):
    858         self.characterDetails = characterDetails
    859         self.SetLocationText()
    860         currentShipTypeID = characterDetails.GetCurrentShip()
    861         texturePath = None
    862         try:
    863             graphicID = evetypes.GetGraphicID(currentShipTypeID)
    864             if graphicID is not None:
    865                 texturePath = inventorycommon.typeHelpers.GetHoloIconPath(currentShipTypeID)
    866         except AttributeError as e:
    867             log.LogException(e)
    868 
    869         self.shipIcon.SetTexturePath(texturePath)
    870         self.shipNameLabel.text = evetypes.GetName(currentShipTypeID)
    871         shipBoundingBox = SHIP_BOUNDING_BOXES.get(currentShipTypeID, None)
    872         if shipBoundingBox is None:
    873             shipBoundingBox = GetShipBoundingBox(texturePath)
    874         if shipBoundingBox:
    875             SHIP_BOUNDING_BOXES[currentShipTypeID] = shipBoundingBox
    876             shipWidth = shipBoundingBox['maxX'] - shipBoundingBox['minX']
    877             shipHeight = shipBoundingBox['maxY'] - shipBoundingBox['minY']
    878         else:
    879             shipWidth = 128
    880             shipHeight = 128
    881         self.shipIconCont.width = shipWidth
    882         self.shipIconCont.height = shipHeight
    883         if texturePath:
    884             self.shipScaleXCont.display = True
    885             self.shipScaleYCont.display = True
    886             self.shipScaleXCont.width = shipWidth
    887             self.shipScaleYCont.height = shipHeight
    888             self.shipScaleXCont.top = int(shipHeight / 2.0) + 10 + self.topOffset
    889             self.shipScaleYCont.left = -int(shipWidth / 2.0) - 15
    890 
    891     def SetLocationText(self, fontColor = (1.0, 1.0, 1.0, 1.0), secColorAlpha = 1.0):
    892         if not self.characterDetails:
    893             return
    894         stationID = self.characterDetails.GetCurrentStation()
    895         locationID, securityStatus = self.characterDetails.GetCurrentLocationInfo()
    896         securityText, secColor = eveFormat.FmtSystemSecStatus(securityStatus, 1)
    897         if csUtil.IsMonochromeStyleEnabled():
    898             secColor = Color.GRAY5
    899         secColor = int(Color.RGBtoHex(secColor[0], secColor[1], secColor[2], secColorAlpha), 16)
    900         normalTextColor = int(Color.RGBtoHex(*fontColor), 16)
    901         fontPath = None
    902         if locationID is None:
    903             locationText = ''
    904         elif IsAbyssalSpaceSystem(locationID):
    905             locationText = sm.GetService('abyss').get_mangled_system_name(locationID, self.characterDetails.charID)
    906             locationText = '<color=%s>%s' % (normalTextColor, locationText)
    907             fontPath = carbonui.fontconst.TRIGLAVIAN
    908         elif IsVoidSpaceSystem(locationID) or IsHiddenSpaceSystem(locationID):
    909             locationText = localization.GetByLabel('UI/Common/Unknown')
    910         else:
    911             locationText = cfg.evelocations.Get(locationID).name
    912             securityModifierText = self._GetSecurityModifierText(locationID)
    913             locationText = '<color=%s>%s</color>%s <color=%s>%s' % (secColor,
    914              securityText,
    915              securityModifierText,
    916              normalTextColor,
    917              locationText)
    918         if stationID:
    919             stationInfo = self.characterDetails.GetCurrentStationAndStationLocation()
    920             stationName = stationInfo.get('stationName', '')
    921             orbitName = stationInfo.get('shortOrbitName', '')
    922             if orbitName:
    923                 extraText = '>>> [%s] %s &lt;&lt;&lt;' % (orbitName, stationName)
    924             else:
    925                 extraText = '>>> %s &lt;&lt;&lt;' % (stationName,)
    926         else:
    927             extraText = localization.GetByLabel('UI/CharacterSelection/NotDocked')
    928         self.textLabel.fontPath = fontPath
    929         self.textLabel.SetText(locationText)
    930         slotWidth, h = self.GetAbsoluteSize()
    931         self.extraTextLabel.SetText(extraText)
    932         self.extraTextLabel.SetRGBA(*fontColor)
    933         if self.extraTextLabel.textwidth > slotWidth:
    934             self.extraTextLabel.SetAlign(uiconst.CENTERLEFT)
    935             self.extraTextLabel.left = 4
    936             fadeEnd = slotWidth - 10
    937             self.extraTextLabel.SetRightAlphaFade(fadeEnd, maxFadeWidth=20)
    938         else:
    939             self.extraTextLabel.left = 0
    940             self.extraTextLabel.SetAlign(uiconst.CENTER)
    941             self.extraTextLabel.SetRightAlphaFade(0, maxFadeWidth=0)
    942 
    943     @Memoize(1)
    944     def _GetSecurityModifierText(self, locationID):
    945         mapSvc = sm.RemoteSvc('map')
    946         modifiedSecuritySystems = mapSvc.GetSecurityModifiedSystems()
    947         indexedSystems = modifiedSecuritySystems.Index('solarSystemID')
    948         if locationID in indexedSystems:
    949             system = indexedSystems[locationID]
    950             return get_font_icon_text(system.security, system.modifiedSecurity)
    951         return ''
    952 
    953     def GetHeight(self, shipVisible = True):
    954         if not shipVisible:
    955             return self.locationContHeight + max(self.shipNameLabel.textheight + 2 * self.shipNameLabel.top, 20)
    956         padding = self.paddingShipAlignmentTop + self.paddingShipAlignmentBottom
    957         return max(self.shipIconCont.height, self.minShipSize) + self.locationCont.height + padding
    958 
    959     def SetShipContHeight(self, height):
    960         self.height = height
    961         self.fullHeight = height
    962 
    963     def SetDisabled(self):
    964         self.vignette.padLeft = -30
    965         self.vignette.padRight = -30
    966         self.vignette.padTop = -30
    967         self.vignette.padBottom = -30
    968         self.normalFrame.SetRGBA(*csColors.LOCATION_FRAME_INACTIVE)
    969         self.locationBg.SetRGBA(*csColors.LOCATION_FILL_INACTIVE)
    970         self.vignette.SetRGBA(*csColors.VIGNETTE_DISABLED)
    971 
    972     def SetActiveState(self, isActive = True, animate = False):
    973         if isActive:
    974             uthread.new(self.SetLocationText, fontColor=csColors.LOCATION_TEXT_ACTIVE)
    975             SetColor(self.glowFrame, csColors.FRAME_GLOW_ACTIVE, animate=animate)
    976         else:
    977             uthread.new(self.SetLocationText, fontColor=csColors.LOCATION_TEXT_INACTIVE, secColorAlpha=0.6)
    978             SetColor(self.glowFrame, csColors.FRAME_GLOW_INACTIVE, animate=animate)
    979 
    980     def SetSelected(self, animate = False):
    981         SetColor(self.shipGrid, csColors.GRID_ACTIVE, animate=animate)
    982         SetColor(self.shipIcon, csColors.SHIP_ICON_ACTIVE, animate=animate)
    983         SetColor(self.normalFrame, csColors.LOCATION_FRAME_ACTIVE, animate=animate)
    984         SetColor(self.locationBg, csColors.LOCATION_FILL_ACTIVE, animate=animate)
    985         SetColor(self.shipNameLabel, csColors.SHIP_NAME_ACTIVE, animate=animate)
    986         self.SetActiveVignetteColor(animate=animate)
    987 
    988     def SetDeselected(self, animate = False):
    989         SetColor(self.shipGrid, csColors.GRID_INACTIVE, animate=animate)
    990         SetColor(self.shipIcon, csColors.SHIP_ICON_INACTIVE, animate=animate)
    991         SetColor(self.normalFrame, csColors.LOCATION_FRAME_INACTIVE, animate=animate)
    992         SetColor(self.locationBg, csColors.LOCATION_FILL_INACTIVE, animate=animate)
    993         SetColor(self.shipNameLabel, csColors.SHIP_NAME_INACTIVE, animate=animate)
    994         self.SetInactiveVignetteColor(animate=animate)
    995 
    996     def SetActiveVignetteColor(self, animate = False):
    997         if self.isEmptySlot:
    998             SetColor(self.vignette, csColors.VIGNETTE_DISABLED, animate=animate)
    999         else:
   1000             SetColor(self.vignette, csColors.VIGNETTE_ACTIVE, animate=animate)
   1001 
   1002     def SetInactiveVignetteColor(self, animate = False):
   1003         if self.isEmptySlot:
   1004             SetColor(self.vignette, csColors.VIGNETTE_DISABLED, animate=animate)
   1005         else:
   1006             SetColor(self.vignette, csColors.VIGNETTE_INACTIVE, animate=animate)
   1007 
   1008     def CollapseShipSection(self, animate = True):
   1009         newHeight = self.locationContHeight + max(self.shipNameLabel.textheight + 2 * self.shipNameLabel.top, 20)
   1010         if animate:
   1011             uicore.animations.MorphScalar(self.shipCont, 'opacity', startVal=self.shipCont.opacity, endVal=0, duration=0.2)
   1012             uicore.animations.MorphScalar(self, 'height', startVal=self.height, endVal=newHeight, duration=csUtil.COLLAPSE_TIME)
   1013         else:
   1014             uicore.animations.StopAnimation(self.shipCont, 'opacity')
   1015             self.shipCont.opacity = 0
   1016             uicore.animations.StopAnimation(self, 'height')
   1017             self.height = newHeight
   1018 
   1019     def ExpandShipSection(self, animate = True):
   1020         if animate:
   1021             uicore.animations.MorphScalar(self.shipCont, 'opacity', startVal=self.shipCont.opacity, endVal=1.0, duration=0.6)
   1022             uicore.animations.MorphScalar(self, 'height', startVal=self.height, endVal=self.fullHeight, duration=csUtil.COLLAPSE_TIME)
   1023         else:
   1024             uicore.animations.StopAnimation(self.shipCont, 'opacity')
   1025             self.shipCont.opacity = 1.0
   1026             uicore.animations.StopAnimation(self, 'height')
   1027             self.height = self.fullHeight
   1028 
   1029     def Close(self):
   1030         self._GetSecurityModifierText.clear_memoized()
   1031         super(CharacterDetailsLocation, self).Close()
   1032 
   1033 
   1034 class CharacterDetailsLine(Container):
   1035     default_height = 20
   1036     default_align = uiconst.TOTOP
   1037     paddingText = 6
   1038     paddingIcon = 4
   1039 
   1040     def ApplyAttributes(self, attributes):
   1041         Container.ApplyAttributes(self, attributes)
   1042         iconPath = attributes.iconPath
   1043         self.addLine = attributes.get('addLine', True)
   1044         self.icon = Sprite(parent=self, name='icon', align=uiconst.CENTERLEFT, state=uiconst.UI_DISABLED, texturePath=iconPath, pos=(self.paddingIcon,
   1045          0,
   1046          24,
   1047          24), spriteEffect=trinity.TR2_SFX_SOFTLIGHT, color=csColors.LINES_ICON_INACTIVE)
   1048         iconPath2 = attributes.iconPath2
   1049         left = self.icon.left + self.icon.width + 2
   1050         self.icon2 = Sprite(parent=self, name='icon2', align=uiconst.CENTERLEFT, state=uiconst.UI_DISABLED, texturePath=iconPath2, pos=(left,
   1051          0,
   1052          24,
   1053          24), spriteEffect=trinity.TR2_SFX_SOFTLIGHT, color=csColors.LINES_ICON_INACTIVE)
   1054         self.icon.display = False
   1055         self.icon2.display = False
   1056         text = attributes.get('text', '')
   1057         self.textLabel = eveLabel.EveLabelMedium(parent=self, name='textLabel', align=uiconst.CENTERRIGHT, text=text, left=self.paddingText)
   1058         if self.addLine:
   1059             self.AddLine()
   1060         self.height = max(self.height, self.textLabel.textheight + 4)
   1061         if text:
   1062             self.SetTextAndEnableContainer(text)
   1063 
   1064     def SetTextAndEnableContainer(self, text):
   1065         self.textLabel.SetText(text)
   1066         self.EnableContainer()
   1067 
   1068     def EnableContainer(self):
   1069         self.icon.display = True
   1070         self.icon2.display = True
   1071 
   1072     def SetSecondIcon(self, texturePath, hint = ''):
   1073         self.icon2.SetTexturePath(texturePath)
   1074         self.icon2.display = True
   1075         self.icon2.state = uiconst.UI_NORMAL if texturePath else uiconst.UI_DISABLED
   1076         self.icon2.hint = hint
   1077 
   1078     def SetActiveState(self, isActive = True, animate = False):
   1079         if isActive:
   1080             SetColor(self.textLabel, csColors.LINES_TEXT_ACTIVE, animate=animate)
   1081             SetColor(self.icon, csColors.LINES_ICON_ACTIVE, animate=animate)
   1082             SetColor(self.icon2, csColors.LINES_ICON_ACTIVE, animate=animate)
   1083             if self.addLine:
   1084                 self.endDots.opacity = csColors.FRAME_GLOW_ACTIVE[3]
   1085                 SetColor(self.bottomLine, csColors.LINES_ACTIVE, animate=animate)
   1086         else:
   1087             SetColor(self.textLabel, csColors.LINES_TEXT_INACTIVE, animate=animate)
   1088             SetColor(self.icon, csColors.LINES_ICON_INACTIVE, animate=animate)
   1089             SetColor(self.icon2, csColors.LINES_ICON_INACTIVE, animate=animate)
   1090             if self.addLine:
   1091                 self.endDots.opacity = csColors.FRAME_GLOW_INACTIVE[3]
   1092                 SetColor(self.bottomLine, csColors.LINES_INACTIVE, animate=animate)
   1093 
   1094     def SetBigText(self, text):
   1095         bigTextLabel = getattr(self, 'bigTextLabel', None)
   1096         if bigTextLabel is None or bigTextLabel.destroyed:
   1097             self.bigTextLabel = eveLabel.CaptionLabel(parent=self, name='bigTextLabel', align=uiconst.CENTER, text='', fontsize=14, uppercase=False, letterspace=0, bold=False)
   1098             self.bigTextLabel.SetTextColor(csColors.ADDCHARACTER_TEXT_ACTIVE)
   1099         self.bigTextLabel.SetText(text)
   1100 
   1101     def AddLine(self):
   1102         padBottom = 0
   1103         weight = 1
   1104         self.bottomLine = Line(parent=self, align=uiconst.TOBOTTOM, weight=weight, color=csColors.LINES_ACTIVE, padBottom=padBottom)
   1105         self.endDots = ThreePartContainer(parent=self, name='endDots', align=uiconst.TOBOTTOM_NOPUSH, state=uiconst.UI_DISABLED, pos=(0,
   1106          0,
   1107          0,
   1108          weight), idx=0, leftTexturePath='res:/UI/Texture/classes/CharacterSelection/glowLineEndLeft.png', rightTexturePath='res:/UI/Texture/classes/CharacterSelection/glowLineEndRight.png', sideSize=8, color=csColors.FRAME_GLOW_ACTIVE)
   1109 
   1110 
   1111 class DeleteButton(Container):
   1112     default_state = uiconst.UI_NORMAL
   1113     default_align = uiconst.TORIGHT
   1114 
   1115     def ApplyAttributes(self, attributes):
   1116         Container.ApplyAttributes(self, attributes)
   1117         self.width = 14
   1118         self.fullWidth = self.width
   1119         texturePath = attributes.get('texturePath', None)
   1120         self.callback = attributes.get('callback')
   1121         color = attributes.get('color', (1, 0, 0, 1))
   1122         rotation = attributes.get('rotation', 0)
   1123         self.onMouseEnterCallback = attributes.get('onMouseEnterCallback')
   1124         self.onMouseExitCallback = attributes.get('onMouseExitCallback')
   1125         self.iconCont = Transform(parent=self, align=uiconst.CENTER, pos=(0, 0, 10, 10), state=uiconst.UI_DISABLED, rotation=rotation)
   1126         self.icon = Sprite(parent=self.iconCont, texturePath=texturePath, align=uiconst.TOPLEFT, pos=(0, 0, 10, 10), state=uiconst.UI_DISABLED, color=color)
   1127 
   1128     def OnClick(self, *args):
   1129         if self.callback:
   1130             self.callback()
   1131         self.icon.top = 0
   1132 
   1133     def OnMouseDown(self, *args):
   1134         self.icon.top = 2
   1135 
   1136     def OnMouseUp(self, *args):
   1137         self.icon.top = 0
   1138 
   1139     def OnMouseEnter(self, *args):
   1140         self.icon.SetAlpha(1.5)
   1141 
   1142     def OnMouseExit(self, *args):
   1143         self.icon.SetAlpha(1.0)
   1144 
   1145     def ExpandButton(self, animate = True):
   1146         if animate:
   1147             uicore.animations.MorphScalar(self, 'width', startVal=self.width, endVal=self.fullWidth, duration=csUtil.COLLAPSE_TIME)
   1148         else:
   1149             self.width = self.fullWidth
   1150 
   1151     def CollapseButton(self, animate = True):
   1152         if animate:
   1153             uicore.animations.MorphScalar(self, 'width', startVal=self.width, endVal=0, duration=csUtil.COLLAPSE_TIME)
   1154         else:
   1155             self.width = 0
   1156 
   1157 
   1158 class ShipScale(Container):
   1159     default_state = uiconst.UI_DISABLED
   1160     default_clipChildren = True
   1161     default_length = 256
   1162     default_weight = 5
   1163     default_scaleWeight = 3
   1164 
   1165     def ApplyAttributes(self, attributes):
   1166         Container.ApplyAttributes(self, attributes)
   1167         isVertical = attributes.get('isVertical', False)
   1168         length = attributes.get('length', self.default_length)
   1169         weight = attributes.get('weight', self.default_weight)
   1170         self.scaleWeigth = attributes.get('scaleWeight', self.default_scaleWeight)
   1171         scaleColor = attributes.get('scaleColor', csColors.GRID_SCALE)
   1172         endColor = attributes.get('endColor', scaleColor)
   1173         if isVertical:
   1174             self.height = length
   1175             self.width = weight
   1176             texturePath = 'res:/UI/Texture/classes/CharacterSelection/scaleY.png'
   1177             startScaleAlign = uiconst.TOBOTTOM_NOPUSH
   1178             endScaleAlign = uiconst.TOTOP_NOPUSH
   1179             spriteHeight = self.height
   1180             spriteWidth = self.scaleWeigth
   1181         else:
   1182             self.height = weight
   1183             self.width = length
   1184             texturePath = 'res:/UI/Texture/classes/CharacterSelection/scaleX.png'
   1185             startScaleAlign = uiconst.TOLEFT_NOPUSH
   1186             endScaleAlign = uiconst.TORIGHT_NOPUSH
   1187             spriteHeight = self.scaleWeigth
   1188             spriteWidth = self.width
   1189         Line(parent=self, align=startScaleAlign, color=endColor)
   1190         Line(parent=self, align=endScaleAlign, color=endColor)
   1191         self.scaleSprite = Sprite(parent=self, texturePath=texturePath, align=uiconst.CENTER, pos=(0,
   1192          0,
   1193          spriteWidth,
   1194          spriteHeight), color=scaleColor, state=uiconst.UI_DISABLED)
   1195 
   1196 
   1197 def GetShipBoundingBox(texturePath, ignoredColors = None):
   1198     if texturePath is None:
   1199         return
   1200     if ignoredColors is None:
   1201         ignoredColors = [(0, 0, 0, 1)]
   1202     image = blue.resMan.GetResource(texturePath, 'raw')
   1203     blue.resMan.Wait()
   1204     maxX = None
   1205     minX = None
   1206     maxY = None
   1207     minY = None
   1208     if not image.height:
   1209         return
   1210     for x in xrange(image.width):
   1211         for y in xrange(image.height):
   1212             color = image.GetPixelColor(x, y)
   1213             if color in ignoredColors:
   1214                 continue
   1215             if minX is None:
   1216                 minX = x
   1217             if maxX is None or maxX < x:
   1218                 maxX = x
   1219             if minY is None or minY > y:
   1220                 minY = y
   1221             if maxY is None or maxY < y:
   1222                 maxY = y
   1223 
   1224     return {'maxX': maxX or image.width,
   1225      'minX': minX or 0,
   1226      'maxY': maxY or image.height,
   1227      'minY': minY or 0}