treeViewEntry.py (22366B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\control\treeViewEntry.py 2 import carbonui.text.styles 3 import logging 4 from math import pi 5 import blue 6 import carbonui 7 from carbon.client.script.environment.AudioUtil import PlaySound 8 from carbon.common.lib import telemetry 9 from carbonui import TextColor, uiconst 10 from carbon.common.script.sys.serviceConst import ROLE_GML, ROLE_PROGRAMMER, ROLE_WORLDMOD 11 from carbonui.control.dragdrop.dragdata import TypeDragData 12 from carbonui.primitives.container import Container 13 from carbonui.primitives.containerAutoSize import ContainerAutoSize 14 from carbonui.primitives.fill import Fill 15 from carbonui.primitives.sprite import Sprite 16 from carbonui.uicore import uicore 17 from carbonui.util.color import Color 18 from eve.client.script.ui import eveColor 19 from eve.client.script.ui.control.eveIcon import Icon 20 from eve.client.script.ui.control.eveLabel import Label 21 from eve.client.script.ui.control.eveWindowUnderlay import ListEntryUnderlay 22 from carbonui.decorative.selectionIndicatorLine import SelectionIndicatorLine 23 from eve.client.script.ui.control.itemIcon import ItemIcon 24 from eve.client.script.ui.control.themeColored import FillThemeColored, GradientThemeColored 25 import localization 26 from eve.client.script.ui.shared.neocom.neocom.buttons.buttonIndicator import ButtonIndicator 27 from eve.client.script.ui.shared.neocom.neocom.highlightState import HighlightState 28 from eveservices.menu import GetMenuService 29 30 class TreeViewEntry(ContainerAutoSize): 31 default_name = 'TreeViewEntry' 32 default_align = uiconst.TOTOP 33 default_alignMode = uiconst.TOTOP 34 default_state = uiconst.UI_NORMAL 35 default_settingsID = '' 36 default_height = 24 37 default_iconColor = eveColor.WHITE 38 default_iconGlowBrightness = 0.0 39 isDragObject = True 40 allow_lazy_construction = True 41 default_label_color = TextColor.NORMAL 42 LEFTPUSH = 8 43 LABEL_PADDING = 4 44 45 @telemetry.ZONE_METHOD 46 def ApplyAttributes(self, attributes): 47 ContainerAutoSize.ApplyAttributes(self, attributes) 48 self.level = attributes.get('level', 0) 49 self.data = attributes.get('data') 50 self.eventListener = attributes.get('eventListener', None) 51 self.parentEntry = attributes.get('parentEntry', None) 52 self.settingsID = attributes.get('settingsID', self.default_settingsID) 53 self.defaultExpanded = attributes.get('defaultExpanded', self.level < 1) 54 self.iconColor = attributes.get('iconColor', self.default_iconColor) 55 self.iconGlowBrightness = attributes.get('iconGlowBrightness', self.default_iconGlowBrightness) 56 self.label_color = attributes.get('label_color', self.default_label_color) 57 if hasattr(self.data, 'uiName'): 58 self.name = self.data.uiName 59 self.childrenInitialized = False 60 self.isToggling = False 61 self.canAccess = True 62 self.descendantSelectedBG = False 63 self.selectedLine = None 64 self.icon = None 65 self.childCont = None 66 self.data.on_selected.connect(self.OnSetSelected) 67 self.data.on_deselected.connect(self.OnSetDeselected) 68 self.data.on_descendant_selected.connect(self.OnDescendantSelected) 69 self.data.on_descendant_deselected.connect(self.OnDescendantDeselected) 70 self.data.on_expanded.connect(self.OnExpanded) 71 self.data.on_collapsed.connect(self.OnCollapsed) 72 self.ConstructContent() 73 if self.data.IsSelected(): 74 self.OnSetSelected(self.data, animate=False) 75 self._UpdateDescendantSelectedBG() 76 77 def OnDescendantSelected(self, node, animate = True): 78 self._UpdateDescendantSelectedBG() 79 80 def OnDescendantDeselected(self, node, animate = True): 81 self._UpdateDescendantSelectedBG() 82 83 def ConstructContent(self): 84 self.topRightCont = Container(name='topCont_%s' % self.name, parent=self, align=uiconst.TOTOP, height=self.default_height) 85 self.topRightCont.GetDragData = self.GetDragData 86 left = self.GetSpacerContWidth() 87 if self.data.IsRemovable(): 88 removeBtn = Sprite(texturePath='res:/UI/Texture/icons/73_16_210.png', parent=self.topRightCont, align=uiconst.CENTERLEFT, width=16, height=16, left=left, hint=localization.GetByLabel('UI/Common/Buttons/Close')) 89 left += 20 90 removeBtn.OnClick = self.Remove 91 left = self.ConstructIcon(left) 92 left += self.LABEL_PADDING 93 self.ConstructLabel() 94 self.label.left = left 95 self.UpdateLabel() 96 self.hoverBG = None 97 self.selectedBG = None 98 self.blinkBG = None 99 if self.data.HasChildren(): 100 self.spacerCont = Container(name='spacerCont', parent=self.topRightCont, align=uiconst.TOLEFT, width=self.GetSpacerContWidth()) 101 self.toggleBtn = Container(name='toggleBtn', parent=self.spacerCont, align=uiconst.CENTERRIGHT, width=16, height=16, state=uiconst.UI_NORMAL) 102 self.toggleBtn.OnClick = self.OnToggleBtnClick 103 self.toggleBtn.OnDblClick = lambda : None 104 self.toggleBtnSprite = Sprite(bgParent=self.toggleBtn, texturePath='res:/UI/Texture/classes/Neocom/arrowDown.png', rotation=pi / 2, padding=(4, 4, 5, 5), color=eveColor.LED_GREY) 105 if not self.data.IsForceCollapsed(): 106 expandChildren = self.GetIsExpandedSetting() 107 else: 108 expandChildren = False 109 else: 110 expandChildren = False 111 self.spacerCont = None 112 self.toggleBtnSprite = None 113 self.ShowChildCont(False, animate=False) 114 if expandChildren: 115 self.ConstructChildren() 116 self.data.SetExpanded(animate=False) 117 else: 118 self.data.SetCollapsed(animate=False) 119 if self.eventListener and hasattr(self.eventListener, 'RegisterID'): 120 self.eventListener.RegisterID(self, self.data.GetID()) 121 self.data.on_created(self.data) 122 123 def GetIsExpandedSetting(self): 124 toggleSettingsDict = settings.user.ui.Get('invTreeViewEntryToggle_%s' % self.settingsID, {}) 125 is_expanded_setting = toggleSettingsDict.get(self.data.GetID(), self.defaultExpanded) 126 return is_expanded_setting 127 128 def ConstructIcon(self, left): 129 icon = self.data.GetIcon() 130 if icon: 131 iconSize = self.GetIconSize() 132 self.icon = Icon(icon=icon, parent=self.topRightCont, pos=(left, 133 0, 134 iconSize, 135 iconSize), align=uiconst.CENTERLEFT, state=uiconst.UI_DISABLED, ignoreSize=True, color=self.iconColor, outputMode=uiconst.OUTPUT_COLOR_AND_GLOW, glowBrightness=self.iconGlowBrightness) 136 left += iconSize 137 return left 138 139 def GetIconSize(self): 140 iconSize = self.height - 2 141 return iconSize 142 143 def ConstructLabel(self): 144 self.label = carbonui.text.styles.TextBody(parent=self.topRightCont, align=uiconst.CENTERLEFT, text=self.data.GetLabel(), autoFadeSides=16) 145 146 def GetSpacerContWidth(self): 147 return (1 + self.level) * self.LEFTPUSH + 16 148 149 def Close(self): 150 try: 151 if self.eventListener and hasattr(self.eventListener, 'UnregisterID'): 152 self.eventListener.UnregisterID(self.data.GetID()) 153 self.data.on_destroyed(self.data) 154 if self.parentEntry and self.data in self.parentEntry.data._children: 155 self.parentEntry.data._children.remove(self.data) 156 finally: 157 ContainerAutoSize.Close(self) 158 159 @telemetry.ZONE_METHOD 160 def ConstructChildren(self): 161 self.childrenInitialized = True 162 children = self.data.GetChildren() 163 if self.destroyed: 164 return 165 if self.childCont is None: 166 self.childCont = ContainerAutoSize(parent=self, name='childCont', align=uiconst.TOTOP, clipChildren=True, state=uiconst.UI_HIDDEN) 167 if children: 168 for child in children: 169 cls = self.GetTreeViewEntryClassByTreeData(child) 170 child = cls(name=getattr(child, 'clsName', ''), parent=self.childCont, parentEntry=self, level=self.level + 1, eventListener=self.eventListener, data=child, settingsID=self.settingsID, state=uiconst.UI_HIDDEN) 171 child.UpdateLabel() 172 if self.allow_lazy_construction: 173 blue.pyos.BeNice() 174 175 if self.childCont.children: 176 self.childCont.children[-1].padBottom = 8 177 178 def GetTreeViewEntryClassByTreeData(self, treeData): 179 return TreeViewEntry 180 181 def ShowChildCont(self, show = True, animate = True): 182 if self.childCont is None or self.childCont.display == show or not self.data.HasChildren(): 183 return 184 for child in self.childCont.children: 185 self.ShowChild(child, show=show) 186 187 self.isToggling = True 188 if animate: 189 if show: 190 self.childCont.display = True 191 uicore.animations.Tr2DRotateTo(self.toggleBtnSprite, pi / 2, 0.0, duration=0.15) 192 _, height = self.childCont.GetAutoSize() 193 self.childCont.DisableAutoSize() 194 uicore.animations.FadeIn(self.childCont, duration=0.15) 195 uicore.animations.MorphScalar(self.childCont, 'height', self.childCont.height, height, duration=0.15, callback=self.childCont.EnableAutoSize) 196 else: 197 uicore.animations.Tr2DRotateTo(self.toggleBtnSprite, 0.0, pi / 2, duration=0.15) 198 self.childCont.DisableAutoSize() 199 uicore.animations.FadeOut(self.childCont, duration=0.15) 200 uicore.animations.MorphScalar(self.childCont, 'height', self.childCont.height, 0, duration=0.15, callback=self._OnEndFadeOut) 201 self.toggleBtn.Enable() 202 else: 203 self.childCont.display = show 204 if show: 205 self.toggleBtnSprite.rotation = 0.0 206 self.childCont.opacity = 1.0 207 else: 208 self.toggleBtnSprite.rotation = pi / 2 209 self.childCont.DisableAutoSize() 210 self.childCont.opacity = 0.0 211 self.isToggling = False 212 213 def _OnEndFadeOut(self, *args): 214 self.childCont.EnableAutoSize() 215 self.childCont.Hide() 216 217 def ShowChild(self, child, show = True): 218 child.display = show 219 220 def UpdateSelectedState(self, selectedIDs): 221 nodeID = self.data.GetID() 222 isSelected = selectedIDs[-1] == nodeID 223 if isSelected: 224 self.SetSelected() 225 else: 226 self.SetDeselected() 227 228 def SetSelected(self, animate = True): 229 self.data.SetSelected(animate) 230 231 def OnSetSelected(self, node, animate = True): 232 self.CheckConstructHoverBG() 233 self.hoverBG.Select() 234 self.CheckConstructSelectedLine() 235 self.selectedLine.Select() 236 if self.parentEntry: 237 self.parentEntry.ExpandFromRoot(animate) 238 self.UpdateLabel() 239 self.UpdateToggleBtnSpriteColor() 240 241 def _UpdateDescendantSelectedBG(self): 242 if self.data.IsAnyDescendantSelected(): 243 self.CheckConstructChildSelectedGradient() 244 self.descendantSelectedBG.Show() 245 elif self.descendantSelectedBG: 246 self.descendantSelectedBG.Hide() 247 248 def SetDeselected(self, animate = True): 249 self.data.SetDeselected(animate) 250 251 def OnSetDeselected(self, node, animate = True): 252 if self.hoverBG: 253 self.hoverBG.Deselect() 254 if self.selectedLine: 255 self.selectedLine.Deselect() 256 self.UpdateLabel() 257 self.UpdateToggleBtnSpriteColor() 258 259 def UpdateToggleBtnSpriteColor(self): 260 if not self.toggleBtnSprite: 261 return 262 if self.data.IsSelected(): 263 self.toggleBtnSprite.SetRGBA(*eveColor.WHITE) 264 else: 265 self.toggleBtnSprite.SetRGBA(*eveColor.LED_GREY) 266 267 def CheckConstructSelectedLine(self): 268 if not self.selectedLine: 269 self.selectedLine = SelectionIndicatorLine(parent=self.topRightCont, align=uiconst.TOLEFT_NOPUSH, idx=0, padding=4) 270 271 def CheckConstructChildSelectedGradient(self): 272 if not self.descendantSelectedBG: 273 self.descendantSelectedBG = GradientThemeColored(bgParent=self.spacerCont, rotation=0, alphaData=[(0, 0.5), (1.0, 0.0)], colorType=uiconst.COLORTYPE_UIHILIGHT) 274 275 @telemetry.ZONE_METHOD 276 def UpdateLabel(self): 277 if self.data.IsSelected() and self.canAccess: 278 self.label.color = TextColor.HIGHLIGHT 279 elif self.canAccess: 280 self.label.color = self.label_color 281 else: 282 self.label.color = TextColor.DISABLED 283 if session.role & (ROLE_GML | ROLE_WORLDMOD): 284 if settings.user.ui.Get('invPrimingDebugMode', False) and hasattr(self.data, 'invController') and self.data.invController.IsPrimed(): 285 self.label.color = Color.RED 286 287 def ExpandFromRoot(self, animate = True): 288 self.ShowChildren(animate) 289 if self.parentEntry: 290 self.parentEntry.ExpandFromRoot(animate) 291 292 def OnClick(self, *args): 293 PlaySound(uiconst.SOUND_ENTRY_SELECT) 294 self.data.on_click(self.data) 295 if self.eventListener and hasattr(self.eventListener, 'OnTreeViewClick'): 296 self.eventListener.OnTreeViewClick(self, *args) 297 298 def OnDblClick(self, *args): 299 self.data.on_dbl_click(self.data) 300 if self.eventListener and hasattr(self.eventListener, 'OnTreeViewDblClick'): 301 self.eventListener.OnTreeViewDblClick(self, *args) 302 303 def OnToggleBtnClick(self, *args): 304 if not self.isToggling: 305 self.data.ToggleExpanded() 306 307 def ToggleChildren(self, animate = True): 308 self.data.ToggleExpanded(animate) 309 310 def ShowChildren(self, amimate = True): 311 self.data.SetExpanded(amimate) 312 313 def HideChildren(self): 314 self.data.SetCollapsed() 315 316 def OnExpanded(self, treeData, animate = True): 317 self._PersistIsExpandedSetting(True) 318 if not self.data.HasChildren(): 319 return 320 if not self.childrenInitialized: 321 self.ConstructChildren() 322 PlaySound(uiconst.SOUND_EXPAND) 323 self.ShowChildCont(True, animate) 324 325 def OnCollapsed(self, treeData, animate = True): 326 self._PersistIsExpandedSetting(False) 327 if not self.data.HasChildren(): 328 return 329 if not self.childrenInitialized: 330 self.ConstructChildren() 331 PlaySound(uiconst.SOUND_COLLAPSE) 332 self.ShowChildCont(False, animate) 333 334 def _PersistIsExpandedSetting(self, isExpanded): 335 toggleSettingsName = 'invTreeViewEntryToggle_%s' % self.settingsID 336 toggleSettingsDict = settings.user.ui.Get(toggleSettingsName, {}) 337 toggleSettingsDict[self.data.GetID()] = isExpanded 338 settings.user.ui.Set(toggleSettingsName, toggleSettingsDict) 339 340 def GetMenu(self): 341 m = self.data.GetMenu() 342 if session.role & ROLE_PROGRAMMER: 343 idString = repr(self.data.GetID()) 344 m.append((u'GM: nodeID={}'.format(idString), blue.pyos.SetClipboardData, (idString,))) 345 if self.data.IsRemovable(): 346 m.append(None) 347 m.append((localization.GetByLabel('UI/Common/Buttons/Close'), self.Remove, ())) 348 return m 349 350 def GetTooltipPointer(self): 351 return self.data.GetTooltipPointer() 352 353 def GetHint(self): 354 return self.data.GetHint() 355 356 def GetFullPathLabelList(self): 357 labelTuple = [self.data.GetLabel()] 358 if self.parentEntry: 359 labelTuple = self.parentEntry.GetFullPathLabelList() + labelTuple 360 return labelTuple 361 362 def Remove(self, *args): 363 self.eventListener.RemoveTreeEntry(self, byUser=True) 364 365 def OnMouseDown(self, *args): 366 self.data.on_mouse_down(self.data) 367 if self.eventListener and hasattr(self.eventListener, 'OnTreeViewMouseDown'): 368 self.eventListener.OnTreeViewMouseDown(self, *args) 369 370 def OnMouseUp(self, *args): 371 self.data.on_mouse_up(self.data) 372 if self.eventListener and hasattr(self.eventListener, 'OnTreeViewMouseUp'): 373 self.eventListener.OnTreeViewMouseUp(self, *args) 374 375 def CheckConstructHoverBG(self): 376 if self.hoverBG is None: 377 self.hoverBG = ListEntryUnderlay(bgParent=self.topRightCont) 378 379 def CheckConstructSelectedBG(self): 380 if self.selectedBG is None: 381 self.selectedBG = FillThemeColored(bgParent=self.topRightCont, colorType=uiconst.COLORTYPE_UIHILIGHT, state=uiconst.UI_HIDDEN, opacity=0.5) 382 383 def CheckConstructBlinkBG(self): 384 if self.blinkBG is None: 385 self.blinkBG = Fill(bgParent=self.topRightCont, color=(1.0, 1.0, 1.0, 0.0)) 386 387 def OnMouseEnter(self, *args): 388 self.CheckConstructHoverBG() 389 self.hoverBG.hovered = True 390 PlaySound(uiconst.SOUND_ENTRY_HOVER) 391 self.data.on_mouse_enter(self.data) 392 if self.eventListener and hasattr(self.eventListener, 'OnTreeViewMouseEnter'): 393 self.eventListener.OnTreeViewMouseEnter(self, *args) 394 395 def OnMouseExit(self, *args): 396 if self.hoverBG: 397 self.hoverBG.hovered = False 398 self.data.on_mouse_exit(self.data) 399 if self.eventListener and hasattr(self.eventListener, 'OnTreeViewMouseExit'): 400 self.eventListener.OnTreeViewMouseExit(self, *args) 401 402 def OnDropData(self, *args): 403 self.data.on_drop_data(self.data) 404 if self.eventListener and hasattr(self.eventListener, 'OnTreeViewDropData'): 405 self.eventListener.OnTreeViewDropData(self, *args) 406 407 def OnDragEnter(self, dragObj, nodes): 408 self.CheckConstructHoverBG() 409 self.hoverBG.hovered = True 410 self.data.on_drag_enter(self.data) 411 if self.eventListener and hasattr(self.eventListener, 'OnTreeViewDragEnter'): 412 self.eventListener.OnTreeViewDragEnter(self, dragObj, nodes) 413 414 def GetDragData(self): 415 if self.data.IsDraggable(): 416 self.eventListener.OnTreeViewGetDragData(self) 417 return [self.data] 418 419 def OnDragExit(self, *args): 420 if self.hoverBG: 421 self.hoverBG.hovered = False 422 self.data.on_drag_exit(self.data) 423 if self.eventListener and hasattr(self.eventListener, 'OnTreeViewDragExit'): 424 self.eventListener.OnTreeViewDragExit(self, *args) 425 426 def Blink(self): 427 self.CheckConstructBlinkBG() 428 uicore.animations.FadeTo(self.blinkBG, 0.0, 0.25, duration=0.25, curveType=uiconst.ANIM_WAVE, loops=2) 429 430 @telemetry.ZONE_METHOD 431 def SetAccessability(self, canAccess): 432 self.canAccess = canAccess 433 if self.icon: 434 if canAccess: 435 self.icon.color = TextColor.NORMAL 436 else: 437 self.icon.color = TextColor.DISABLED 438 self.UpdateLabel() 439 440 441 class TreeViewEntryWithTag(TreeViewEntry): 442 default_name = 'TreeViewEntryWithTag' 443 __notifyevents__ = ['OnInventoryBadgingUpdated', 'OnInventoryBadgingDestroyed'] 444 TAG_SIZE = 8 445 TAG_PADDING = 4 446 TAG_COLOR = (0.97, 0.09, 0.13) 447 TAG_TEXTURE_PATH = 'res:/UI/Texture/Shared/smallDot.png' 448 449 def ApplyAttributes(self, attributes): 450 onDividerMoved = attributes.get('onDividerMoved', None) 451 if onDividerMoved is not None: 452 onDividerMoved.connect(self.OnDividerMoved) 453 self.shouldShowTag = False 454 super(TreeViewEntryWithTag, self).ApplyAttributes(attributes) 455 sm.RegisterNotify(self) 456 457 def ConstructContent(self): 458 super(TreeViewEntryWithTag, self).ConstructContent() 459 self.ConstructTag() 460 461 def ConstructTag(self): 462 self.tagContainer = Container(name='tagContainer', parent=self.topRightCont, align=uiconst.TORIGHT, width=ButtonIndicator.default_width, padding=(self.TAG_PADDING, 463 0, 464 self.TAG_PADDING, 465 0), state=uiconst.UI_HIDDEN) 466 self.buttonIndicator = ButtonIndicator(parent=self.tagContainer, align=uiconst.CENTER) 467 self.buttonIndicator.SetHighlightState(HighlightState.important) 468 self.UpdateShouldShowTag() 469 470 def UpdateShouldShowTag(self): 471 self.shouldShowTag = sm.GetService('neocom').HasUnseenInventoryItemsInLocation(self.data.invType) 472 self.UpdateTagState() 473 474 def UpdateTagState(self): 475 self.tagContainer.state = uiconst.UI_DISABLED if self.shouldShowTag else uiconst.UI_HIDDEN 476 self.UpdateLabelWidth() 477 478 def ClearTag(self): 479 self.tagContainer.state = uiconst.UI_HIDDEN 480 self.UpdateLabelWidth() 481 482 def UpdateLabelWidth(self): 483 entryWidth, _ = self.GetAbsoluteSize() 484 tagWidth = self.TAG_SIZE + 2 * self.TAG_PADDING if self.tagContainer.display else 0 485 clipWidth = entryWidth - self.label.left - tagWidth 486 if clipWidth > 0 and self.label.textwidth > clipWidth: 487 self.label.clipWidth = clipWidth 488 else: 489 self.label.clipWidth = self.label.textwidth 490 491 def OnDividerMoved(self): 492 self.UpdateLabelWidth() 493 494 def OnInventoryBadgingUpdated(self): 495 self.UpdateShouldShowTag() 496 497 def OnInventoryBadgingDestroyed(self): 498 self.UpdateShouldShowTag() 499 500 501 class TreeViewEntryHeader(TreeViewEntry): 502 default_height = 48 503 LABEL_PADDING = 8 504 505 def ConstructLabel(self): 506 self.label = carbonui.text.styles.TextHeader(parent=self.topRightCont, align=uiconst.CENTERLEFT, text=self.data.GetLabel(), autoFadeSides=16) 507 508 def GetIconSize(self): 509 return 32 510 511 512 class TreeViewEntryShip(TreeViewEntry): 513 default_height = 32 514 515 def ConstructIcon(self, left): 516 iconSize = self.GetIconSize() 517 self.icon = ItemIcon(parent=self.topRightCont, pos=(left, 518 0, 519 iconSize, 520 iconSize), align=uiconst.CENTERLEFT, state=uiconst.UI_DISABLED, typeID=self.data.GetID()) 521 return left + iconSize + 2 522 523 def GetMenu(self): 524 m = super(TreeViewEntryShip, self).GetMenu() 525 return m + GetMenuService().GetMenuFromItemIDTypeID(itemID=None, typeID=self.data.GetID(), includeMarketDetails=True) 526 527 def OnMouseEnter(self, *args): 528 super(TreeViewEntryShip, self).OnMouseEnter(*args) 529 self.icon.OnMouseEnter(*args) 530 531 def OnMouseExit(self, *args): 532 super(TreeViewEntryShip, self).OnMouseExit(*args) 533 self.icon.OnMouseExit(*args) 534 535 def GetDragData(self): 536 return [TypeDragData(self.data.GetID())]