resizer.py (11828B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\carbonui\window\resizer.py 2 import math 3 from carbonui import uiconst 4 from carbonui.primitives.container import Container 5 from carbonui.primitives.sprite import Sprite 6 from carbonui.primitives.stretchspritehorizontal import StretchSpriteHorizontal 7 from carbonui.primitives.stretchspritevertical import StretchSpriteVertical 8 from carbonui.uianimations import animations 9 from eve.client.script.ui import eveThemeColor 10 11 class Side(object): 12 LEFT = 1 13 TOP = 2 14 RIGHT = 3 15 BOTTOM = 4 16 _ALL = (LEFT, 17 TOP, 18 RIGHT, 19 BOTTOM) 20 21 @classmethod 22 def iter(cls): 23 return iter(cls._ALL) 24 25 26 class Resizer(Container): 27 DEFAULT_INNER_PADDING = (0, 0, 0, 0) 28 29 def __init__(self, inner_padding = None, locked_sides = None, on_end_scale = None, on_start_scale = None, **kwargs): 30 self._inner_padding = sanitize_padding(inner_padding, default=self.DEFAULT_INNER_PADDING) 31 self._handles = [] 32 self._locked_sides = set(locked_sides or ()) 33 self._on_end_scale = on_end_scale 34 self._on_start_scale = on_start_scale 35 super(Resizer, self).__init__(**kwargs) 36 self._create_handles() 37 38 @property 39 def inner_padding(self): 40 return self._inner_padding 41 42 @inner_padding.setter 43 def inner_padding(self, value): 44 value = sanitize_padding(value, default=self.DEFAULT_INNER_PADDING) 45 if self._inner_padding != value: 46 self._inner_padding = value 47 self._update_inner_padding() 48 49 @property 50 def locked_sides(self): 51 return frozenset(self._locked_sides) 52 53 @locked_sides.setter 54 def locked_sides(self, value): 55 new_locked_sides = set(value) 56 if self._locked_sides != new_locked_sides: 57 self._locked_sides = new_locked_sides 58 self._update_handle_locked_state() 59 60 def _create_handles(self): 61 for orientation in Orientation.iter(): 62 handle = ResizeHandle(parent=self, orientation=orientation, on_start_scale=lambda _handle: self._on_start_scale(Orientation.get_sides(_handle.orientation)), on_end_scale=lambda _handle: self._on_end_scale(Orientation.get_sides(_handle.orientation)), enabled=not self._is_orientation_locked(orientation), idx=0 if Orientation.is_corner(orientation) else -1) 63 self._handles.append(handle) 64 65 def _update_inner_padding(self): 66 for handle in self._handles: 67 handle.inner_padding = self._inner_padding 68 69 def _update_handle_locked_state(self): 70 for handle in self._handles: 71 handle.enabled = not self._is_orientation_locked(handle.orientation) 72 73 def _is_orientation_locked(self, orientation): 74 return any((side in self._locked_sides for side in Orientation.get_sides(orientation))) 75 76 77 def sanitize_padding(value, default): 78 if not value: 79 value = default 80 if isinstance(value, int): 81 value = (value,) * 4 82 return value 83 84 85 class Orientation(object): 86 LEFT = 1 87 TOP = 2 88 RIGHT = 3 89 BOTTOM = 4 90 TOP_LEFT = 5 91 TOP_RIGHT = 6 92 BOTTOM_RIGHT = 7 93 BOTTOM_LEFT = 8 94 _ALL = (LEFT, 95 TOP, 96 RIGHT, 97 BOTTOM, 98 TOP_LEFT, 99 TOP_RIGHT, 100 BOTTOM_RIGHT, 101 BOTTOM_LEFT) 102 _HORIZONTAL_ORIENTATIONS = {LEFT, 103 RIGHT, 104 TOP_LEFT, 105 TOP_RIGHT, 106 BOTTOM_LEFT, 107 BOTTOM_RIGHT} 108 _VERTICAL_ORIENTATIONS = {TOP, 109 BOTTOM, 110 TOP_LEFT, 111 TOP_RIGHT, 112 BOTTOM_LEFT, 113 BOTTOM_RIGHT} 114 _CORNER_ORIENTATIONS = {TOP_LEFT, 115 TOP_RIGHT, 116 BOTTOM_LEFT, 117 BOTTOM_RIGHT} 118 _SIDES_BY_ORIENTATION = {LEFT: (Side.LEFT,), 119 TOP: (Side.TOP,), 120 RIGHT: (Side.RIGHT,), 121 BOTTOM: (Side.BOTTOM,), 122 TOP_LEFT: (Side.TOP, Side.LEFT), 123 TOP_RIGHT: (Side.TOP, Side.RIGHT), 124 BOTTOM_RIGHT: (Side.BOTTOM, Side.RIGHT), 125 BOTTOM_LEFT: (Side.BOTTOM, Side.LEFT)} 126 127 @classmethod 128 def iter(cls): 129 return iter(cls._ALL) 130 131 @classmethod 132 def get_sides(cls, orientation): 133 return cls._SIDES_BY_ORIENTATION[orientation] 134 135 @classmethod 136 def is_corner(cls, orientation): 137 return orientation in cls._CORNER_ORIENTATIONS 138 139 @classmethod 140 def is_horizontal(cls, orientation): 141 return orientation in cls._HORIZONTAL_ORIENTATIONS 142 143 @classmethod 144 def is_vertical(cls, orientation): 145 return orientation in cls._VERTICAL_ORIENTATIONS 146 147 148 class ResizeHandle(Container): 149 ALIGN_BY_ORIENTATION = {Orientation.LEFT: uiconst.TOLEFT_NOPUSH, 150 Orientation.TOP: uiconst.TOTOP_NOPUSH, 151 Orientation.RIGHT: uiconst.TORIGHT_NOPUSH, 152 Orientation.BOTTOM: uiconst.TOBOTTOM_NOPUSH, 153 Orientation.TOP_LEFT: uiconst.TOPLEFT, 154 Orientation.TOP_RIGHT: uiconst.TOPRIGHT, 155 Orientation.BOTTOM_RIGHT: uiconst.BOTTOMRIGHT, 156 Orientation.BOTTOM_LEFT: uiconst.BOTTOMLEFT} 157 CURSOR_BY_ORIENTATION = {Orientation.LEFT: uiconst.UICURSOR_LEFT_RIGHT_DRAG, 158 Orientation.TOP: uiconst.UICURSOR_TOP_BOTTOM_DRAG, 159 Orientation.RIGHT: uiconst.UICURSOR_LEFT_RIGHT_DRAG, 160 Orientation.BOTTOM: uiconst.UICURSOR_TOP_BOTTOM_DRAG, 161 Orientation.TOP_LEFT: uiconst.UICURSOR_TOP_LEFT_BOTTOM_RIGHT_DRAG, 162 Orientation.TOP_RIGHT: uiconst.UICURSOR_TOP_RIGHT_BOTTOM_LEFT_DRAG, 163 Orientation.BOTTOM_RIGHT: uiconst.UICURSOR_TOP_LEFT_BOTTOM_RIGHT_DRAG, 164 Orientation.BOTTOM_LEFT: uiconst.UICURSOR_TOP_RIGHT_BOTTOM_LEFT_DRAG} 165 SIZE_BY_ORIENTATION = {Orientation.LEFT: (8, 0), 166 Orientation.TOP: (0, 8), 167 Orientation.RIGHT: (8, 0), 168 Orientation.BOTTOM: (0, 8), 169 Orientation.TOP_LEFT: (8, 8), 170 Orientation.TOP_RIGHT: (8, 8), 171 Orientation.BOTTOM_RIGHT: (8, 8), 172 Orientation.BOTTOM_LEFT: (8, 8)} 173 HANDLE_ALIGN_BY_ORIENTATION = {Orientation.LEFT: uiconst.CENTERLEFT, 174 Orientation.TOP: uiconst.CENTERTOP, 175 Orientation.RIGHT: uiconst.CENTERRIGHT, 176 Orientation.BOTTOM: uiconst.CENTERBOTTOM, 177 Orientation.TOP_LEFT: uiconst.TOPLEFT, 178 Orientation.TOP_RIGHT: uiconst.TOPRIGHT, 179 Orientation.BOTTOM_RIGHT: uiconst.BOTTOMRIGHT, 180 Orientation.BOTTOM_LEFT: uiconst.BOTTOMLEFT} 181 TEXTURE_ROTATION_BY_ORIENTATION = {Orientation.LEFT: 0.0, 182 Orientation.TOP: 0.0, 183 Orientation.RIGHT: math.pi, 184 Orientation.BOTTOM: math.pi, 185 Orientation.TOP_LEFT: 0.0, 186 Orientation.TOP_RIGHT: -math.pi / 2.0, 187 Orientation.BOTTOM_RIGHT: -math.pi, 188 Orientation.BOTTOM_LEFT: math.pi / 2.0} 189 OPACITY_IDLE = 0.0 190 OPACITY_HOVER = 0.5 191 OPACITY_SCALING = 1.0 192 DEFAULT_INNER_PADDING = (0, 0, 0, 0) 193 _handle = None 194 _handle_wrap = None 195 _hovered = False 196 _scaling = False 197 198 def __init__(self, orientation, on_start_scale = None, on_end_scale = None, enabled = True, inner_padding = None, **kwargs): 199 self._orientation = orientation 200 self._on_start_scale = on_start_scale 201 self._on_end_scale = on_end_scale 202 self._enabled = enabled 203 self._inner_padding = sanitize_padding(inner_padding, default=self.DEFAULT_INNER_PADDING) 204 width, height = self._get_size(orientation=self._orientation, inner_padding=self._inner_padding) 205 super(ResizeHandle, self).__init__(align=self.ALIGN_BY_ORIENTATION[orientation], cursor=self.CURSOR_BY_ORIENTATION[orientation], state=self._get_state(), width=width, height=height, opacity=self._get_opacity(), **kwargs) 206 align = self.HANDLE_ALIGN_BY_ORIENTATION[orientation] 207 rotation = self.TEXTURE_ROTATION_BY_ORIENTATION[orientation] 208 self._handle_wrap = Container(parent=self, align=uiconst.TOALL, clipChildren=True, padding=self._get_handle_wrap_padding()) 209 if orientation in {Orientation.LEFT, Orientation.RIGHT}: 210 self._handle = StretchSpriteVertical(parent=self._handle_wrap, align=align, width=2, height=64, topEdgeSize=2, bottomEdgeSize=2, texturePath='res:/UI/Texture/classes/Window/resize_handle_edge_vertical.png', rotation=rotation, color=self._get_color(), outputMode=uiconst.OUTPUT_COLOR_AND_GLOW, glowBrightness=0.5) 211 elif orientation in {Orientation.TOP, Orientation.BOTTOM}: 212 self._handle = StretchSpriteHorizontal(parent=self._handle_wrap, align=align, width=64, height=2, leftEdgeSize=2, rightEdgeSize=2, texturePath='res:/UI/Texture/classes/Window/resize_handle_edge_horizontal.png', rotation=rotation, color=self._get_color(), outputMode=uiconst.OUTPUT_COLOR_AND_GLOW, glowBrightness=0.5) 213 else: 214 self._handle = Sprite(parent=self._handle_wrap, align=align, width=8, height=8, state=uiconst.UI_DISABLED, texturePath='res:/UI/Texture/classes/Window/resize_handle_corner.png', rotation=rotation, color=self._get_color(), outputMode=uiconst.OUTPUT_COLOR_AND_GLOW, glowBrightness=0.5) 215 216 @property 217 def enabled(self): 218 return self._enabled 219 220 @enabled.setter 221 def enabled(self, value): 222 if self._enabled != value: 223 self._enabled = value 224 self._update_state() 225 226 @property 227 def inner_padding(self): 228 return self._inner_padding 229 230 @inner_padding.setter 231 def inner_padding(self, value): 232 value = sanitize_padding(value, default=self.DEFAULT_INNER_PADDING) 233 if self._inner_padding != value: 234 self._inner_padding = value 235 self._update_size() 236 self._update_handle_wrap_padding() 237 238 @property 239 def orientation(self): 240 return self._orientation 241 242 def _get_state(self): 243 if self._enabled: 244 return uiconst.UI_NORMAL 245 return uiconst.UI_DISABLED 246 247 def _update_state(self): 248 self.state = self._get_state() 249 if not self._enabled: 250 self._end_scaling() 251 252 @classmethod 253 def _get_size(cls, orientation, inner_padding): 254 width, height = cls.SIZE_BY_ORIENTATION[orientation] 255 pad_left, pad_top, pad_right, pad_bottom = inner_padding 256 width += pad_left + pad_right 257 height += pad_top + pad_bottom 258 return (width, height) 259 260 def _update_size(self): 261 self.width, self.height = self._get_size(orientation=self._orientation, inner_padding=self._inner_padding) 262 263 def _get_handle_wrap_padding(self): 264 return self._inner_padding 265 266 def _update_handle_wrap_padding(self): 267 if self._handle_wrap: 268 self._handle_wrap.padding = self._get_handle_wrap_padding() 269 270 def _get_opacity(self): 271 if not self._enabled: 272 return self.OPACITY_IDLE 273 elif self._scaling: 274 return self.OPACITY_SCALING 275 elif self._hovered: 276 return self.OPACITY_HOVER 277 else: 278 return self.OPACITY_IDLE 279 280 def _update_opacity(self): 281 duration = 0.15 if self._hovered else 0.3 282 animations.FadeTo(self, startVal=self.opacity, endVal=self._get_opacity(), duration=duration) 283 284 def _start_scaling(self): 285 if not self._scaling and self._enabled: 286 self._scaling = True 287 self._update_opacity() 288 if self._on_start_scale: 289 self._on_start_scale(self) 290 291 def _end_scaling(self): 292 if self._scaling: 293 self._scaling = False 294 self._update_opacity() 295 if self._on_end_scale: 296 self._on_end_scale(self) 297 298 @staticmethod 299 def _get_color(): 300 return eveThemeColor.THEME_ACCENT 301 302 def OnColorThemeChanged(self): 303 if self._handle is not None: 304 self._handle.color = self._get_color() 305 306 def OnMouseEnter(self, *args): 307 self._hovered = True 308 self._update_opacity() 309 310 def OnMouseExit(self, *args): 311 self._hovered = False 312 self._update_opacity() 313 314 def OnMouseDown(self, button, *args): 315 if button == uiconst.MOUSELEFT and self._enabled: 316 self._start_scaling() 317 318 def OnMouseUp(self, button, *args): 319 if button == uiconst.MOUSELEFT: 320 self._end_scaling()