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

characterCustomization.py (26673B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\login\charcreation\steps\characterCustomization.py
      2 from carbon.client.script.environment.AudioUtil import PlaySound
      3 from carbon.common.script.sys import serviceConst
      4 from carbonui import const as uiconst
      5 from carbonui.control.singlelineedits.singleLineEditInteger import SingleLineEditInteger
      6 from carbonui.primitives.container import Container
      7 from carbonui.primitives.containerAutoSize import ContainerAutoSize
      8 from carbonui.primitives.frame import Frame
      9 from carbonui.primitives.sprite import Sprite
     10 from carbonui.uianimations import animations
     11 from charactercreator import const as ccConst
     12 from eve.client.script.ui import eveColor
     13 from eve.client.script.ui.control import eveLabel
     14 from carbonui.control.buttonIcon import ButtonIcon
     15 from carbonui.control.button import Button
     16 from eve.client.script.ui.control.eveLabel import EveLabelMedium, Label, EveHeaderLarge
     17 from eve.client.script.ui.login.charcreation import ccUtil
     18 from eve.client.script.ui.login.charcreation.assetMenu import CCColorPalette, CharCreationAssetMenu
     19 from eve.client.script.ui.login.charcreation.charCreation import BaseCharacterCreationStep, CCHeadBodyPicker, MAXMENUSIZE
     20 from eve.client.script.ui.login.charcreation.hexes import CCGenderPicker, CCHexButtonRandomize
     21 from eve.client.script.ui.login.charcreation.historySlider import CharacterCreationHistorySlider
     22 from eveexceptions import UserError
     23 from evegraphics import settings as gfxsettings
     24 import localization
     25 import trinity
     26 import uthread
     27 import blue
     28 from carbonui.uicore import uicore
     29 from eveprefs import prefs, boot
     30 from itertoolsext.Enum import Enum
     31 
     32 class CharacterCustomization(BaseCharacterCreationStep):
     33     __notifyevents__ = ['OnColorPaletteChanged', 'OnHideUI', 'OnShowUI']
     34     stepID = ccConst.CUSTOMIZATIONSTEP
     35     ASSETMENU = 1
     36     TATTOOMENU = 2
     37 
     38     def ApplyAttributes(self, attributes):
     39         uicore.event.RegisterForTriuiEvents(uiconst.UI_ACTIVE, self.CheckAppFocus)
     40         BaseCharacterCreationStep.ApplyAttributes(self, attributes)
     41         info = self.GetInfo()
     42         self.menuMode = self.ASSETMENU
     43         self.charID = attributes.charID
     44         self.colorPaletteWidth = CCColorPalette.COLORPALETTEWIDTH
     45         self.tattooChangeMade = 0
     46         self.menusInitialized = 0
     47         self.tattoMenu = None
     48         self.assetMenu = None
     49         self.loadingWheelThread = None
     50         self.historySlider = None
     51         self.debugReloadBtn = None
     52         customizationOptionsContainer = ContainerAutoSize(name='customizationOptionsContainer', parent=self.leftSide, align=uiconst.TOLEFT, top=90, width=200)
     53         clickable = uicore.layer.charactercreation.controller.CanChangeGender()
     54         disabledHex = []
     55         CCGenderPicker(parent=Container(parent=customizationOptionsContainer, align=uiconst.TOTOP, height=80, left=40), align=uiconst.CENTER, genderID=info.genderID, clickable=clickable, disabledHex=disabledHex)
     56         EveLabelMedium(name='genderLabel', parent=customizationOptionsContainer, align=uiconst.TOTOP, text='<center>%s</center>' % localization.GetByLabel('UI/Common/Gender/Gender'))
     57         self.randomizeButton = CCHexButtonRandomize(name='randomizeButton', parent=Container(parent=customizationOptionsContainer, align=uiconst.TOTOP, height=64), align=uiconst.CENTER, state=uiconst.UI_NORMAL, width=64, height=64, pickRadius=32, iconNum=0, func=self.RandomizeCharacter, hexName=localization.GetByLabel('UI/CharacterCreation/Randomize'))
     58         EveLabelMedium(name='randomizeLabel', parent=customizationOptionsContainer, align=uiconst.TOTOP, text='<center>%s</center>' % localization.GetByLabel('UI/CharacterCreation/RandomizeAll'), top=-4)
     59         CCHeadBodyPicker(parent=customizationOptionsContainer, align=uiconst.TOTOP, headCallback=self.LoadFaceMode, bodyCallback=self.LoadBodyMode, top=10)
     60         EveLabelMedium(name='toggleClothesLabel', parent=customizationOptionsContainer, align=uiconst.TOTOP, text='<center>%s</center>' % localization.GetByLabel('UI/CharacterCreation/Zoom'))
     61         ButtonIcon(name='toggleClothesButton', parent=Container(parent=customizationOptionsContainer, align=uiconst.TOTOP, height=64, top=5), align=uiconst.CENTER, width=64, height=64, iconSize=64, texturePath='res:/UI/Texture/WindowIcons/charcustomization.png', func=self.ToggleClothes, useThemeColor=False, iconClass=Sprite, iconBlendMode=trinity.TR2_SBM_BLEND, hint=localization.GetByLabel('UI/CharacterCreation/ToggleClothes'))
     62         EveLabelMedium(name='toggleClothesLabel', parent=customizationOptionsContainer, align=uiconst.TOTOP, text='<center>%s</center>' % localization.GetByLabel('UI/CharacterCreation/ToggleClothes'))
     63         self.assetMenuParent = Container(parent=self.rightSide, name='assetMenuParent', pos=(20, 115, 500, 0), state=uiconst.UI_PICKCHILDREN, align=uiconst.TORIGHT)
     64         assetMenuWidth = min(MAXMENUSIZE, self.rightSide.width - 22)
     65         Label(name='assetMenuLabel', parent=Container(parent=self.assetMenuParent, align=uiconst.TOPRIGHT, width=assetMenuWidth, height=25), align=uiconst.CENTERLEFT, text=localization.GetByLabel('UI/CharacterCreation/CustomizeAppearance'), color=eveColor.PRIMARY_BLUE, fontsize=22, uppercase=True)
     66         self.hintBox = Container(name='hintBox', parent=self.assetMenuParent, pos=(-96, 30, 200, 150), align=uiconst.TOPLEFT, state=uiconst.UI_DISABLED)
     67         self.hintText = eveLabel.EveLabelMedium(parent=self.hintBox, align=uiconst.TOTOP)
     68         self.characterCustomizationInfoPanel = CharacterCustomizationInfoPanel(name='characterCustomizationInfoPanel', parent=self.uiContainer, align=uiconst.CENTERTOP, top=80, width=300)
     69         self.UpdateLayout()
     70         if uicore.layer.charactercreation.controller.needSculptingTutorial:
     71             self.ShowSculptingInfoPanel()
     72         elif uicore.layer.charactercreation.controller.needNavigationTutorial:
     73             self.ShowNavigationInfoPanel()
     74         uicore.layer.charactercreation.controller.camera.cameraModeChanged.connect(self._OnCameraModeChanged)
     75         self.StartLoadingThread()
     76 
     77     def StartLoadingThread(self, *args):
     78         if self.loadingWheelThread:
     79             self.loadingWheelThread.kill()
     80             self.loadingWheelThread = None
     81         self.loadingWheelThread = uthread.new(self.ShowLoadingWheel_thread)
     82 
     83     def SetHintText(self, modifier, hintText = ''):
     84         text = hintText
     85         if modifier in ccConst.HELPTEXTS:
     86             labelPath = ccConst.HELPTEXTS[modifier]
     87             text = localization.GetByLabel(labelPath)
     88         elif modifier == ccConst.eyes:
     89             labelPath = ccConst.HELPTEXTS[ccConst.EYESGROUP]
     90             text = localization.GetByLabel(labelPath)
     91         if text != self.hintText.text:
     92             self.hintText.text = text
     93 
     94     def ToggleClothes(self, *args):
     95         PlaySound(uiconst.SOUND_BUTTON_CLICK)
     96         if uicore.layer.charactercreation.controller.doll.busyUpdating:
     97             raise UserError('uiwarning01')
     98         uicore.layer.charactercreation.controller.ToggleClothes()
     99 
    100     def OnGenderSelected(self, genderID):
    101         self.GoToAssetMode(forcedMode=1)
    102         if self.tattoMenu:
    103             self.tattoMenu.Close()
    104 
    105     def UpdateLayout(self, *args):
    106         self.colorPaletteWidth = CCColorPalette.COLORPALETTEWIDTH
    107         sm.GetService('cc').LogInfo('CharacterCustomization::UpdateLayout')
    108         if not self.menusInitialized:
    109             self.tattoMenu = self.ReloadTattooMenu()
    110             self.assetMenu = self.ReloadAssetMenu()
    111             self.menusInitialized = 1
    112         self.LoadMenu()
    113 
    114     def OnColorPaletteChanged(self, width, *args):
    115         if width > self.colorPaletteWidth:
    116             self.colorPaletteWidth = width
    117 
    118     def RandomizeCharacter(self, *args):
    119         self.randomizeButton.StartBlinking()
    120         PlaySound('ui_icc_button_mouse_down_play')
    121         info = self.GetInfo()
    122         doll = self.charSvc.GetSingleCharactersDoll(info.charID)
    123         if doll.busyUpdating:
    124             return
    125         uicore.layer.charactercreation.controller.LockNavigation()
    126         uicore.layer.charactercreation.controller.ToggleClothes(forcedValue=0)
    127         if info.genderID == ccConst.GENDERID_FEMALE:
    128             itemList = ccConst.femaleRandomizeItems.keys()
    129         else:
    130             itemList = ccConst.maleRandomizeItems.keys()
    131         canChangeBaseAppearance = uicore.layer.charactercreation.controller.CanChangeBaseAppearance()
    132         blacklist = ccConst.randomizerCategoryBlacklist[:]
    133         if not canChangeBaseAppearance:
    134             blacklist += ccConst.recustomizationRandomizerBlacklist
    135         if boot.region == 'optic' and info.genderID == ccConst.GENDERID_FEMALE:
    136             blacklist.append(ccConst.scarring)
    137         categoryList = []
    138         for item in itemList:
    139             if item not in blacklist:
    140                 categoryList.append(item)
    141 
    142         self.charSvc.RandomizeCharacterGroups(info.charID, info.raceID, categoryList, doUpdate=False, fullRandomization=True)
    143         if canChangeBaseAppearance:
    144             self.charSvc.RandomizeCharacterSculpting(info.charID, info.raceID, doUpdate=False)
    145         decalModifiers = doll.buildDataManager.GetModifiersByCategory(ccConst.tattoo)
    146         for modifier in decalModifiers:
    147             modifier.IsDirty = True
    148 
    149         self.charSvc.UpdateDoll(info.charID, 'RandomizeCharacter')
    150         self.randomizeButton.StopBlinking()
    151 
    152     def LoadMenu(self, animate = 0, forcedMode = 0, *arg):
    153         sm.GetService('cc').LogInfo('CharacterCustomization::LoadMenu')
    154         menu = None
    155         if self.menuMode == self.ASSETMENU:
    156             menu = self.GetAssetMenu(forcedMode)
    157         elif self.menuMode == self.TATTOOMENU:
    158             menu = self.GetTattooMenu(forcedMode)
    159         if menu is None:
    160             return
    161         if animate:
    162             mainCont = menu.mainContainter
    163             if self.menuMode == self.TATTOOMENU:
    164                 menu.state = uiconst.UI_PICKCHILDREN
    165             else:
    166                 menu.state = uiconst.UI_DISABLED
    167                 uicore.effect.MorphUIMassSpringDamper(mainCont, 'top', 0, newthread=False, float=False, frequency=15.0, dampRatio=0.85)
    168                 menu.state = uiconst.UI_PICKCHILDREN
    169         else:
    170             menu.state = uiconst.UI_PICKCHILDREN
    171         menu.CheckIfOversize()
    172 
    173     def GetTattooMenu(self, forcedMode = 0, *args):
    174         sm.GetService('cc').LogInfo('CharacterCustomization::GetTattooMenu')
    175         if not forcedMode and self.tattoMenu and not self.tattoMenu.destroyed:
    176             if self.assetMenu:
    177                 self.assetMenu.state = uiconst.UI_HIDDEN
    178             return self.tattoMenu
    179         else:
    180             return self.ReloadTattooMenu()
    181 
    182     def ReloadTattooMenu(self, *args):
    183         sm.GetService('cc').LogInfo('CharacterCustomization::ReloadTattooMenu')
    184         self.StartLoadingThread()
    185         if self.assetMenu:
    186             self.assetMenu.state = uiconst.UI_HIDDEN
    187         if self.tattoMenu:
    188             self.tattoMenu.Close()
    189         info = self.GetInfo()
    190         piercingSub = (ccConst.p_brow,
    191          ccConst.p_nose,
    192          ccConst.p_nostril,
    193          ccConst.p_earshigh,
    194          ccConst.p_earslow,
    195          ccConst.p_lips,
    196          ccConst.p_chin)
    197         scarSub = (ccConst.s_head,)
    198         tattooSub = (ccConst.t_head, ccConst.t_armleft, ccConst.t_armright)
    199         augmentations = (ccConst.pr_armleft,
    200          ccConst.pr_armright,
    201          ccConst.augm_face,
    202          ccConst.augm_body)
    203         groups = []
    204         groups += [(ccConst.PIERCINGGROUP, piercingSub)]
    205         groups += [(ccConst.TATTOOGROUP, tattooSub)]
    206         groups += [(ccConst.SCARSGROUP, scarSub)]
    207         groups += [(ccConst.AUGMENTATIONS, augmentations)]
    208         self.tattoMenu = CharCreationAssetMenu(menuType='tattooMenu', parent=self.assetMenuParent, bloodlineID=info.bloodlineID, raceID=info.raceID, state=uiconst.UI_PICKCHILDREN, genderID=info.genderID, charID=info.charID, groups=groups, align=uiconst.TOALL, toggleFunc=self.GoToAssetMode, togglerIdx=0, top=26)
    209         return self.tattoMenu
    210 
    211     def GetAssetMenu(self, forcedMode = 0, *args):
    212         sm.GetService('cc').LogInfo('CharacterCustomization::GetAssetMenu')
    213         if not forcedMode and self.assetMenu and not self.assetMenu.destroyed:
    214             if self.tattoMenu and not self.tattoMenu.destroyed:
    215                 self.tattoMenu.state = uiconst.UI_HIDDEN
    216             return self.assetMenu
    217         else:
    218             return self.ReloadAssetMenu()
    219 
    220     def ReloadAssetMenu(self, *args):
    221         sm.GetService('cc').LogInfo('CharacterCustomization::ReloadAssetMenu')
    222         self.StartLoadingThread()
    223         if self.assetMenu:
    224             self.assetMenu.Close()
    225         if self.tattoMenu:
    226             self.tattoMenu.state = uiconst.UI_HIDDEN
    227         info = self.GetInfo()
    228         makeup = ccConst.MAKEUPGROUP
    229         if info.genderID == 1:
    230             makeup = ccConst.SKINDETAILSGROUP
    231         clothesSub = (ccConst.outer,
    232          ccConst.topouter,
    233          ccConst.topmiddle,
    234          ccConst.bottomouter,
    235          ccConst.bottommiddle,
    236          ccConst.feet,
    237          ccConst.glasses,
    238          ccConst.mask)
    239         groups = []
    240         if uicore.layer.charactercreation.controller.CanChangeBaseAppearance():
    241             groups += [(ccConst.BODYGROUP, ())]
    242             groups += [(ccConst.SKINGROUP, ())]
    243         groups += [(ccConst.EYESGROUP, ())]
    244         groups += [(ccConst.HAIRGROUP, ())]
    245         groups += [(makeup, (ccConst.eyeshadow,
    246            ccConst.eyeliner,
    247            ccConst.blush,
    248            ccConst.lipstick))]
    249         groups += [(ccConst.CLOTHESGROUP, clothesSub)]
    250         assetMenuWidth = min(MAXMENUSIZE + CCColorPalette.COLORPALETTEWIDTH, self.rightSide.width - 20)
    251         self.assetMenuMainWidth = assetMenuWidth - CCColorPalette.COLORPALETTEWIDTH
    252         self.assetMenu = CharCreationAssetMenu(menuType='assetMenu', parent=self.assetMenuParent, bloodlineID=info.bloodlineID, raceID=info.raceID, state=uiconst.UI_PICKCHILDREN, genderID=info.genderID, charID=info.charID, groups=groups, align=uiconst.TOALL, toggleFunc=self.GoToTattooMode, clipChildren=True, top=26)
    253         if self.historySlider:
    254             self.historySlider.Close()
    255         self.historySlider = CharacterCreationHistorySlider(parent=self.uiContainer, align=uiconst.CENTERBOTTOM, top=-45, width=400, opacity=0.0, bitChangeCheck=self.IsDollReady, lastLitHistoryBit=uicore.layer.charactercreation.controller.lastLitHistoryBit)
    256         mask = serviceConst.ROLE_CONTENT | serviceConst.ROLE_QA | serviceConst.ROLE_PROGRAMMER | serviceConst.ROLE_GML
    257         if session.role & mask:
    258             if self.debugReloadBtn:
    259                 self.debugReloadBtn.Close()
    260                 self.tattooModeBtn.Close()
    261                 self.typeAddEdit.Close()
    262                 self.validationToggle.Close()
    263                 self.typeAddBtn.Close()
    264             self.debugReloadBtn = Button(parent=self.uiContainer, func=self.GoToAssetMode, args=(1,), label='Reload Menu (debug)', align=uiconst.TOPRIGHT, left=self.randomizeButton.left + 30, top=16)
    265             self.tattooModeBtn = Button(parent=self.uiContainer, func=self.GoToTattooMode, args=(0, 1), label='Go to Tattoo mode (debug)', align=uiconst.TOPRIGHT, left=250, top=16)
    266             self.typeAddEdit = SingleLineEditInteger(parent=self.uiContainer, name='typeAdd', maxValue=100000, align=uiconst.TOPRIGHT, left=650, top=16, maxLength=10)
    267             self.validationToggle = Button(parent=self.uiContainer, name='validationToggle', func=self.ToggleValidation, label='Validation On', align=uiconst.TOPRIGHT, left=430, top=16)
    268             self.typeAddBtn = Button(parent=self.uiContainer, func=self.AddTypeButton, label='Add Type (debug)', align=uiconst.TOPRIGHT, left=530, top=16)
    269             self.addBlankDoll = Button(parent=self.uiContainer, func=self.AddBlankDrifterDoll, label='Add Blank Drifter Doll (debug)', align=uiconst.TOPRIGHT, left=530, top=35)
    270         animations.MorphScalar(self.historySlider, 'top', endVal=55, duration=0.125)
    271         animations.FadeIn(self.historySlider, duration=0.125)
    272         return self.assetMenu
    273 
    274     def AddBlankDrifterDoll(self, *args):
    275         from eve.common.script.paperDoll.paperDollDefinitions import LOD_SKIN
    276         info = self.GetInfo()
    277         self.charSvc.RemoveCharacter(info.charID)
    278         self.charSvc.AddCharacterToScene(info.charID, uicore.layer.charactercreation.controller.scene, ccUtil.GenderIDToPaperDollGender(info.genderID), bloodlineID=19, raceID=None, noRandomize=True, updateDoll=False)
    279         doll = uicore.layer.charactercreation.controller.doll = self.charSvc.GetSingleCharactersDoll(info.charID)
    280         while doll.IsBusyUpdating():
    281             blue.synchro.Yield()
    282 
    283         doll.overrideLod = LOD_SKIN
    284         textureQuality = gfxsettings.Get(gfxsettings.GFX_CHAR_TEXTURE_QUALITY)
    285         doll.textureResolution = ccConst.TEXTURE_RESOLUTIONS[textureQuality]
    286         if uicore.layer.charactercreation.controller.IsSlowMachine():
    287             doll.useFastShader = True
    288         else:
    289             doll.useFastShader = False
    290         self.charSvc.SetDollBloodline(info.charID, 19)
    291         self.charSvc.UpdateDoll(info.charID, fromWhere='AddCharacter')
    292 
    293     def ToggleValidation(self, *args):
    294         validating = sm.RemoteSvc('charUnboundMgr').ToggleValidation()
    295         if validating:
    296             self.validationToggle.SetLabel('Validation On')
    297         else:
    298             self.validationToggle.SetLabel('Validation Off')
    299 
    300     def AddTypeButton(self, *args):
    301         resourceID = self.typeAddEdit.GetValue()
    302         paperdollResource = cfg.paperdollResources.Get(resourceID)
    303         if paperdollResource:
    304             info = self.GetInfo()
    305             itemRelativeResPath = self.charSvc.GetRelativePath(paperdollResource.resPath).lower()
    306             itemTypeData = self.charSvc.factory.GetItemType(itemRelativeResPath, gender=ccUtil.GenderIDToPaperDollGender(info.genderID))
    307             itemInfo = (resourceID, itemTypeData[:3], paperdollResource.typeID)
    308             uicore.layer.charactercreation.controller.SetItemType(itemInfo)
    309 
    310     def GoToTattooMode(self, animate = 1, forcedMode = 0, *args):
    311         self.menuMode = self.TATTOOMENU
    312         self.tattooChangeMade = 0
    313         self.charSvc.StopEditing()
    314         if self.historySlider:
    315             self.historySlider.state = uiconst.UI_HIDDEN
    316         self.randomizeButton.Disable()
    317         if self.assetMenu and not self.assetMenu.destroyed:
    318             mainCont = self.assetMenu.mainContainter
    319             h = mainCont.displayHeight - self.assetMenu.menuToggler.height - 4
    320             uicore.effect.MorphUIMassSpringDamper(mainCont, 'top', -h, newthread=False, float=False, frequency=15.0, dampRatio=0.85)
    321         self.LoadMenu(animate=animate, forcedMode=forcedMode)
    322 
    323     def GoToAssetMode(self, forcedMode = 0, *args):
    324         self.menuMode = self.ASSETMENU
    325         if self.tattoMenu and not self.tattoMenu.destroyed:
    326             if self.tattooChangeMade:
    327                 uicore.layer.charactercreation.controller.TryStoreDna(False, 'GoToAssetMode', sculpting=False, force=1, allowReduntant=0)
    328             mainCont = self.tattoMenu.mainContainter
    329             h = self.tattoMenu.menuToggler.height + self.tattoMenu.menuToggler.padTop + self.tattoMenu.menuToggler.padBottom
    330             animations.MorphScalar(mainCont, 'top', endVal=0, duration=0.01)
    331             animations.MorphScalar(mainCont, 'height', endVal=h, duration=0.25, sleep=True)
    332         self.tattooChangeMade = 0
    333         if uicore.layer.charactercreation.controller.CanChangeBaseAppearance():
    334             uicore.layer.charactercreation.controller.StartEditMode()
    335         if self.historySlider:
    336             self.historySlider.state = uiconst.UI_PICKCHILDREN
    337         self.randomizeButton.Enable()
    338         self.LoadMenu(animate=1, forcedMode=forcedMode)
    339 
    340     def OnGenericMouseEnter(self, btn, *args):
    341         PlaySound('ui_icc_button_mouse_over_play')
    342         btn.icon.SetAlpha(1.0)
    343 
    344     def OnGenericMouseExit(self, btn, *args):
    345         btn.icon.SetAlpha(0.5)
    346 
    347     def LoadFaceMode(self, *args):
    348         info = self.GetInfo()
    349         avatar = self.charSvc.GetSingleCharactersAvatar(info.charID)
    350         uicore.layer.charactercreation.controller.camera.ToggleMode(ccConst.CAMERA_MODE_FACE, avatar=avatar, transformTime=500.0)
    351 
    352     def LoadBodyMode(self, *args):
    353         info = self.GetInfo()
    354         avatar = self.charSvc.GetSingleCharactersAvatar(info.charID)
    355         uicore.layer.charactercreation.controller.camera.ToggleMode(ccConst.CAMERA_MODE_BODY, avatar=avatar, transformTime=500.0)
    356 
    357     def ValidateStepComplete(self):
    358         info = self.GetInfo()
    359         if prefs.GetValue('ignoreCCValidation', False):
    360             return True
    361         if self.menuMode == self.TATTOOMENU:
    362             uicore.layer.charactercreation.controller.TryStoreDna(False, 'ValidateStepComplete', force=1, allowReduntant=0)
    363         while not self.IsDollReady():
    364             blue.synchro.Yield()
    365 
    366         return self.charSvc.ValidateDollCustomizationComplete(info.charID)
    367 
    368     def ShowLoadingWheel_thread(self, *args):
    369         layer = uicore.layer.charactercreation.controller
    370         doll = layer.doll
    371         while doll and not self.destroyed:
    372             if layer.step and getattr(layer.step, '_activeSculptZone', None) is not None:
    373                 layer.HideLoading()
    374             elif doll.busyUpdating:
    375                 layer.ShowLoading(why=localization.GetByLabel('UI/CharacterCreation/UpdatingCharacter'))
    376             else:
    377                 layer.HideLoading()
    378             blue.pyos.synchro.SleepWallclock(100)
    379 
    380     def CheckAppFocus(self, wnd, msgID, vkey):
    381         focused = vkey[0]
    382         if not focused and uicore.layer.charactercreation.controller:
    383             uicore.layer.charactercreation.controller.PassMouseEventToSculpt('LeftDown', uicore.uilib.x, uicore.uilib.y)
    384             uicore.layer.charactercreation.controller.PassMouseEventToSculpt('LeftUp', uicore.uilib.x, uicore.uilib.y)
    385             self.ChangeSculptingCursor(-1, 0, 0)
    386             uicore.layer.charactercreation.controller.UnfreezeAnimationIfNeeded()
    387         return 1
    388 
    389     def StoreHistorySliderPosition(self, *args):
    390         if self.historySlider:
    391             currentIndex, maxIndex = self.historySlider.GetCurrentIndexAndMaxIndex()
    392         else:
    393             currentIndex = None
    394         uicore.layer.charactercreation.controller.lastLitHistoryBit = currentIndex
    395 
    396     def _SetActiveSculptZone(self, sculptZone):
    397         super(CharacterCustomization, self)._SetActiveSculptZone(sculptZone)
    398         if sculptZone:
    399             self.HideSculptingInfoPanel()
    400 
    401     def _OnCameraModeChanged(self, previousMode, newMode):
    402         if previousMode is not None and newMode in [ccConst.CAMERA_MODE_FACE, ccConst.CAMERA_MODE_BODY]:
    403             uicore.layer.charactercreation.controller.needNavigationTutorial = False
    404             self.HideNavigationInfoPanel()
    405             uicore.layer.charactercreation.controller.camera.cameraModeChanged.disconnect(self._OnCameraModeChanged)
    406 
    407     def IsNavigationInfoPanelVisible(self):
    408         return self.characterCustomizationInfoPanel.IsVisible() and self.characterCustomizationInfoPanel.GetMode() == CharacterCustomizationInfoPanel.Modes.NAVIGATION
    409 
    410     def IsSculptingInfoPanelVisible(self):
    411         return self.characterCustomizationInfoPanel.IsVisible() and self.characterCustomizationInfoPanel.GetMode() == CharacterCustomizationInfoPanel.Modes.SCULPTING
    412 
    413     def ShowSculptingInfoPanel(self):
    414         if uicore.layer.charactercreation.controller.needSculptingTutorial:
    415             self.characterCustomizationInfoPanel.SetMode(CharacterCustomizationInfoPanel.Modes.SCULPTING)
    416             self.characterCustomizationInfoPanel.Show()
    417 
    418     def HideSculptingInfoPanel(self):
    419         if self.IsSculptingInfoPanelVisible():
    420             self.characterCustomizationInfoPanel.Hide(callback=lambda : self.ShowNavigationInfoPanel(timeOffset=1.0))
    421             uicore.layer.charactercreation.controller.needSculptingTutorial = False
    422 
    423     def ShowNavigationInfoPanel(self, timeOffset = 0.0):
    424         if uicore.layer.charactercreation.controller.needNavigationTutorial:
    425             self.characterCustomizationInfoPanel.SetMode(CharacterCustomizationInfoPanel.Modes.NAVIGATION)
    426             self.characterCustomizationInfoPanel.Show(timeOffset=timeOffset)
    427 
    428     def HideNavigationInfoPanel(self):
    429         if self.IsNavigationInfoPanelVisible():
    430             self.characterCustomizationInfoPanel.Hide()
    431             uicore.layer.charactercreation.controller.needNavigationTutorial = False
    432 
    433 
    434 class CharacterCustomizationInfoPanel(ContainerAutoSize):
    435 
    436     @Enum
    437 
    438     class Modes(object):
    439         NONE = 'NONE'
    440         NAVIGATION = 'NAVIGATION'
    441         SCULPTING = 'SCULPTING'
    442 
    443     def ApplyAttributes(self, attributes):
    444         super(CharacterCustomizationInfoPanel, self).ApplyAttributes(attributes)
    445         Frame(bgParent=self, color=(0.15, 0.15, 0.15, 1.0))
    446         self.background_color = (0.04, 0.04, 0.04, 1.0)
    447         self._mode = CharacterCustomizationInfoPanel.Modes.NONE
    448         self._title = EveHeaderLarge(name='sculptingInfoTitle', parent=self, align=uiconst.TOTOP, top=10)
    449         self._title.SetTextColor(eveColor.PRIMARY_BLUE)
    450         self._text = EveLabelMedium(name='sculptingInfoText', parent=self, align=uiconst.TOTOP, padding=(10, 10, 10, 10))
    451         self.opacity = 0
    452 
    453     def SetMode(self, mode):
    454         self._mode = mode
    455         if self._mode == CharacterCustomizationInfoPanel.Modes.NONE:
    456             self._SetTitle('')
    457             self._SetText('')
    458             self.opacity = 0
    459             return
    460         if self._mode == CharacterCustomizationInfoPanel.Modes.SCULPTING:
    461             self._SetTitle(localization.GetByLabel('UI/CharacterCreation/SculptingTool'))
    462             self._SetText(localization.GetByLabel('UI/CharacterCreation/SculptingToolHelp'))
    463         elif self._mode == CharacterCustomizationInfoPanel.Modes.NAVIGATION:
    464             self._SetTitle(localization.GetByLabel('UI/CharacterCreation/Navigation'))
    465             self._SetText(localization.GetByLabel('UI/CharacterCreation/NavigationHelp'))
    466 
    467     def GetMode(self):
    468         return self._mode
    469 
    470     def IsVisible(self):
    471         return self.opacity > 0
    472 
    473     def _SetTitle(self, title):
    474         self._title.SetText('<center>%s</center>' % title)
    475 
    476     def _SetText(self, text):
    477         self._text.SetText(text)
    478 
    479     def Show(self, timeOffset = 0.0, callback = None):
    480         uicore.animations.FadeTo(self, startVal=self.opacity, endVal=1.0, duration=0.25 * (1.0 - self.opacity), timeOffset=timeOffset, callback=callback)
    481 
    482     def Hide(self, timeOffset = 0.0, callback = None):
    483         uicore.animations.FadeTo(self, startVal=self.opacity, endVal=0.0, duration=0.25 * self.opacity, timeOffset=timeOffset, callback=callback)