eveSpinWheelPicker.py (10721B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\control\eveSpinWheelPicker.py 2 import math 3 import uthread 4 import blue 5 from carbon.common.script.util import timerstuff 6 from carbonui import uiconst 7 from carbonui.primitives.container import Container 8 from carbonui.primitives.fill import Fill 9 from carbonui.primitives.sprite import Sprite 10 from carbonui.primitives.transform import Transform 11 from carbonui.uicore import uicore 12 13 class SpinWheelPicker(Container): 14 default_align = uiconst.CENTER 15 default_left = 0 16 default_top = 0 17 default_width = 256 18 default_height = 256 19 default_name = 'SpinWheel' 20 default_state = uiconst.UI_NORMAL 21 default_pickRadius = 66 22 TEXTURESIZE = 162 23 MARKERTFSIZE = 98 24 SPINRATIO = 1.0 25 26 def ApplyAttributes(self, attributes): 27 Container.ApplyAttributes(self, attributes) 28 self._spinning = False 29 self._lastAngle = 0.0 30 self._tickGap = 0.0 31 self._options = None 32 self._value = None 33 self._lastRotationDelta = None 34 self._didSpin = False 35 self._wheelbuffer = 0 36 self._wheeling = False 37 for each in uicore.layer.main.children[:]: 38 if each.name == self.default_name: 39 each.Close() 40 41 if attributes.parent is None: 42 uicore.layer.main.children.append(self) 43 transform = Transform(parent=self, pos=(0, 44 0, 45 self.TEXTURESIZE, 46 self.TEXTURESIZE), align=uiconst.CENTER, state=uiconst.UI_DISABLED, name='mainTransform') 47 self.sr.mainTransform = transform 48 sprite = Sprite(parent=transform, align=uiconst.TOALL, texturePath='res:/UI/Texture/spinWheelPicker_main.dds') 49 self.sr.mainTransform = transform 50 self.sr.marker = Fill(parent=self, align=uiconst.CENTER, pos=(0, -64, 2, 16), color=(1.0, 1.0, 1.0, 1.0), idx=0) 51 options = attributes.Get('options', [(True, None)] + [ (False, i) for i in xrange(60) ]) 52 activeOptionIndex = attributes.Get('activeOptionIndex', 4) 53 self.LoadOptions(options, activeOptionIndex) 54 setvalueCallback = attributes.Get('OnSetValue', None) 55 if setvalueCallback: 56 self.OnSetValue = setvalueCallback 57 58 def LoadOptions(self, options, activeOptionIndex = 0): 59 for each in self.sr.mainTransform.children[:]: 60 if each.name == 'tick': 61 each.Close() 62 63 self._options = options 64 step = math.pi * 2 / len(self._options) 65 self._tickGap = step 66 angle = 0.0 67 activeRotation = 0.0 68 for i, each in enumerate(self._options): 69 isZero, args = each 70 markerTransform = Transform(parent=self.sr.mainTransform, pos=(0, 71 0, 72 self.MARKERTFSIZE, 73 self.MARKERTFSIZE), align=uiconst.CENTER, state=uiconst.UI_DISABLED, name='tick', rotation=angle + math.pi * 0.25, idx=0) 74 sprite = Sprite(parent=markerTransform, align=uiconst.TOPRIGHT, pos=(0, 0, 16, 16), color=(0.0, 0.0, 0.0, 1.0), texturePath='res:/UI/Texture/spinWheelPicker_marker2.dds') 75 if i == activeOptionIndex: 76 activeRotation = angle 77 angle += step 78 if isZero: 79 sprite.texture.resPath = 'res:/UI/Texture/CharacterCreation/ovalSlider_Filler.dds' 80 sprite.SetRGB(1.0, 0.0, 0.0) 81 sprite.top = 2 82 sprite.left = 2 83 84 if activeRotation: 85 86 def UpdateMarker(_None, newAngle): 87 self.sr.mainTransform.SetRotation(newAngle) 88 89 currentAngle = self.sr.mainTransform.GetRotation() 90 uicore.effect.MorphUIMassSpringDamper(None, None, activeRotation, newthread=False, frequency=15.0, dampRatio=0.5, callback=UpdateMarker, initVal=currentAngle) 91 self.SettleOnTick() 92 93 def SettleOnTick(self): 94 sm.StartService('audio').SendUIEvent(unicode('ui_icc_circular_slider_item_selected_play')) 95 currentAngle = self.sr.mainTransform.GetRotation() 96 97 def UpdateMarker(_None, newAngle): 98 if self.destroyed: 99 return 100 self.sr.mainTransform.SetRotation(newAngle) 101 102 step = self._tickGap 103 angle = 0.0 104 value = None 105 for isZero, value in self._options: 106 if angle - step / 2 < 0.0 and angle - step / 2 + math.pi * 2 <= currentAngle <= angle + step / 2 + math.pi * 2: 107 break 108 if angle - step / 2 <= currentAngle <= angle + step / 2: 109 break 110 angle += step 111 112 if abs(angle - currentAngle) > step: 113 angle += math.pi * 2 114 uicore.effect.MorphUIMassSpringDamper(None, None, angle, frequency=15.0, dampRatio=0.5, callback=UpdateMarker, initVal=currentAngle) 115 self.SetValue(value) 116 117 def GetValue(self): 118 return self._value 119 120 def SetValue(self, value): 121 self._value = value 122 self.OnSetValue(self, value) 123 124 def OnSetValue(self, control, value): 125 pass 126 127 def RotationTick(self, *args): 128 if self._spinning: 129 newAngle = self.GetRotationAngleFromCenter() 130 delta = self._lastAngle - newAngle 131 if delta: 132 self._didSpin = True 133 if abs(delta) > math.pi: 134 if delta < 0.0: 135 delta += math.pi * 2 136 else: 137 delta -= math.pi * 2 138 self.sr.mainTransform.Rotate(delta * self.SPINRATIO) 139 self._lastRotationDelta = delta * self.SPINRATIO 140 self._lastAngle = newAngle 141 else: 142 self.sr._rotationTimer = None 143 144 def OnClick(self, *args): 145 if self._didSpin: 146 return 147 mouseAngle = self.GetRotationAngleFromCenter() 148 currentAngle = self.sr.mainTransform.GetRotation() 149 newAngle = mouseAngle + currentAngle - math.pi * 0.5 150 newAngle = self.sr.mainTransform.ClampRotation(newAngle) 151 self.sr.mainTransform.SetRotation(newAngle) 152 153 def UpdateMarker(_None, _newAngle): 154 self.sr.mainTransform.SetRotation(_newAngle) 155 156 step = self._tickGap 157 angle = 0.0 158 value = None 159 for isZero, value in self._options: 160 if angle - step / 2 < 0.0 and angle - step / 2 + math.pi * 2 <= newAngle <= angle + step / 2 + math.pi * 2: 161 break 162 if angle - step / 2 <= newAngle <= angle + step / 2: 163 break 164 angle += step 165 166 diff = abs(angle - currentAngle) 167 if diff > math.pi: 168 if angle > currentAngle: 169 angle -= math.pi * 2 170 else: 171 angle += math.pi * 2 172 uicore.effect.MorphUIMassSpringDamper(None, None, angle, frequency=15.0, dampRatio=0.5, callback=UpdateMarker, initVal=currentAngle) 173 self.SetValue(value) 174 175 def OnMouseWheel(self, *args): 176 if getattr(self, '_wheeling', False): 177 self._wheelbuffer += uicore.uilib.dz 178 else: 179 uthread.new(self.MouseWheelThread, uicore.uilib.dz) 180 181 def MouseWheelThread(self, delta): 182 self._wheeling = True 183 blue.pyos.synchro.SleepWallclock(100) 184 if self._wheelbuffer: 185 delta += self._wheelbuffer 186 self._wheelbuffer = 0 187 sm.StartService('audio').SendUIEvent(unicode('ui_icc_circular_slider_item_selected_play')) 188 currentAngle = self.sr.mainTransform.GetRotation() 189 190 def UpdateMarker(_None, newAngle): 191 self.sr.mainTransform.SetRotation(newAngle) 192 193 steps = abs(delta / 120) 194 if delta > 0: 195 newAngle = currentAngle + self._tickGap * steps 196 else: 197 newAngle = currentAngle - self._tickGap * steps 198 if newAngle < 0.0: 199 newAngle += math.pi * 2 200 elif newAngle > math.pi * 2: 201 newAngle -= math.pi * 2 202 step = self._tickGap 203 angle = 0.0 204 value = None 205 for isZero, value in self._options: 206 if angle - step / 2 < 0.0 and angle - step / 2 + math.pi * 2 <= newAngle <= angle + step / 2 + math.pi * 2: 207 break 208 if angle - step / 2 <= newAngle <= angle + step / 2: 209 break 210 angle += step 211 212 diff = abs(angle - currentAngle) 213 if diff > math.pi: 214 if angle > currentAngle: 215 angle -= math.pi * 2 216 else: 217 angle += math.pi * 2 218 uicore.effect.MorphUIMassSpringDamper(None, None, angle, newthread=0, frequency=15.0, dampRatio=0.5, callback=UpdateMarker, initVal=currentAngle) 219 self._wheeling = False 220 if self._wheelbuffer: 221 buff = self._wheelbuffer 222 self._wheelbuffer = 0 223 return self.MouseWheelThread(buff) 224 self.SetValue(value) 225 226 def OnMouseDown(self, button, *args): 227 if button == uiconst.MOUSELEFT: 228 sm.StartService('audio').SendUIEvent(unicode('ui_icc_inventory_item_mouse_over_loop_play')) 229 self._lastAngle = self.GetRotationAngleFromCenter() 230 self._spinning = True 231 self._didSpin = False 232 self.sr._rotationTimer = timerstuff.AutoTimer(10, self.RotationTick) 233 234 def OnMouseUp(self, button, *args): 235 if button == uiconst.MOUSELEFT: 236 sm.StartService('audio').SendUIEvent(unicode('ui_icc_inventory_item_mouse_over_loop_stop')) 237 self._spinning = False 238 if self._didSpin: 239 uthread.new(self.Throw) 240 241 def Throw(self, *args): 242 newAngle = self.GetRotationAngleFromCenter() 243 delta = self._lastRotationDelta 244 lenOptions = len(self._options) 245 if delta: 246 distance = delta 247 steps = 20 248 maxExp = math.exp(steps / 10.0) 249 for i in xrange(1, steps + 1): 250 iExp = math.exp(i / 10.0) 251 _delta = distance - distance * (iExp / maxExp) 252 self.sr.mainTransform.Rotate(_delta) 253 blue.pyos.synchro.SleepWallclock(10) 254 if self.destroyed or self._spinning: 255 return 256 257 self.SettleOnTick() 258 259 def GetRotationAngleFromCenter(self): 260 x, y = uicore.uilib.x, uicore.uilib.y 261 l, t, w, h = self.GetAbsolute() 262 px, py = l + w / 2, t + h / 2 263 tn = (abs(x - px) or 1e-07) / float(abs(y - py) or 1e-07) 264 if y < py: 265 if x > px: 266 rot = math.pi * 0.5 + math.atan(tn) 267 else: 268 rot = math.pi * 0.5 - math.atan(tn) 269 elif x > px: 270 rot = math.pi * 1.5 - math.atan(tn) 271 else: 272 rot = math.pi * 1.5 + math.atan(tn) 273 return self.sr.mainTransform.ClampRotation(rot)