careerNode.py (17868B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\careerPortal\circleView\careerNode.py 2 import math 3 import carbonui.const as uiconst 4 import trinity 5 from carbon.client.script.environment.AudioUtil import PlaySound 6 from carbon.common.script.sys.serviceConst import ROLE_GML 7 from carbonui.control.button import Button 8 from carbonui import ButtonFrameType, ButtonVariant, Density 9 from carbonui.primitives.container import Container 10 from carbonui.primitives.containerAutoSize import ContainerAutoSize 11 from carbonui.primitives.sprite import Sprite 12 from carbonui.primitives.transform import Transform 13 from carbonui.uianimations import animations 14 from carbonui.util.color import Color 15 from careergoals.client.career_goal_svc import get_career_goals_svc 16 from characterdata import careerpath, careerpathconst 17 from eve.client.script.ui import eveColor 18 from eve.client.script.ui.control.donutSegment import DonutSegment 19 from eve.client.script.ui.control.eveLabel import EveCaptionLarge 20 from eve.client.script.ui.control.gaugeCircular import GaugeCircular 21 from eve.client.script.ui.control.infoIcon import InfoGlyphIcon 22 from eve.client.script.ui.shared.careerPortal import cpSignals, careerConst 23 from eve.client.script.ui.shared.careerPortal.careerConst import LEVEL_ANIMATION_DURATION 24 from eve.client.script.ui.shared.careerPortal.careerControllerUI import get_career_portal_controller_svc 25 from eve.client.script.ui.shared.careerPortal.careerPointsLabel import CareerPointsLabel 26 from eve.client.script.ui.shared.careerPortal.circleView.circleNode import CircleNode 27 from eve.client.script.ui.shared.careerPortal.link.dragData import NodeDragData 28 from eve.client.script.ui.util.uix import GetTextWidth, GetTextHeight, QtyPopup 29 from localization import GetByMessageID, GetByLabel 30 LABEL_CONTAINER_HEIGHT = 30 31 TEXT_CONT_TOP = 4 32 GLYPH_ICON_SIZE = 16 33 ICON_SIZE = 128 34 BG_PADDING = 180 35 NODE_MAX_SIZE = 180 36 ANIM_DURATION = 0.4 37 38 class CareerNode(CircleNode): 39 default_name = 'CareerNode' 40 default_state = uiconst.UI_NORMAL 41 default_align = uiconst.CENTER 42 isInCenter = False 43 44 def GetMenu(self): 45 if session and session.role & ROLE_GML: 46 menu = [['QA: Complete', self._Debug_CompleteGoal], ['QA: Progress', self._Debug_ProgressGoal]] 47 return menu 48 49 def _Debug_CompleteGoal(self): 50 get_career_goals_svc().get_goal_data_controller().admin_complete_goal(self.nodeObject.goal.goal_id) 51 52 def _Debug_ProgressGoal(self): 53 ret = QtyPopup(minvalue=0, setvalue=1, maxvalue=self.nodeObject.goal.definition.target_value) 54 if ret and 'qty' in ret: 55 get_career_goals_svc().get_goal_data_controller().admin_progress_goal(self.nodeObject.goal.goal_id, ret['qty']) 56 57 def ApplyAttributes(self, attributes): 58 self.nodeObject = attributes.nodeObject 59 self.prevPos = None 60 super(CareerNode, self).ApplyAttributes(attributes) 61 progress, target = self.nodeObject.GetCareerPathProgress() 62 self.iconGauge.SetGaugeValue(progress, target) 63 self.iconGauge.UpdateGaugeColor(progress >= target) 64 self.OnCareerWindowStateChanged(attributes.initialState) 65 66 def GetSignals(self): 67 signals = super(CareerNode, self).GetSignals() 68 signals.extend([(cpSignals.on_career_node_hover_on, self.OnCareerNodeHoveredOn), (cpSignals.on_career_node_hover_off, self.OnCareerNodeHoveredOff)]) 69 return signals 70 71 def PrepareUI(self): 72 self.iconGauge = IconWithGauge(parent=self, align=uiconst.CENTERTOP, nodeObject=self.nodeObject) 73 self.textCont = CardTextCont(name='textCont', parent=self, nodeObject=self.nodeObject) 74 75 def OnGoalUpdated(self, goalID, value): 76 if goalID != self.nodeObject.goal.goal_id: 77 return 78 if careerConst.CAREER_WINDOW_STATE_SETTING.get() != careerConst.CareerWindowState.CAREERS_VIEW and careerConst.SELECTED_CAREER_PATH_SETTING.get() != self.nodeObject.careerPathID: 79 self.FadeIn(callback=lambda : self.FadeOut(timeOffset=1.5)) 80 progress, target = self.nodeObject.GetCareerPathProgress() 81 self.iconGauge.SetGaugeValue(progress, target) 82 83 def ResizeComponents(self, nodeSize, left, top, angle, animate = False): 84 self.iconGauge.ResizeComponents(nodeSize, animate) 85 self.textCont.top = self.iconGauge.height + TEXT_CONT_TOP 86 newWidth = max(self.textCont.GetWidth(), self.iconGauge.gauge.width) 87 textContHeight = self.textCont.GetHeight() 88 newHeight = textContHeight + self.iconGauge.gauge.height + TEXT_CONT_TOP 89 newAnchorY = newAnchorX = nodeSize / 2 90 top += textContHeight / 2 91 if self.IsSelected(): 92 self._GoToCenter() 93 if animate: 94 animations.MorphScalar(self, 'width', self.width, newWidth, duration=LEVEL_ANIMATION_DURATION) 95 animations.MorphScalar(self, 'height', self.width, newHeight, duration=LEVEL_ANIMATION_DURATION) 96 animations.MorphScalar(self, 'left', startVal=self.left, endVal=left, duration=careerConst.LEVEL_ANIMATION_DURATION) 97 animations.MorphScalar(self, 'top', startVal=self.top, endVal=top, duration=careerConst.LEVEL_ANIMATION_DURATION) 98 animations.MorphScalar(self, 'anchorPointX', self.anchorPointX, newAnchorX, duration=LEVEL_ANIMATION_DURATION) 99 animations.MorphScalar(self, 'anchorPointY', self.anchorPointY, newAnchorY, duration=LEVEL_ANIMATION_DURATION) 100 else: 101 self.top = top 102 self.left = left 103 self.width = newWidth 104 self.height = newHeight 105 self.prevPos = (left, 106 top, 107 newWidth, 108 newHeight) 109 self.anchorPointY = newAnchorY 110 self.anchorPointX = newAnchorY 111 112 def IsSelected(self): 113 careerID = careerConst.SELECTED_CAREER_PATH_SETTING.get() 114 return careerID == self.nodeObject.careerPathID 115 116 def OnCareerWindowStateChanged(self, state): 117 careerID = careerConst.SELECTED_CAREER_PATH_SETTING.get() 118 if state == careerConst.CareerWindowState.CAREERS_VIEW: 119 self.Show() 120 animations.FadeIn(self, duration=ANIM_DURATION) 121 animations.Tr2DRotateTo(self, startAngle=self.rotation, endAngle=0) 122 self.textCont.Show() 123 animations.FadeIn(self.textCont, duration=ANIM_DURATION, callback=self.textCont.careerPointsLabel.Reset) 124 if careerID == self.nodeObject.careerPathID: 125 self._GoToCircle() 126 else: 127 self.Enable() 128 animations.Tr2DScaleTo(self.iconGauge, startScale=self.iconGauge.scale, endScale=(1.0, 1.0)) 129 if state in (careerConst.CareerWindowState.ACTIVITIES_VIEW, careerConst.CareerWindowState.GOALS_VIEW): 130 animations.Tr2DRotateTo(self, startAngle=self.rotation, endAngle=math.radians(-careerConst.CIRCLE_ROTATION_BY_CAREER[careerID])) 131 animations.FadeOut(self.textCont, duration=0.2) 132 if self.nodeObject.careerPathID == careerID: 133 self._GoToCenter() 134 else: 135 self.Disable() 136 animations.FadeOut(self, duration=ANIM_DURATION, callback=self.Hide) 137 animations.Tr2DScaleTo(self.iconGauge, self.iconGauge.scale, (0.8, 0.8)) 138 139 def _GoToCircle(self): 140 animations.MoveTo(self, self.pos, self.prevPos) 141 textContHeight = self.textCont.GetHeight() 142 newHeight = textContHeight + self.iconGauge.gauge.height + TEXT_CONT_TOP 143 animations.MorphScalar(self, 'height', self.height, newHeight, duration=0.2) 144 careerConst.SELECTED_CAREER_PATH_SETTING.set(careerpathconst.career_path_none) 145 self.isInCenter = False 146 147 def _GoToCenter(self): 148 animations.MoveTo(self, startPos=self.pos, endPos=(0, 0)) 149 newHeight = self.iconGauge.width or 172 150 animations.MorphScalar(self, 'height', self.height, newHeight, duration=0.2) 151 animations.Tr2DScaleTo(self.iconGauge, startScale=self.iconGauge.scale, endScale=(1.5, 1.5)) 152 self.isInCenter = True 153 154 def OnClick(self, *args): 155 PlaySound('career_portal_select_profession_play') 156 if careerConst.SELECTED_CAREER_PATH_SETTING.get() == self.nodeObject.careerPathID: 157 currentState = careerConst.CAREER_WINDOW_STATE_SETTING.get() 158 if currentState == careerConst.CareerWindowState.GOALS_VIEW: 159 newState = careerConst.CareerWindowState.ACTIVITIES_VIEW 160 else: 161 newState = careerConst.CareerWindowState.CAREERS_VIEW 162 careerConst.CAREER_WINDOW_STATE_SETTING.set(newState) 163 else: 164 get_career_portal_controller_svc().select_career(self.nodeObject.careerPathID, self.nodeObject.goal.goal_id) 165 166 def OnMouseEnter(self, *args): 167 self.iconGauge.OnMouseEnter(*args) 168 if self.IsAnimating(): 169 return 170 PlaySound('career_portal_hover_profession_play') 171 cpSignals.on_career_node_hover_on(self.nodeObject.careerPathID) 172 173 def OnMouseExit(self, *args): 174 self.iconGauge.OnMouseExit(*args) 175 cpSignals.on_career_node_hover_off(self.nodeObject.careerPathID) 176 177 def IsAnimating(self): 178 return self.HasAnimation('left') or self.HasAnimation('top') 179 180 def OnCareerNodeHoveredOn(self, careerPathID): 181 currentState = careerConst.CAREER_WINDOW_STATE_SETTING.get() 182 if currentState != careerConst.CareerWindowState.ACTIVITIES_VIEW: 183 return 184 if careerPathID != self.nodeObject.careerPathID: 185 self.Show() 186 animations.FadeIn(self, duration=0.2) 187 188 def OnCareerNodeHoveredOff(self, careerPathID): 189 currentState = careerConst.CAREER_WINDOW_STATE_SETTING.get() 190 if currentState != careerConst.CareerWindowState.ACTIVITIES_VIEW: 191 return 192 if careerPathID != self.nodeObject.careerPathID: 193 animations.FadeOut(self, duration=0.2, callback=self.Hide) 194 195 def FadeIn(self, callback = None): 196 animations.FadeIn(self, duration=ANIM_DURATION, callback=callback) 197 198 def FadeOut(self, timeOffset = 0.0): 199 animations.FadeOut(self, duration=ANIM_DURATION, timeOffset=timeOffset) 200 201 def GetDragData(self): 202 if self.nodeObject: 203 return NodeDragData(self.nodeObject.careerPathID, None, None, self.nodeObject.careerPathName) 204 205 206 class CardTextCont(ContainerAutoSize): 207 default_alignMode = uiconst.TOTOP 208 default_align = uiconst.CENTERTOP 209 210 def ApplyAttributes(self, attributes): 211 super(CardTextCont, self).ApplyAttributes(attributes) 212 self.nodeObject = attributes.nodeObject 213 self.careerInfoContainer = ContainerAutoSize(name='careerInfoContainer', parent=self, align=uiconst.TOTOP) 214 nameLabelAndInfoContainer = Container(name='nameLabelAndInfoContainer', parent=self.careerInfoContainer, align=uiconst.TOTOP, height=LABEL_CONTAINER_HEIGHT) 215 self.careerPathLabel = EveCaptionLarge(parent=nameLabelAndInfoContainer, name='careerPathLabel', align=uiconst.CENTER, state=uiconst.UI_DISABLED, bold=True, singleline=True, text=self.nodeObject.careerPathName) 216 self.infoGlyphIcon = InfoGlyphIcon(parent=nameLabelAndInfoContainer, align=uiconst.CENTER) 217 pointsContainer = Container(name='pointsContainer', parent=self.careerInfoContainer, align=uiconst.TOTOP, height=20) 218 self.careerPointsLabel = CareerPointsLabel(parent=pointsContainer, careerNode=self.nodeObject) 219 self.videoButton = Button(parent=Container(name='playButtonContainer', parent=self, align=uiconst.TOTOP, height=24, top=4), name='videoButton', align=uiconst.CENTER, label=GetByLabel('UI/CareerPortal/PlayVideo'), texturePath='res:/UI/Texture/classes/careerPortal/playVideo.png', func=self.PlayVideo, iconSize=GLYPH_ICON_SIZE, density=Density.COMPACT, variant=ButtonVariant.GHOST, frame_type=ButtonFrameType.CUT_BOTTOM_LEFT_RIGHT) 220 self.UpdateLabels() 221 self.width = self.GetWidth() 222 223 def UpdateLabels(self): 224 self.infoGlyphIcon.left = self.careerPathLabel.width / 2 + GLYPH_ICON_SIZE 225 self.infoGlyphIcon.hint = GetByLabel(careerConst.CAREER_DESCRIPTIONS.get(self.nodeObject.careerPathID, '')) 226 227 def PlayVideo(self, *args): 228 videoPath = careerConst.CAREER_VIDEOS.get(self.nodeObject.careerPathID, None) 229 get_career_portal_controller_svc().play_video(videoPath) 230 231 def GetWidth(self): 232 careerLabelWidth = GetTextWidth(self.nodeObject.careerPathName, fontsize=self.careerPathLabel.fontsize, bold=True) 233 return careerLabelWidth + self.infoGlyphIcon.width + GLYPH_ICON_SIZE + 4 234 235 def GetHeight(self): 236 careerLabelHeight = GetTextHeight(self.nodeObject.careerPathName, fontsize=self.careerPathLabel.fontsize, bold=True) 237 pointsLabelHeight = GetTextHeight(self.nodeObject.GetCareerPathPointsText()) 238 totalHeight = careerLabelHeight + pointsLabelHeight + self.videoButton.parent.height + self.videoButton.parent.top * 2 239 return totalHeight 240 241 242 class IconWithGauge(Transform): 243 default_align = uiconst.CENTERTOP 244 default_state = uiconst.UI_DISABLED 245 default_bgGaugeOpacity = 0.15 246 default_rotationCenter = (0.5, 0.5) 247 default_scalingCenter = (0.5, 0.5) 248 249 def ApplyAttributes(self, attributes): 250 super(IconWithGauge, self).ApplyAttributes(attributes) 251 self.nodeObject = attributes.nodeObject 252 texturePath = self.nodeObject.iconTexturePath 253 self.isSelected = False 254 self.gauge = GaugeCircular(parent=self, name='gauge', align=uiconst.CENTER, lineWidth=4, clockwise=True, showMarker=False, glow=True, glowBrightness=0.5, bgPortion=0.997, idx=0, colorBg=Color(eveColor.CRYO_BLUE).SetBrightness(0.2).GetRGBA(), useMiddleGauge=True) 255 self.icon = Sprite(parent=self, name='icon', align=uiconst.CENTER, texturePath=texturePath, state=uiconst.UI_DISABLED, width=ICON_SIZE, height=ICON_SIZE, outputMode=uiconst.OUTPUT_COLOR_AND_GLOW, glowBrightness=0.3, idx=1) 256 257 def _SetupBackground(self): 258 self.bgCont = Container(name='backgroundContainer', parent=self, align=uiconst.CENTER, bgTexturePath='res:/UI/Texture/classes/careerPortal/careerNodeHoverOff.png', bgOutputMode=uiconst.OUTPUT_COLOR_AND_GLOW, bgSpriteEffect=trinity.TR2_SFX_SOFTLIGHT, opacity=0.5) 259 self.bgCont._bgSprite.glowBrightness = 0.3 260 261 def ConstructLine(self, radius, lineWidth): 262 return DonutSegment(parent=self, align=uiconst.CENTER, lineWidth=lineWidth, radius=radius, isClockwise=True) 263 264 def ResizeComponents(self, nodeSize, animate): 265 if animate: 266 self._AnimateToNewSize(nodeSize) 267 else: 268 iconSize = nodeSize / 1.2 269 bgSizeWithPadding = nodeSize * 2.2 270 self.icon.SetSize(iconSize, iconSize) 271 self.bgCont.SetSize(bgSizeWithPadding, bgSizeWithPadding) 272 self.height = self.width = nodeSize 273 radius = nodeSize / 2 274 self.gauge.SetRadius(radius) 275 276 def _AnimateToNewSize(self, nodeSize): 277 animations.MorphScalar(self, 'height', self.height, nodeSize, duration=LEVEL_ANIMATION_DURATION) 278 animations.MorphScalar(self, 'width', self.width, nodeSize, duration=LEVEL_ANIMATION_DURATION) 279 iconSize = nodeSize / 1.2 280 bgSizeWithPadding = nodeSize * 2.2 281 animations.MorphScalar(self.icon, 'height', self.icon.height, iconSize, duration=LEVEL_ANIMATION_DURATION) 282 animations.MorphScalar(self.icon, 'width', self.icon.width, iconSize, duration=LEVEL_ANIMATION_DURATION) 283 animations.MorphScalar(self.bgCont, 'height', self.bgCont.height, bgSizeWithPadding, duration=LEVEL_ANIMATION_DURATION) 284 animations.MorphScalar(self.bgCont, 'width', self.bgCont, bgSizeWithPadding, duration=LEVEL_ANIMATION_DURATION) 285 286 def SetGaugeValue(self, value, maxValue): 287 isGaugeFull = value >= maxValue 288 self.gauge.SetValueWithMiddleGauge(float(value) / float(maxValue), lingerDurationSeconds=1.0, callback=lambda : self.UpdateGaugeColor(isGaugeFull)) 289 290 def UpdateGaugeColor(self, full): 291 if full: 292 animations.MorphScalar(self.gauge.gauge, 'glowBrightness', startVal=self.gauge.glowBrightness, endVal=1.0, curveType=uiconst.ANIM_OVERSHOT5) 293 self.gauge.SetColor(eveColor.LEAFY_GREEN, eveColor.LEAFY_GREEN) 294 else: 295 self.gauge.SetColor(eveColor.CRYO_BLUE, eveColor.CRYO_BLUE) 296 297 def OnMouseEnter(self, *args): 298 animations.FadeTo(self.icon, self.icon.opacity, 1.4, duration=careerConst.HOVER_ANIMATION_DURATION) 299 animations.FadeIn(self.bgCont, endVal=1.0, duration=careerConst.HOVER_ANIMATION_DURATION) 300 301 def OnMouseExit(self, *args): 302 animations.FadeTo(self.icon, self.icon.opacity, 1.0, duration=careerConst.HOVER_ANIMATION_DURATION) 303 animations.FadeTo(self.bgCont, startVal=self.bgCont.opacity, endVal=0.5, duration=careerConst.HOVER_ANIMATION_DURATION) 304 305 306 class CareerNodeObject(object): 307 308 def __init__(self, careerPathID): 309 self.careerPathID = careerPathID 310 self._careerPathName = None 311 self.goal = get_career_goals_svc().get_goal_data_controller().get_career_path_goal(self.careerPathID) 312 313 @property 314 def iconTexturePath(self): 315 return careerConst.ICON_BY_CAREER_ID.get(self.careerPathID, '') 316 317 @property 318 def careerPathName(self): 319 if self._careerPathName is None: 320 careerInfo = careerpath.get_career_path(self.careerPathID) 321 self._careerPathName = GetByMessageID(careerInfo.nameID) 322 return self._careerPathName 323 324 def GetCareerPathPointsText(self): 325 currentPoints = self.goal.progress 326 maxPoints = self.goal.definition.target_value 327 return GetByLabel('UI/CareerPortal/CareerPointsNumFull', currentPoints=currentPoints, totalPoints=maxPoints) 328 329 def GetCareerPathProgress(self): 330 return (self.goal.progress, self.goal.definition.target_value)