countdownTimer.py (11253B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\control\countdownTimer.py 2 from math import pi 3 from carbonui.primitives import container 4 from carbonui.primitives import transform 5 from carbonui.primitives import sprite 6 from carbonui import const as uiconst 7 import uthread 8 import blue 9 import trinity 10 from carbonui.primitives.transform import Transform 11 from carbonui.uicore import uicore 12 ALPHA_EMPTY = 0.2 13 BLINK_BEFORE_DONE_TIME = const.SEC * 5 14 REWIND_SPEED = 500 15 TEXT_OFFSET = -17 16 TIMER_RUNNING_OUT_NO_ANIMATION = 1 17 TIMER_RUNNING_OUT_BLINK_ALL = 2 18 TIMER_RUNNING_OUT_BLINK_ICON = 4 19 20 def FormatCounterTime(timeLeft): 21 timeLeft = max(0, timeLeft / const.SEC) 22 minutes, seconds = divmod(timeLeft, 60) 23 hours, minutes = divmod(minutes, 60) 24 if hours > 0: 25 return '%02d:%02d:%02d' % (hours, minutes, seconds) 26 else: 27 return '%02d:%02d' % (minutes, seconds) 28 29 30 class CountdownTimer(Transform): 31 default_width = 32 32 default_height = 32 33 default_align = uiconst.CENTER 34 default_state = uiconst.UI_DISABLED 35 default_scalingCenter = (0.5, 0.5) 36 sound_loop_play_event = None 37 sound_loop_stop_event = None 38 39 def ApplyAttributes(self, attributes): 40 Transform.ApplyAttributes(self, attributes) 41 self.SetupVariables(attributes) 42 self.CreateMainContentLayout() 43 self.CreateIconLayout(attributes) 44 self.CreateTimerCycleLayout() 45 self.SetTimerColor(self.color) 46 self.SetExpiryTime(None, 0.0) 47 self.PlayEntryAnimation() 48 49 def SetupVariables(self, attributes): 50 self.countsDown = attributes.Get('countsDown', False) 51 self.GetTime = attributes.Get('timerFunc', blue.os.GetSimTime) 52 self.color = attributes.Get('color', (1, 1, 1, 1)) 53 self.maxTimeout = attributes.maxTimeout 54 self.resetAudioEvent = attributes.Get('resetAudioEvent', None) 55 self.endingAudioEvent = attributes.Get('endingAudioEvent', None) 56 self.timerRunningOutAnimation = attributes.Get('timerRunningOutAnimation', TIMER_RUNNING_OUT_BLINK_ICON) 57 self.icon = None 58 self.iconBlink = None 59 self.rewind = False 60 self.paused = None 61 self.ratio = 1.0 62 self.animationThread = None 63 self.activeAnimationCurves = None 64 65 def CreateMainContentLayout(self): 66 self.content = transform.Transform(parent=self, name='content', align=uiconst.CENTER, pos=(0, 0, 32, 32), state=uiconst.UI_NORMAL) 67 self.content.OnMouseEnter = self.OnMouseEnter 68 69 def CreateIconLayout(self, attributes): 70 if attributes.icon: 71 self.iconTransform = transform.Transform(parent=self.content, name='iconTransform', align=uiconst.CENTER, width=16, height=16, state=uiconst.UI_DISABLED) 72 self.icon = sprite.Sprite(name='icon', parent=self.iconTransform, pos=(0, 0, 16, 16), texturePath=attributes.icon, state=uiconst.UI_DISABLED, align=uiconst.CENTER) 73 self.iconTransform.scalingCenter = (0.5, 0.5) 74 else: 75 self.icon = None 76 77 def CreateTimerCycleLayout(self): 78 self.circleSprite = sprite.Sprite(name='icon', parent=self.content, pos=(0, 0, 32, 32), texturePath='res:/UI/Texture/Crimewatch/Crimewatch_TimerCircle.png', state=uiconst.UI_DISABLED, align=uiconst.CENTER, opacity=ALPHA_EMPTY) 79 self.halfCircleSprite = sprite.Sprite(name='half_circle', parent=self.content, width=32, height=32, rotation=0 if self.countsDown else pi, texturePath='res:/UI/Texture/Crimewatch/Crimewatch_TimerHalfCircle.png', state=uiconst.UI_DISABLED) 80 self.clipContainer = container.Container(name='clipper', parent=self.content, width=16, align=uiconst.TOLEFT, clipChildren=True, state=uiconst.UI_DISABLED) 81 self.cycleContainer = transform.Transform(name='cycle_container', parent=self.clipContainer, width=32, height=32) 82 self.cycleSprite = sprite.Sprite(name='cycle_half_circle', parent=self.cycleContainer, width=32, height=32, rotation=pi if self.countsDown else 0, texturePath='res:/UI/Texture/Crimewatch/Crimewatch_TimerHalfCircle.png', state=uiconst.UI_DISABLED) 83 self.pointerContainer = transform.Transform(name='pointer_container', parent=self.content, width=32, height=32, idx=0) 84 self.pointerClipper = container.Container(parent=self.pointerContainer, pos=(9, -10, 15, 13), clipChildren=True, align=uiconst.TOPLEFT, state=uiconst.UI_DISABLED) 85 self.pointerSprite = sprite.Sprite(name='cycle_pointer', parent=self.pointerClipper, pos=(0, 0, 15, 19), texturePath='res:/UI/Texture/Crimewatch/Crimewatch_TimerPoint_WithShadow.png', align=uiconst.TOPLEFT, state=uiconst.UI_DISABLED) 86 87 def PlayEntryAnimation(self): 88 uicore.animations.FadeIn(self, duration=0.25, endVal=1.0) 89 if self.icon: 90 uicore.animations.Tr2DScaleTo(self.iconTransform, startScale=(0.8, 0.8), endScale=(1.0, 1.0), duration=0.75, curveType=uiconst.ANIM_OVERSHOT) 91 92 def SetTimerColor(self, color): 93 r, g, b, a = color 94 self.circleSprite.SetRGBA(r, g, b, 0.5) 95 self.halfCircleSprite.SetRGBA(r, g, b, a) 96 self.cycleSprite.SetRGBA(r, g, b, a) 97 self.pointerSprite.SetRGBA(r, g, b, a) 98 if self.icon: 99 self.icon.SetRGBA(r, g, b, a) 100 101 def SetRatio(self, ratio): 102 self.ratio = min(1.0, max(0.0, ratio)) 103 if self.ratio > 0.5: 104 self.clipContainer.SetAlign(uiconst.TORIGHT) 105 self.cycleContainer.left = -16 106 self.halfCircleSprite.display = True if self.countsDown else False 107 else: 108 self.clipContainer.SetAlign(uiconst.TOLEFT) 109 self.cycleContainer.left = 0 110 self.halfCircleSprite.display = False if self.countsDown else True 111 rotation = 2 * pi * self.ratio 112 self.pointerContainer.rotation = rotation 113 self.cycleContainer.rotation = rotation 114 115 def SetExpiryTime(self, timerExpiryTime, timerDuration, timerPaused = None, doAlert = False): 116 self.Reset(timerExpiryTime, timerDuration, doAlert) 117 self.paused = timerPaused 118 if timerExpiryTime is None: 119 self.PlayActiveAnimation() 120 else: 121 self.animationThread = uthread.new(self.Animate_Thread, timerExpiryTime, timerDuration) 122 123 def GetCurrentTime(self): 124 return self.paused or self.GetTime() 125 126 def Reset(self, resetTo, timerDuration, doAlert): 127 if self.animationThread is not None: 128 self.animationThread.kill() 129 uthread.new(self.Rewind_Thread, resetTo, timerDuration, doAlert) 130 131 def Rewind_Thread(self, resetTo, timerDuration, doAlert): 132 if self.rewind: 133 return 134 if doAlert and self.resetAudioEvent: 135 sm.GetService('audio').SendUIEvent(self.resetAudioEvent) 136 self.rewind = True 137 ratio = self.ratio 138 startTime = self.GetCurrentTime() 139 distance = 1 - ratio 140 cycleSpeed = float(distance * REWIND_SPEED) 141 while not self.destroyed and cycleSpeed > 0: 142 if resetTo is not None: 143 resetRatio = self.GetRatio(resetTo - self.GetCurrentTime(), timerDuration) 144 if self.ratio >= resetRatio: 145 break 146 elapsedTime = blue.os.TimeDiffInMs(startTime, self.GetCurrentTime()) 147 toAdd = elapsedTime / cycleSpeed 148 self.SetRatio(ratio + toAdd) 149 blue.pyos.synchro.SleepWallclock(25) 150 151 self.rewind = False 152 153 def FlipFlop(self, sprite, duration = 1.0, startValue = 0.0, endValue = 1.0, loops = 5): 154 curve = trinity.Tr2CurveScalar() 155 curve.AddKey(0, startValue, trinity.Tr2CurveInterpolation.LINEAR) 156 curve.AddKey(0.01 * duration, endValue, trinity.Tr2CurveInterpolation.LINEAR) 157 curve.AddKey(0.5 * duration, endValue, trinity.Tr2CurveInterpolation.LINEAR) 158 curve.AddKey(0.51 * duration, startValue, trinity.Tr2CurveInterpolation.LINEAR) 159 curve.AddKey(duration, startValue, trinity.Tr2CurveInterpolation.LINEAR) 160 return uicore.animations.Play(curve, sprite, 'opacity', loops, None, False) 161 162 def GetRatio(self, timeLeft, duration): 163 ratio = timeLeft / float(duration) 164 ratio = min(1.0, max(0.0, ratio)) 165 return ratio 166 167 def Animate_Thread(self, expiryTime, duration): 168 self.StopActiveAnimation() 169 self.StartSoundLoop() 170 while not self.destroyed and expiryTime is not None: 171 if not self.rewind: 172 if self.ratio <= 0.0: 173 break 174 timeLeft = expiryTime - self.GetCurrentTime() 175 ratio = self.GetRatio(timeLeft, duration) 176 self.SetRatio(ratio) 177 if timeLeft < BLINK_BEFORE_DONE_TIME: 178 self.PlayTimerRunningOutAnimation() 179 else: 180 self.StopTimerRunningOutAnimation() 181 blue.pyos.synchro.SleepWallclock(50) 182 183 self.StopActiveAnimation() 184 self.StopSoundLoop() 185 186 def PlayTimerRunningOutAnimation(self): 187 if self.timerRunningOutAnimation == TIMER_RUNNING_OUT_NO_ANIMATION: 188 return 189 if self.iconBlink is not None: 190 return 191 if self.timerRunningOutAnimation == TIMER_RUNNING_OUT_BLINK_ICON: 192 animationSprite = self.icon 193 else: 194 animationSprite = self.content 195 self.iconBlink = self.FlipFlop(animationSprite, startValue=1.0, endValue=0.0) 196 if self.endingAudioEvent: 197 sm.GetService('audio').SendUIEvent(self.endingAudioEvent) 198 199 def StopTimerRunningOutAnimation(self): 200 if self.iconBlink is not None: 201 self.iconBlink.Stop() 202 self.iconBlink = None 203 204 def EndAnimation(self): 205 self.SetRatio(0.0) 206 uicore.animations.FadeOut(self, duration=0.5, timeOffset=0.5) 207 uicore.animations.MoveOutBottom(self.pointerSprite, amount=9, duration=0.3, sleep=False) 208 self.content.scalingCenter = (0.5, 0.5) 209 uicore.animations.Tr2DScaleTo(self.content, startScale=(1.0, 1.0), endScale=(0.8, 0.8), duration=0.4, sleep=True) 210 211 def PlayActiveAnimation(self): 212 self.activeAnimationCurves = ((self.halfCircleSprite, self.FlipFlop(self.halfCircleSprite, startValue=1.0, endValue=0.75, duration=1.0, loops=uiconst.ANIM_REPEAT)), (self.cycleSprite, self.FlipFlop(self.cycleSprite, startValue=1.0, endValue=0.75, duration=1.0, loops=uiconst.ANIM_REPEAT)), (self.pointerSprite, self.FlipFlop(self.pointerSprite, startValue=1.0, endValue=0.75, duration=1.0, loops=uiconst.ANIM_REPEAT))) 213 214 def StopActiveAnimation(self): 215 if self.activeAnimationCurves is not None: 216 for sprite, animationCurve in self.activeAnimationCurves: 217 animationCurve.Stop() 218 sprite.opacity = 1.0 219 220 self.activeAnimationCurves = None 221 222 def SetSoundLoop(self, playEvent, stopEvent): 223 self.sound_loop_play_event = playEvent 224 self.sound_loop_stop_event = stopEvent 225 226 def StartSoundLoop(self): 227 if self.sound_loop_play_event is not None: 228 sm.GetService('audio').SendUIEvent(self.sound_loop_play_event) 229 230 def StopSoundLoop(self): 231 if self.sound_loop_stop_event is not None: 232 sm.GetService('audio').SendUIEvent(self.sound_loop_stop_event)