uiComponents.py (7942B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\util\uiComponents.py 2 import functools 3 import math 4 import signals 5 import carbonui.const as uiconst 6 from carbonui.primitives.fill import Fill 7 from carbonui.primitives.gradientSprite import GradientSprite 8 import logging 9 import uthread 10 from carbonui.uicore import uicore 11 from carbonui.util.various_unsorted import GetWindowAbove 12 logger = logging.getLogger(__name__) 13 14 def Component(component): 15 16 def AttachComponent(cls): 17 if not hasattr(cls, '_attached_ui_components'): 18 setattr(cls, '_attached_ui_components', []) 19 cls._attached_ui_components.append(component) 20 for methodName in component.__observed_methods__: 21 method = getattr(cls, methodName, None) 22 if method is None: 23 continue 24 signal = getattr(method, '_component_method_observers', None) 25 if signal is None: 26 signal = signals.Signal() 27 28 def GetWrapper(_method, _signal): 29 30 @functools.wraps(method) 31 def Wrapper(*args, **kwargs): 32 try: 33 result = _method(*args, **kwargs) 34 except: 35 logger.exception('Method %s raised an exception before signal could emit', methodName) 36 raise 37 38 try: 39 _signal(*args, **kwargs) 40 except Exception: 41 logger.exception('Failed while notifying observers for method %s', methodName) 42 43 return result 44 45 return Wrapper 46 47 wrapper = GetWrapper(method, signal) 48 setattr(wrapper, '_component_method_observers', signal) 49 setattr(cls, methodName, wrapper) 50 signal.connect(getattr(component, methodName)) 51 52 return cls 53 54 return AttachComponent 55 56 57 THREADS_BY_KEY = {} 58 59 def RunThreadOnce(threadKey): 60 61 def Wrapper(func): 62 63 @functools.wraps(func) 64 def RunThread(*args, **kwargs): 65 if threadKey not in THREADS_BY_KEY: 66 THREADS_BY_KEY[threadKey] = uthread.new(ExecuteAndRelease, func, *args, **kwargs) 67 68 return RunThread 69 70 def ExecuteAndRelease(func, *args, **kwargs): 71 try: 72 func(*args, **kwargs) 73 finally: 74 del THREADS_BY_KEY[threadKey] 75 76 return Wrapper 77 78 79 class ButtonEffect: 80 __observed_methods__ = ['ApplyAttributes', 81 'OnMouseEnter', 82 'OnMouseExit', 83 'OnMouseUp', 84 'OnMouseDown', 85 'OnClick'] 86 isToggleButton = False 87 isRadioButton = False 88 89 def __init__(self, opacityIdle = 0.0, opacityHover = 0.5, opacityMouseDown = 0.85, idx = 0, bgElementFunc = None, audioOnEntry = None, audioOnClick = None, exitDuration = 0.3): 90 self.opacityIdle = opacityIdle 91 self.opacityHover = opacityHover 92 self.opacityMouseDown = opacityMouseDown 93 self.bgElementFunc = bgElementFunc 94 self.audioOnEntry = audioOnEntry 95 self.audioOnClick = audioOnClick 96 self.idx = idx 97 self.exitDuration = exitDuration 98 99 def ApplyAttributes(self, _self, attributes, *args): 100 if self.bgElementFunc: 101 _self._buttonEffect_bgElement = self.bgElementFunc(_self, attributes) 102 else: 103 _self._buttonEffect_bgElement = GradientSprite(name='hoverGradient', bgParent=_self, rotation=-math.pi / 2, rgbData=[(0, (1.0, 1.0, 1.0))], alphaData=[(0, 0.5), (0.3, 0.2), (0.6, 0.08)], idx=self.idx) 104 _self._buttonEffect_bgElement.opacity = self.opacityIdle 105 if not hasattr(_self, 'disabled'): 106 setattr(_self, 'disabled', attributes.disabled or False) 107 if self.isToggleButton: 108 setattr(_self, 'isActive', attributes.isActive or False) 109 if _self.isActive: 110 _self._buttonEffect_bgElement.opacity = self.opacityMouseDown 111 112 def SetActive(isActive): 113 _self.isActive = isActive 114 if _self.isActive: 115 uicore.animations.FadeTo(_self._buttonEffect_bgElement, _self._buttonEffect_bgElement.opacity, self.opacityMouseDown, duration=0.1) 116 else: 117 uicore.animations.FadeTo(_self._buttonEffect_bgElement, _self._buttonEffect_bgElement.opacity, self.opacityIdle, duration=self.exitDuration) 118 onActiveStateChange = getattr(_self, 'OnActiveStateChange', None) 119 if onActiveStateChange is not None: 120 onActiveStateChange() 121 122 _self.SetActive = SetActive 123 124 def OnMouseEnter(self, _self, *args): 125 if _self.disabled: 126 return 127 if not self.IsActiveToggle(_self): 128 uicore.animations.FadeTo(_self._buttonEffect_bgElement, _self._buttonEffect_bgElement.opacity, self.opacityHover, duration=0.1) 129 if self.audioOnEntry: 130 sm.GetService('audio').SendUIEvent(self.audioOnEntry) 131 132 def OnMouseExit(self, _self, *args): 133 if not (self.isToggleButton and _self.isActive): 134 uicore.animations.FadeTo(_self._buttonEffect_bgElement, _self._buttonEffect_bgElement.opacity, self.opacityIdle, duration=0.3) 135 136 def OnMouseDown(self, _self, *args): 137 if _self.disabled: 138 return 139 if self.IsActiveToggle(_self): 140 uicore.animations.FadeTo(_self._buttonEffect_bgElement, _self._buttonEffect_bgElement.opacity, self.opacityMouseDown, duration=0.1) 141 142 def OnMouseUp(self, _self, *args): 143 if _self.disabled: 144 return 145 if self.IsActiveToggle(_self): 146 return 147 uicore.animations.FadeTo(_self._buttonEffect_bgElement, _self._buttonEffect_bgElement.opacity, self.opacityHover, duration=0.2) 148 149 def OnClick(self, _self, *args): 150 if _self.disabled: 151 return 152 self.Toggle(_self) 153 if not self.IsActiveToggle(_self): 154 uicore.animations.FadeTo(_self._buttonEffect_bgElement, _self._buttonEffect_bgElement.opacity, self.opacityMouseDown, duration=self.exitDuration) 155 if self.audioOnClick: 156 sm.GetService('audio').SendUIEvent(self.audioOnClick) 157 158 def IsActiveToggle(self, _self): 159 return self.isToggleButton and _self.isActive 160 161 def Toggle(self, _self): 162 if self.isRadioButton: 163 _self.SetActive(True) 164 elif self.isToggleButton: 165 _self.SetActive(not _self.isActive) 166 167 168 class ToggleButtonEffect(ButtonEffect): 169 isToggleButton = True 170 171 172 class RadioButtonEffect(ButtonEffect): 173 isToggleButton = True 174 isRadioButton = True 175 176 177 class HoverEffect: 178 __observed_methods__ = ['ApplyAttributes', 179 'OnMouseEnter', 180 'OnMouseExit', 181 'OnClick'] 182 183 def __init__(self, padding = (1, 1, 1, 1), color = (1.0, 1.0, 1.0, 0.25), audioOnEntry = None, audioOnClick = None, bgElementFunc = None): 184 self.padding = padding 185 self.color = color 186 self.audioOnEntry = audioOnEntry 187 self.audioOnClick = audioOnClick 188 self.bgElementFunc = bgElementFunc 189 190 def _GetHoverElement(self, _self): 191 return getattr(_self, '_hoverEffect_bgFill', None) 192 193 def ApplyAttributes(self, _self, *args): 194 setattr(_self, '_hoverEffect_bgFill', Fill(bgParent=_self, padding=self.padding, color=self.color, state=uiconst.UI_HIDDEN)) 195 196 def OnMouseEnter(self, _self, *args): 197 fill = self._GetHoverElement(_self) 198 if fill is None: 199 return 200 fill.state = uiconst.UI_NORMAL 201 if self.audioOnEntry: 202 sm.GetService('audio').SendUIEvent(self.audioOnEntry) 203 204 def OnMouseExit(self, _self, *args): 205 fill = self._GetHoverElement(_self) 206 if fill: 207 fill.state = uiconst.UI_HIDDEN 208 209 def OnClick(self, _self, *args): 210 if self.audioOnClick: 211 sm.GetService('audio').SendUIEvent(self.audioOnClick)