circleView.py (8745B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\careerPortal\circleView\circleView.py 2 import math 3 import carbonui.const as uiconst 4 import telemetry 5 import trinity 6 from carbonui.primitives.container import Container 7 from carbonui.primitives.transform import Transform 8 from carbonui.primitives.vectorlinetrace import DashedCircle 9 from carbonui.uianimations import animations 10 from carbonui.uicore import uicore 11 from carbonui.util.dpi import ScaleDpi 12 from carbonui.util.various_unsorted import GetWindowAbove 13 from careergoals.client.signal import on_goal_completed 14 from eve.client.script.ui import eveColor 15 from eve.client.script.ui.shared.careerPortal import careerConst, cpSignals 16 from eve.client.script.ui.shared.careerPortal.circleView.innerCircles import InnerCircles 17 from eveexceptions import EatsExceptions 18 from eveui import Sprite 19 MAX_CIRCLE_WIDTH = 800 20 GLOW_WIDTH = 220 21 22 class CircleViewContainer(Container): 23 default_opacity = 0 24 default_height = 800 25 default_width = 800 26 default_align = uiconst.CENTER 27 28 def __init__(self, initialState, *args, **kwargs): 29 super(CircleViewContainer, self).__init__(*args, **kwargs) 30 self.initialState = initialState 31 self.nodesByID = {} 32 self.currentState = None 33 self.PrepareUI() 34 self.ConnectToSignals() 35 self.OnCareerWindowStateChanged(initialState) 36 37 def PrepareUI(self): 38 wnd = GetWindowAbove(self) 39 w, _ = wnd.GetAbsoluteSize() 40 self.width = self.height = min(MAX_CIRCLE_WIDTH, w / 2) 41 self.circleView = self.CreateCircleView(width=self.width, height=self.height) 42 43 def CreateCircleView(self, *args, **kwargs): 44 raise NotImplementedError 45 46 def Close(self): 47 self.DisconnectFromSignals() 48 super(CircleViewContainer, self).Close() 49 50 def GetSignals(self): 51 return [(careerConst.CAREER_WINDOW_STATE_SETTING.on_change, self.OnCareerWindowStateChanged), (cpSignals.on_cp_window_size_changed, self.on_parent_window_end_resize)] 52 53 def on_parent_window_end_resize(self, wnd): 54 w, _ = wnd.GetAbsoluteSize() 55 self.circleView.width = self.circleView.height = min(MAX_CIRCLE_WIDTH, w / 2) 56 self.width = self.height = min(MAX_CIRCLE_WIDTH, w / 2) 57 self.circleView.UpdateCircle() 58 59 def OnCareerWindowStateChanged(self, newState, animate = True): 60 raise NotImplementedError 61 62 @EatsExceptions('CircleView::ConnectToSignals') 63 def ConnectToSignals(self): 64 for signal, callback in self.GetSignals(): 65 signal.connect(callback) 66 67 @EatsExceptions('CircleView::DisconnectFromSignals') 68 def DisconnectFromSignals(self): 69 for signal, callback in self.GetSignals(): 70 signal.disconnect(callback) 71 72 73 class CircleView(Transform): 74 default_height = 800 75 default_width = 800 76 default_align = uiconst.CENTER 77 default_arc_opacity = 0.8 78 default_scalingCenter = (0.5, 0.5) 79 innerCircleTexturePath = 'res:/UI/Texture/classes/careerPortal/innerCircles.png' 80 81 def ApplyAttributes(self, attributes): 82 super(CircleView, self).ApplyAttributes(attributes) 83 self.nodes = [] 84 self._initialized = False 85 self.innerCircles = None 86 self.outerCircle = None 87 self.nodeParent = Container(name='nodeParent', parent=self, align=uiconst.TOALL) 88 self.ConstructInnerCircles() 89 self.fill = Sprite(name='fill', parent=self, align=uiconst.CENTER, texturePath='res:/UI/Texture/classes/careerPortal/circle_glow.png', state=uiconst.UI_DISABLED, outputMode=uiconst.OUTPUT_COLOR_AND_GLOW, opacity=0.5) 90 on_goal_completed.connect(self.OnGoalCompleted) 91 92 def Close(self): 93 on_goal_completed.disconnect(self.OnGoalCompleted) 94 super(CircleView, self).Close() 95 96 def OnGoalCompleted(self, *args): 97 if not self.nodes: 98 return 99 self.UpdateViewColor() 100 101 def ConstructOuterCircle(self, radius): 102 prevOpacity = 1 103 if self.outerCircle is not None: 104 prevOpacity = self.outerCircle.opacity 105 self.outerCircle.Close() 106 angle, dashSizeFactor, nodeCount = self.GetOuterCircleVariables(radius) 107 self.outerCircle = DashedCircle(name='OuterCircle', parent=self, align=uiconst.CENTER, range=math.radians(360), lineWidth=ScaleDpi(2), radius=radius, glowBrightness=0.5, startAngle=angle, dashCount=nodeCount, dashSizeFactor=dashSizeFactor, opacity=prevOpacity) 108 109 def GetOuterCircleVariables(self, radius): 110 nodeCount = self._GetNodesCount() 111 nodeSize = self.GetNodeSize() 112 angle = self._GetAngleOffset() + 0 / float(nodeCount) * 2 * math.pi 113 dashSizeFactor = (math.pi * (2 * radius) - nodeCount * nodeSize) / (nodeCount * nodeSize) 114 return (angle, dashSizeFactor, nodeCount) 115 116 def ConstructInnerCircles(self): 117 if self.innerCircles is not None: 118 self.innerCircles.Close() 119 self.innerCircles = InnerCircles(parent=self, align=uiconst.CENTER, texturePath=self.innerCircleTexturePath, spriteEffect=trinity.TR2_SFX_MODULATE, state=uiconst.UI_DISABLED) 120 121 def _GetViewColor(self): 122 if any((not node.IsCompleted() for node in self.nodes)): 123 return eveColor.WHITE 124 else: 125 return eveColor.LEAFY_GREEN 126 127 def Reset(self): 128 self.nodes = [] 129 self.nodeParent.Flush() 130 131 def AddNode(self, node): 132 self.nodes.append(node) 133 node.SetParent(self.nodeParent) 134 135 @telemetry.ZONE_METHOD 136 def UpdateCircle(self): 137 if not self.nodes: 138 return 139 size = self.width 140 nodeSize = self.GetNodeSize() 141 diameter = size - nodeSize 142 radius = diameter * 0.5 143 self.ConstructOuterCircle(radius) 144 self.UpdateCircleMask() 145 self.innerCircles.pos = (0, 146 0, 147 diameter - 10, 148 diameter - 10) 149 fillSize = diameter * 1.33 150 self.fill.SetSize(fillSize, fillSize) 151 self.UpdateViewColor() 152 self.AdjustNodes(size, radius) 153 154 def UpdateViewColor(self): 155 viewColor = eveColor.Color(self._GetViewColor()) 156 self.fill.color = viewColor.SetOpacity(self.fill.opacity).GetRGBA() 157 self.outerCircle.color = viewColor.SetOpacity(self.outerCircle.opacity).GetRGBA() 158 159 def UpdateCircleMask(self): 160 maskTexturePath = self._GetNodeMask() 161 self.innerCircles.SetSecondaryTexturePath(maskTexturePath) 162 self.innerCircles.scaleSecondary = self._GetInnerCircleScale() 163 164 def _GetNodeMask(self): 165 return 'res:/UI/Texture/classes/careerPortal/nodeMasks/%s_node_mask.png' % len(self.nodes) 166 167 def _GetInnerCircleScale(self): 168 if uicore.dpiScaling > 1.25: 169 return (0.94, 0.94) 170 return (0.91, 0.91) 171 172 @staticmethod 173 def _GetFillScale(): 174 scale = 900 / 730.0 175 return (scale, scale) 176 177 def OnAdjustSizeDone(self, radius): 178 self.radius = radius 179 180 @telemetry.ZONE_METHOD 181 def AdjustNodes(self, size, radius): 182 for i, nodeCont in enumerate(self.nodes): 183 self.AdjustNode(nodeCont, i, size, radius) 184 185 def AdjustNode(self, node, idx, size, radius, animate = False): 186 nodeSize = self.GetNodeSize() 187 left, top, angle = self._GetNodeContPositionFromSizeAndRadius(nodeSize, idx, radius) 188 node.ResizeComponents(nodeSize, left, top, angle, animate) 189 190 def _GetNodesCount(self): 191 return len(self.nodes) 192 193 def _GetNodeAngleMeasure(self, radius): 194 if radius <= 0: 195 return 0 196 else: 197 adjustment_radius = 0.5 * self.GetNodeSize() / radius 198 try: 199 node_angle_measure = 2.0 * math.asin(adjustment_radius) 200 except ValueError: 201 return 0 202 203 return node_angle_measure 204 205 def _GetArcAngleMeasure(self, nodeAngleMeasure): 206 count = float(self._GetNodesCount()) 207 if count > 0: 208 return (2 * math.pi - count * nodeAngleMeasure) / count 209 return 2 * math.pi 210 211 def _GetNodeContPositionFromSizeAndRadius(self, nodeSize, i, radius): 212 angle = self._GetAngleOffset() + i / float(self._GetNodesCount()) * 2 * math.pi 213 left = radius * math.cos(angle) + int(nodeSize / 2 - nodeSize / 2) 214 top = radius * math.sin(angle) + int(nodeSize / 2 - nodeSize / 2) 215 return (left, top, angle) 216 217 def _GetAngleOffset(self): 218 return -math.pi / 2 219 220 def GetNodeSize(self): 221 raise NotImplementedError 222 223 def SetArcOpacity(self, opacity, duration, animate = True): 224 if animate: 225 animations.FadeTo(self.outerCircle, self.outerCircle.opacity, opacity, duration=duration) 226 else: 227 self.outerCircle.opacity = opacity