skillQueueSkillEntry.py (17212B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\skillPlan\skillQueuePanel\skillQueueSkillEntry.py 2 import sys 3 import blue 4 import evetypes 5 import gametime 6 import localization 7 import log 8 import trinity 9 import uthread 10 from carbon.common.script.util import timerstuff 11 from carbon.common.script.util.commonutils import GetAttrs 12 from carbonui import const as uiconst 13 from carbonui.control.buttonIcon import ButtonIcon 14 from carbonui.primitives.container import Container 15 from carbonui.primitives.containerAutoSize import ContainerAutoSize 16 from carbonui.primitives.line import Line 17 from carbonui.primitives.sprite import Sprite 18 from carbonui.uianimations import animations 19 from carbonui.uicore import uicore 20 from clonegrade.const import COLOR_OMEGA_ORANGE 21 from eve.client.script.ui.control.eveLabel import EveLabelLarge 22 from eve.client.script.ui.control.eveScroll import Scroll 23 from eve.client.script.ui.shared.industry.views.errorFrame import ErrorFrame 24 from eve.client.script.ui.shared.info.panels.panelRequiredFor import RequiredForScrollController 25 from eve.client.script.ui.skillPlan.skillPlanEditor.skillPlanDropIndicatorCont import IsMultiSkillEntryMove 26 from omega.client.clone_grade_svc import get_clone_grade_svc 27 from player_messaging.client.ui_message import prompt_player_fsd_dialog 28 from skills.client.skillController import SkillController 29 from eve.client.script.ui.shared.neocom.skillConst import COLOR_SKILL_1, COLOR_MOVE_INDICATOR 30 from eve.client.script.ui.shared.neocom.skillConst import COLOR_TRAININGALLOWED, COLOR_TRAININGNOTALLOWED 31 from eve.client.script.ui.shared.neocom.timelineContainer import TimelineContainer 32 from eve.client.script.ui.skillPlan.skillQueuePanel.baseSkillEntry import BaseSkillEntry 33 from eveservices.menu import GetMenuService 34 from fsdBuiltData.common.iconIDs import GetIconFile 35 from localization import GetByLabel 36 from menu import MenuLabel 37 OPACITY_START = 0.3 38 39 class SkillQueueSkillEntry(BaseSkillEntry): 40 __guid__ = 'listentry.SkillQueueSkillEntry' 41 __nonpersistvars__ = ['selection', 'id'] 42 isDragObject = True 43 44 def ApplyAttributes(self, attributes): 45 self.entryHeight = 0 46 self.blinking = 0 47 super(SkillQueueSkillEntry, self).ApplyAttributes(attributes) 48 self.posIndicatorLine = None 49 self.acceleratedSprite = None 50 self.skillQueueSvc = sm.GetService('skillqueue') 51 self.skills = sm.GetService('skills') 52 self.timelineCont = None 53 self.flashCont = None 54 self.disabledFrame = None 55 self.removeButton = None 56 57 def CheckConstructRemoveButton(self): 58 if not self.removeButton: 59 self.removeButton = ButtonIcon(parent=self, align=uiconst.CENTERRIGHT, texturePath='res:/UI/Texture/Icons/105_32_12.png', pos=(0, 0, 24, 24), iconSize=24, func=self.RemoveFromQueue) 60 61 def CheckConstructAcceleratedSprite(self): 62 if not self.acceleratedSprite: 63 self.acceleratedSprite = Sprite(name='accelratedTraining', parent=self, align=uiconst.BOTTOMLEFT, state=uiconst.UI_HIDDEN, pos=(2, 4, 16, 16), texturePath='res:/UI/Texture/Crimewatch/booster.png', idx=0, hint=localization.GetByLabel('UI/SkillQueue/Skills/AcceleratedTraining')) 64 65 def Load(self, node): 66 BaseSkillEntry.Load(self, node) 67 self.controller = SkillController(node.skillID) 68 data = node 69 self.skillID = data.skillID 70 self.UpdateSkillNameLevelLabel() 71 self.inQueue = data.Get('inQueue', 0) 72 if data.trained: 73 queue = self.skillQueueSvc.GetQueue() 74 isTypeActive = len(queue) and data.skill.typeID == queue[0].trainingTypeID 75 isNextLevel = data.Get('currentLevel', -1) + 1 == data.Get('trainToLevel') 76 isNotQueuedRecord = data.Get('inQueue', 0) == 0 77 recordNeedsUpdating = isTypeActive and (isNotQueuedRecord or isNextLevel) 78 if recordNeedsUpdating: 79 uthread.new(self.UpdateTraining, data.skill) 80 else: 81 skill = data.skill 82 spsNextLevel = self.skills.SkillpointsNextLevel(skill.typeID) 83 if spsNextLevel is not None: 84 timeLeft = data.timeLeft 85 if timeLeft > 0: 86 timeLeftText = self._GetTimeLeftText(long(timeLeft)) 87 else: 88 timeLeftText = '' 89 self.timeLeftText.text = timeLeftText 90 self.HidePosIndicator() 91 if self.inQueue == 1 and self.inTrainingHilite: 92 self.inTrainingHilite.Hide() 93 self.UpdateAcceleratedMarker() 94 self.ConstructTypeUnlockIcons() 95 self.UpdateRemoveButton() 96 if self.timeLeftText: 97 if self.IsCurrentlyTraining(): 98 self.StartFlashAnimation() 99 self.timeLeftText.opacity = 1.0 100 else: 101 self.timeLeftText.opacity = 0.5 102 if self.IsDisabledForTraining() or self.sr.node.disabledForTraining: 103 self.ShowDisabledFrame() 104 else: 105 self.HideDisabledFrame() 106 107 def GetTypeID(self): 108 return self.sr.node.skillID 109 110 def IsCurrentlyTraining(self): 111 currSkill = sm.GetService('skillqueue').SkillInTraining() 112 isCurrentSkill = currSkill and currSkill.typeID == self.GetTypeID() and currSkill.trainedSkillLevel == self.GetTrainToLevel() - 1 113 return isCurrentSkill 114 115 def GetTrainToLevel(self): 116 return self.sr.node.trainToLevel 117 118 def HideDisabledFrame(self): 119 if self.disabledFrame: 120 self.disabledFrame.Hide() 121 122 def ShowDisabledFrame(self): 123 if not self.disabledFrame: 124 self.disabledFrame = ErrorFrame(bgParent=self, color=COLOR_OMEGA_ORANGE, opacityLow=0.15, padding=2) 125 self.disabledFrame.Show() 126 127 def IsDisabledForTraining(self): 128 maxLevel = get_clone_grade_svc().get_max_skill_level(self.skillID) 129 return maxLevel < self.GetTrainToLevel() 130 131 def DrawTimeline(self, offset, segments, animate = False): 132 self._CheckConstructTimeline() 133 self.timelineCont.FlushLine() 134 for width, color in segments: 135 self.timelineCont.AddSegment(width, color) 136 137 self.timelineCont.SetOffset(offset) 138 if animate: 139 self.timelineCont.opacity = 0.0 140 animations.FadeIn(self.timelineCont) 141 else: 142 self.timelineCont.StopAnimations() 143 self.timelineCont.opacity = 1.0 144 145 def HideTimeline(self, animate = False): 146 if animate: 147 animations.FadeOut(self.timelineCont, callback=self.timelineCont.FlushLine) 148 else: 149 self.timelineCont.FlushLine() 150 151 def _CheckConstructTimeline(self): 152 if self.timelineCont is None: 153 self.timelineCont = TimelineContainer(parent=self, idx=0, align=uiconst.TOBOTTOM_NOPUSH, state=uiconst.UI_DISABLED, barHeight=1, height=2, clipChildren=1) 154 155 def RemoveFromQueue(self): 156 self.sr.node.RemoveFromQueue(self.sr.node) 157 158 def UpdateRemoveButton(self): 159 data = self.sr.node 160 skillQueueSvc = sm.GetService('skillqueue') 161 isRemovable = skillQueueSvc.IsRemoveAllowed(data.invtype, data.trainToLevel) 162 if isRemovable: 163 self.CheckConstructRemoveButton() 164 self.removeButton.Show() 165 elif self.removeButton: 166 self.removeButton.Hide() 167 168 def StartFlashAnimation(self): 169 if not self.flashCont: 170 self.ConstructFlashCont() 171 uicore.animations.FadeTo(self.flashSprite, 0.3, 0.5, duration=1.0) 172 uicore.animations.MorphScalar(self.flashCont, 'left', -120, 0, duration=4.0, curveType=uiconst.ANIM_LINEAR, loops=uiconst.ANIM_REPEAT) 173 uicore.animations.FadeTo(self.flashCont, OPACITY_START, 1.0, duration=5.0, curveType=uiconst.ANIM_WAVE, loops=uiconst.ANIM_REPEAT) 174 175 def StopFlashAnimation(self): 176 if self.flashCont: 177 self.flashCont.StopAnimations() 178 self.flashCont.opacity = OPACITY_START 179 self.flashSprite.opacity = 0.0 180 181 def ConstructFlashCont(self): 182 color = COLOR_SKILL_1 183 self.flashCont = Container(name='flashCont', parent=self, state=uiconst.UI_DISABLED, idx=0, align=uiconst.TOPLEFT, width=self.width, height=self.height, opcaity=OPACITY_START) 184 self.flashSprite = Sprite(parent=self.flashCont, align=uiconst.CENTERLEFT, texturePath='res:/UI/Texture/Classes/Industry/CenterBar/arrows.png', pos=(0, 185 0, 186 1000, 187 self.height), color=color, opacity=0.2, tileX=True) 188 189 def OnDblClick(self, *args): 190 sm.GetService('info').ShowInfo(self.GetTypeID()) 191 192 def ConstructTypeUnlockIcons(self): 193 from eve.client.script.ui.shared.info.panels.panelRequiredFor import RequiredForScrollController 194 controller = RequiredForScrollController() 195 typeIDsByMarketGroupID = controller.GetUnlockTypeIDsByMarketGroup(self.GetTypeID(), self.GetTrainToLevel()) 196 if typeIDsByMarketGroupID: 197 iconSize = 24 198 cont = Container(parent=self.textCont) 199 iconCont = ContainerAutoSize(parent=cont, align=uiconst.CENTERLEFT, height=iconSize, left=8) 200 for marketGroupID, typeIDs in typeIDsByMarketGroupID.iteritems(): 201 TypesUnlockedIcon(parent=iconCont, align=uiconst.TOLEFT, width=iconSize, marketGroupID=marketGroupID, typeIDs=typeIDs) 202 203 iconCont.SetSizeAutomatically() 204 205 def UpdateSkillNameLevelLabel(self): 206 self.CheckConstructNameLevelLabel() 207 text = self.controller.GetRequiredSkillNameAndLevelComparedToTrainedLevel(self.GetTrainToLevel()) 208 self.nameLevelLabel.text = text 209 210 def UpdateAcceleratedMarker(self): 211 if not self.inQueue: 212 return 213 data = self.sr.node 214 if data.isAccelerated: 215 self.CheckConstructAcceleratedSprite() 216 self.acceleratedSprite.display = True 217 elif self.acceleratedSprite: 218 self.acceleratedSprite.display = False 219 220 def FillBoxes(self, currentLevel, trainToLevel): 221 inTraining = self.skillQueueSvc.SkillInTraining() 222 for i in xrange(currentLevel, 5): 223 if inTraining and inTraining.typeID == self.skillID: 224 if not self.inQueue: 225 if i == currentLevel: 226 self.blinking = 1 227 continue 228 elif currentLevel + 1 == trainToLevel: 229 self.blinking = 1 230 continue 231 box = self.sr.Get('box_%s' % i, None) 232 if box and i < trainToLevel: 233 box.SetRGBA(*self.blueColor) 234 box.state = uiconst.UI_DISABLED 235 236 def GetMenu(self): 237 m = GetMenuService().GetMenuForSkill(self.rec.typeID) 238 selected = self.sr.node.scroll.GetSelectedNodes(self.sr.node) 239 if self.inQueue == 1: 240 if GetAttrs(self, 'parent', 'RemoveSkillFromQueue'): 241 m.append(None) 242 m.append((MenuLabel('UI/Commands/Remove'), self.parent.RemoveSkillFromQueue, ())) 243 return m 244 245 def GetHint(self): 246 return evetypes.GetDescription(self.skillID) 247 248 def OnClick(self, *args): 249 if self.sr.node: 250 if self.sr.node.Get('selectable', 1): 251 self.sr.node.scroll.SelectNode(self.sr.node) 252 prompt_player_fsd_dialog('ListEntryClick') 253 if self.sr.node.Get('OnClick', None): 254 self.sr.node.OnClick(self) 255 256 def UpdateTraining(self, skill): 257 if not self or self.destroyed: 258 return 259 currentPoints = self.GetCurrentPoints(skill) 260 fill = self.sr.Get('box_%s' % int(skill.trainedSkillLevel)) 261 if not fill: 262 return 263 fill.state = uiconst.UI_DISABLED 264 if self.blinking == 1: 265 fill.SetRGBA(*COLOR_SKILL_1) 266 sm.StartService('ui').BlinkSpriteA(fill, 1.0, time=1000.0, maxCount=0, passColor=0, minA=0.5) 267 if self.inQueue == 0: 268 self.OnSkillpointChange(currentPoints) 269 270 def GetCurrentPoints(self, skill): 271 if not self or self.destroyed: 272 return 273 ETA = sm.GetService('skillqueue').GetEndOfTraining(skill.typeID) 274 level = skill.trainedSkillLevel 275 if not self or self.destroyed or GetAttrs(self, 'sr', 'node', 'skill', 'typeID') != skill.typeID: 276 return 277 if ETA: 278 time = ETA - gametime.GetWallclockTime() 279 secs = time / 10000000 280 else: 281 time = 0 282 secs = 0 283 currentPoints = sm.GetService('skillqueue').GetEstimatedSkillPointsTrained(skill.typeID) 284 if GetAttrs(self, 'sr', 'node', 'trainToLevel') != level: 285 if GetAttrs(self, 'sr', 'node', 'timeLeft'): 286 time = self.sr.node.timeLeft 287 else: 288 time = None 289 self.SetTimeLeft(time) 290 if ETA: 291 self.endOfTraining = ETA 292 else: 293 self.endOfTraining = None 294 self.lasttime = gametime.GetWallclockTime() 295 self.lastsecs = secs 296 self.lastpoints = currentPoints 297 self.timer = timerstuff.AutoTimer(1000, self.UpdateProgress) 298 return currentPoints 299 300 def UpdateProgress(self): 301 try: 302 if self.endOfTraining is None: 303 self.timer = None 304 return 305 skill = self.rec 306 timeLeft = self.endOfTraining - blue.os.GetWallclockTime() 307 if self.inQueue == 0: 308 currentPoints = self.skillQueueSvc.GetEstimatedSkillPointsTrained(skill.typeID) 309 self.OnSkillpointChange(currentPoints) 310 else: 311 self.SetTimeLeft(timeLeft) 312 except: 313 self.timer = None 314 log.LogException() 315 sys.exc_clear() 316 317 def GetDragData(self, *args): 318 return self.sr.node.scroll.GetSelectedNodes(self.sr.node) 319 320 def OnDropData(self, dragObj, nodes, *args): 321 self.HidePosIndicator() 322 if GetAttrs(self, 'parent', 'OnDropData'): 323 if self.inQueue: 324 self.parent.OnDropData(dragObj, nodes, idx=self.sr.node.idx) 325 else: 326 node = nodes[0] 327 if GetAttrs(node, 'panel', 'inQueue'): 328 self.parent.OnDropData(dragObj, nodes) 329 330 def OnDragEnter(self, dragObj, nodes, *args): 331 if not self.inQueue or nodes is None: 332 return 333 self.ShowPosIndicator(nodes) 334 335 def CheckConstructPosIndicatorLine(self): 336 if not self.posIndicatorLine: 337 self.posIndicatorLine = Line(parent=self, align=uiconst.TOPLEFT_PROP, pos=(0, 0, 0.99, 2), state=uiconst.UI_DISABLED, opacity=0.0, idx=0) 338 339 def ShowPosIndicator(self, nodes): 340 self.CheckConstructPosIndicatorLine() 341 if IsMultiSkillEntryMove(nodes): 342 color = COLOR_MOVE_INDICATOR 343 else: 344 firstNode = nodes[0] 345 allowedMove = self.skillQueueSvc.IsMoveAllowed(firstNode, self.sr.node.idx) 346 if allowedMove: 347 color = COLOR_TRAININGALLOWED 348 elif self.skillQueueSvc.IsSkillEntry(firstNode): 349 color = COLOR_TRAININGNOTALLOWED 350 else: 351 color = (0, 0, 0, 0) 352 self.posIndicatorLine.SetRGBA(*color) 353 354 def OnDragExit(self, *args): 355 if not self.inQueue: 356 return 357 self.HidePosIndicator() 358 359 def HidePosIndicator(self): 360 if self.posIndicatorLine: 361 self.posIndicatorLine.opacity = 0.0 362 363 def GetDynamicHeight(node, width): 364 name = localization.GetByLabel('UI/SkillQueue/Skills/SkillNameAndRankValue', skill=node.skill.typeID, rank=0) 365 _, nameHeight = EveLabelLarge.MeasureTextSize(name, maxLines=1) 366 return max(32, nameHeight + 8) 367 368 369 class TypesUnlockedIcon(Sprite): 370 default_spriteEffect = trinity.TR2_SFX_SOFTLIGHT 371 default_saturation = 0.0 372 default_effectOpacity = 0.0 373 default_opacity = 0.85 374 375 def ApplyAttributes(self, attributes): 376 Sprite.ApplyAttributes(self, attributes) 377 self.typeIDs = attributes.typeIDs 378 marketGroupID = attributes.marketGroupID 379 self.marketGroup = cfg.GetMarketGroup(marketGroupID) 380 self.texturePath = GetIconFile(self.marketGroup.iconID, 'res:/ui/Texture/WindowIcons/smallfolder.png') 381 382 def LoadTooltipPanel(self, tooltipPanel, *args): 383 tooltipPanel.LoadGeneric1ColumnTemplate() 384 tooltipPanel.state = uiconst.UI_NORMAL 385 text = GetByLabel('UI/CharacterSheet/CharacterSheetWindow/SkillTabs/TypesUnlockedCaption', groupName=self.marketGroup.marketGroupName) 386 tooltipPanel.AddLabelLarge(text=text, cellPadding=(0, 4, 0, 6)) 387 controller = RequiredForScrollController() 388 scrollList = controller.GetTypeScrollList(self.typeIDs) 389 maxWidth = max((EveLabelLarge.MeasureTextSize(x.label)[0] for x in scrollList)) 390 maxWidth = max(maxWidth + 60, 250) 391 maxHeight = 205 392 height = min(maxHeight, len(scrollList) * 30 + 3) 393 scroll = Scroll(align=uiconst.TOPLEFT, pos=(0, 394 0, 395 maxWidth, 396 height)) 397 scroll.HideBackground() 398 scroll.Load(fixedEntryHeight=27, contentList=scrollList) 399 tooltipPanel.AddCell(scroll)