plexVault.py (23279B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\inventory\plexVault.py 2 from carbon.client.script.environment.AudioUtil import PlaySound 3 from carbon.common.script.util.format import FmtAmt 4 from carbonui import uiconst, fontconst 5 from carbonui.control.scrollContainer import ScrollContainer 6 from carbonui.primitives.container import Container 7 from carbonui.primitives.containerAutoSize import ContainerAutoSize 8 from carbonui.primitives.fill import Fill 9 from carbonui.primitives.flowcontainer import FlowContainer 10 from carbonui.primitives.frame import Frame 11 from carbonui.primitives.sprite import Sprite 12 from carbonui.uianimations import animations 13 from carbonui.uicore import uicore 14 from carbonui.util.bunch import Bunch 15 from eve.client.script.environment import invControllers 16 from eve.client.script.ui.control.eveLabel import Label, EveCaptionMedium, EveLabelMedium 17 from eve.client.script.ui.control.eveWindowUnderlay import ListEntryUnderlay 18 from eve.client.script.ui.control.infoIcon import MoreInfoIcon 19 from eve.client.script.ui.plex.textures import PLEX_128_GRADIENT_YELLOW, PLEX_SLOT 20 from eve.client.script.ui.services.menuSvcExtras.marketMenu import SellItems 21 from eve.client.script.ui.shared.container import _InvContBase 22 from eve.client.script.ui.shared.market.sellMulti import SellItems as SellItemsWnd 23 from eve.client.script.ui.shared.tooltip.item import InventoryItemTooltip 24 from eve.client.script.ui.tooltips.tooltipsWrappers import TooltipDescriptionWrapper 25 from plex.client.api.repository import get_repository 26 from plex.client.api.signal import on_balance_changed 27 from plex.common.const import InvoiceType 28 from vgs.client.currency import OFFER_CURRENCY_PLEX 29 from eve.client.script.ui.shared.vgs.priceTag import PriceTagSmall 30 from eve.client.script.ui.util.uix import QtyPopup 31 from eve.client.script.ui.view.aurumstore.shared.offerpricing import get_min_offer_price_in_currency 32 from eve.common.lib.vgsConst import CATEGORYTAG_GAMETIME 33 import evelink.client 34 import evetypes 35 from eveexceptions import UserError 36 from fastcheckout.const import FROM_PLEX_VAULT 37 from inventorycommon import const as invconst 38 from inventorycommon.typeHelpers import GetAveragePrice 39 from inventorycommon.util import GetTypeVolume 40 import localization 41 import logging 42 import uthread 43 from vgs.common.listeners import PlexWithdrawalListener, PlexDepositListener 44 logger = logging.getLogger(__name__) 45 46 class PlexVaultController(object): 47 48 @property 49 def balance(self): 50 try: 51 return get_repository().get_balance() 52 except Exception as e: 53 logger.exception('failed to retrieve PLEX balance: %s' % e) 54 return None 55 56 def DepositPlex(self, itemID, quantity): 57 locationID = session.stationid or session.structureid 58 reference = sm.GetService('invCache').GetInventoryMgr().DepositPlexToVault(locationID, itemID, quantity, InvoiceType.InventoryToVault) 59 PlexDepositListener(session.userid, quantity, reference) 60 61 def WithdrawPlex(self, inventory): 62 if not inventory.DoesAcceptItem(self._GetFakePlexItem()): 63 return 64 savedLocationID = session.locationid 65 quantity = self._PromptUserForQuantity(inventory) 66 if quantity is None or quantity <= 0: 67 return 68 if session.locationid != savedLocationID: 69 return 70 if not inventory.CheckCanAdd(invconst.typePlex, quantity): 71 return 72 otherPartyID = None 73 if hasattr(inventory, 'tradeSession') and inventory.tradeSession is not None: 74 tradeSession = inventory.tradeSession.List() 75 otherPartyID = tradeSession.traders[not tradeSession.traders.index(session.charid)] 76 invID = inventory.GetInvID() 77 if invID and len(invID) > 0 and invID[0] == 'PlayerTrade': 78 invoiceType = InvoiceType.VaultToDirectTrade 79 else: 80 invoiceType = InvoiceType.VaultToInventory 81 reference = sm.GetService('invCache').GetInventoryMgr().WithdrawPlexFromVault(quantity, inventory.itemID, invoiceType, inventory.locationFlag, otherPartyID) 82 PlexWithdrawalListener(session.userid, quantity, reference) 83 84 def _GetFakePlexItem(self): 85 return Bunch(typeID=invconst.typePlex, groupID=evetypes.GetGroupID(invconst.typePlex), categoryID=evetypes.GetCategoryID(invconst.typePlex), quantity=self.balance, singleton=0, stacksize=self.balance, ownerID=session.charid, isInPlexVault=True) 86 87 def _PromptUserForQuantity(self, inventory): 88 if inventory.hasCapacity: 89 capacity = inventory.GetCapacity() 90 remainingCapacity = capacity.capacity - capacity.used 91 itemVolume = GetTypeVolume(invconst.typePlex, 1) 92 maxQuantity = min(self.balance, int(remainingCapacity / itemVolume)) 93 if maxQuantity <= 0: 94 raise UserError('NotEnoughCargoSpaceFor1Unit', {'type': invconst.typePlex, 95 'free': remainingCapacity, 96 'required': itemVolume}) 97 else: 98 maxQuantity = self.balance 99 if maxQuantity <= 0: 100 return 0 101 if maxQuantity != self.balance: 102 errmsg = localization.GetByLabel('UI/Common/NoRoomForMore') 103 else: 104 errmsg = None 105 ret = QtyPopup(maxvalue=maxQuantity, minvalue=0, setvalue=maxQuantity, hint=errmsg) 106 if ret: 107 return ret['qty'] 108 109 def OnDropData(self, dragObj, nodes): 110 items = self._GatherDroppedPlexItemIds(nodes) 111 for item in items: 112 if item.groupID != invconst.groupCurrency: 113 continue 114 self.DepositPlex(item.itemID, item.stacksize) 115 116 def _GatherDroppedPlexItemIds(self, nodes): 117 items = [] 118 for node in nodes: 119 if not hasattr(node, 'item') or node.item is None: 120 continue 121 if node.item.typeID != invconst.typePlex: 122 continue 123 if node.item.itemID is None: 124 continue 125 items.append(node.item) 126 127 return items 128 129 def GetItemMenu(self): 130 return sm.GetService('menu').InvItemMenu(self._GetFakePlexItem()) 131 132 def SellPlex(self): 133 if not session.stationid and not session.structureid: 134 raise UserError('CantSellPLEXFromSpace') 135 item = self._GetFakePlexItem() 136 item.locationID = session.stationid or session.structureid 137 item.flagID = invconst.flagHangar 138 SellItems([item]) 139 140 141 def IsPartiallyClipped(child): 142 parent = child.parent 143 cdx = child.displayX 144 cdw = child.displayWidth 145 sdw = parent.displayWidth 146 if cdw > sdw or cdx + cdw > sdw: 147 return True 148 cdy = child.displayY 149 cdh = child.displayHeight 150 sdh = parent.displayHeight 151 if cdh > sdh or cdy + cdh > sdh: 152 return True 153 return False 154 155 156 class PlexVault(_InvContBase): 157 __invControllerClass__ = invControllers.PlexVault 158 default_name = invconst.INVENTORY_ID_PLEX_VAULT 159 default_availableViewModes = [] 160 161 def ApplyAttributes(self, attributes): 162 self.controller = PlexVaultController() 163 self._isResponsive = False 164 super(PlexVault, self).ApplyAttributes(attributes) 165 166 def ConstructUI(self): 167 self.viewMode = 'icons' 168 self.vault = Vault(parent=self, align=uiconst.TOTOP, padBottom=16, controller=self.controller) 169 self.mainCont = Container(parent=self, align=uiconst.TOALL, clipChildren=True) 170 self.vaultActionsScrollContainer = ScrollContainer(name='vaultActionsScrollContainer', parent=self.mainCont, align=uiconst.TOALL) 171 self.actions = PlexVaultActions(parent=self.vaultActionsScrollContainer, align=uiconst.TOTOP, controller=self.controller, logContext=FROM_PLEX_VAULT) 172 173 def IsQuickFilterEnabled(self): 174 return False 175 176 def IsCapacityEnabled(self): 177 return False 178 179 def IsEstimatedValueEnabled(self): 180 return False 181 182 def OnDropData(self, dragObj, nodes): 183 self.controller.OnDropData(dragObj, nodes) 184 185 def OnPostCfgDataChanged(self, what, data): 186 pass 187 188 def UpdateHint(self): 189 pass 190 191 def _ChangeViewMode(self): 192 pass 193 194 195 class Vault(Container): 196 default_height = 120 197 default_state = uiconst.UI_NORMAL 198 default_clipChildren = True 199 200 def ApplyAttributes(self, attributes): 201 super(Vault, self).ApplyAttributes(attributes) 202 self.controller = attributes.controller 203 self._currentBalance = None 204 self.Layout() 205 uthread.new(self.UpdateBalance, animate=False) 206 on_balance_changed.connect(self.OnBalanceUpdated) 207 208 def Close(self): 209 on_balance_changed.disconnect(self.OnBalanceUpdated) 210 super(Vault, self).Close() 211 212 def Layout(self): 213 centerCont = Container(parent=self, align=uiconst.CENTER, width=130, height=90) 214 Sprite(bgParent=centerCont, texturePath=PLEX_SLOT, width=118, height=90, opacity=0.5) 215 leftCont = Container(parent=self, align=uiconst.TOLEFT_PROP, width=0.5) 216 balanceLabelCont = ContainerAutoSize(parent=leftCont, align=uiconst.CENTERRIGHT, left=60) 217 self.balanceLabel = EveCaptionMedium(parent=balanceLabelCont, align=uiconst.TOPRIGHT) 218 self.iskValueLabel = EveLabelMedium(parent=balanceLabelCont, align=uiconst.TOPRIGHT, top=26, opacity=0.6) 219 self.item = PlexItem(parent=centerCont, align=uiconst.CENTER, controller=self.controller) 220 MoreInfoIcon(parent=centerCont, align=uiconst.TOPRIGHT, hint=localization.GetByLabel('UI/PlexVault/HelpText'), opacity=0.5) 221 222 def OnDragEnter(self, dragObj, nodes): 223 pass 224 225 def OnDragExit(self, dragObj, nodes): 226 pass 227 228 def OnDropData(self, dragObj, nodes): 229 self.controller.OnDropData(dragObj, nodes) 230 231 def UpdateBalance(self, animate = True): 232 balance = self.controller.balance 233 if balance is not None: 234 if balance > 0: 235 self.item.Show() 236 else: 237 self.item.Hide() 238 if animate: 239 animations.MorphScalar(self, 'balance', startVal=float(self.balance) or 0, endVal=float(balance), curveType=uiconst.ANIM_SMOOTH, duration=1.2, callback=lambda : setattr(self, 'balance', float(balance))) 240 else: 241 self.balance = balance 242 else: 243 self.item.Hide() 244 self.balanceLabel.SetText(localization.GetByLabel('UI/PlexVault/PlexBalanceUnknown')) 245 self.iskValueLabel.SetText(localization.GetByLabel('UI/PlexVault/PlexVaultConnectionLost')) 246 247 @property 248 def balance(self): 249 return self._currentBalance 250 251 @balance.setter 252 def balance(self, balance): 253 self._currentBalance = balance 254 text = localization.GetByLabel('UI/PlexVault/PlexBalance', amount=balance) 255 self.balanceLabel.SetText(text) 256 price = GetAveragePrice(invconst.typePlex) 257 if price: 258 value = balance * price 259 text = localization.GetByLabel('UI/PlexVault/EstimatedIskValue', value=value) 260 self.iskValueLabel.SetText(text) 261 262 def OnBalanceUpdated(self, *args, **kwargs): 263 self.UpdateBalance() 264 265 266 class PlexItem(Container): 267 default_width = 64 268 default_height = 64 269 default_state = uiconst.UI_NORMAL 270 isDragObject = True 271 272 def ApplyAttributes(self, attributes): 273 super(PlexItem, self).ApplyAttributes(attributes) 274 self.controller = attributes.controller 275 self.ConstructLayout() 276 uthread.new(self.UpdateBalance) 277 on_balance_changed.connect(self.OnBalanceUpdated) 278 279 def Close(self): 280 on_balance_changed.disconnect(self.OnBalanceUpdated) 281 super(PlexItem, self).Close() 282 283 def ConstructLayout(self): 284 self.hilite = ListEntryUnderlay(bgParent=self, padding=(-6, -6, -5, -5)) 285 Sprite(bgParent=self, name='background', texturePath='res:/UI/Texture/classes/InvItem/bgNormal.png') 286 Sprite(parent=self, name='icon', align=uiconst.TOALL, state=uiconst.UI_DISABLED, texturePath=PLEX_128_GRADIENT_YELLOW) 287 qtypar = ContainerAutoSize(parent=self, idx=0, name='qtypar', pos=(2, 48, 0, 0), align=uiconst.TOPRIGHT, state=uiconst.UI_DISABLED, bgColor=(0, 0, 0, 0.9)) 288 self.quantityLabel = Label(parent=qtypar, maxLines=1, bold=True, fontsize=fontconst.EVE_SMALL_FONTSIZE, opacity=1.0, padding=(4, 1, 4, 0)) 289 290 def OnClick(self, *args): 291 PlaySound(uiconst.SOUND_ENTRY_SELECT) 292 super(PlexItem, self).OnClick(*args) 293 294 def OnMouseEnter(self, *args): 295 self.hilite.hovered = True 296 PlaySound(uiconst.SOUND_ENTRY_HOVER) 297 298 def OnMouseExit(self, *args): 299 self.hilite.hovered = False 300 301 def OnDropData(self, dragObj, nodes): 302 self.controller.OnDropData(dragObj, nodes) 303 304 def GetDragData(self): 305 return [PlexDragData(self.controller)] 306 307 def OnEndDrag(self, dragSource, dropLocation, dragData): 308 if self is dragSource: 309 wnd = SellItemsWnd.GetIfOpen() 310 if dropLocation.IsUnder(wnd) or dropLocation is wnd: 311 wnd.DropItems(None, dragData) 312 313 def GetMenu(self): 314 return self.controller.GetItemMenu() 315 316 def LoadTooltipPanel(self, tooltipPanel, *args): 317 if uicore.IsDragging(): 318 return 319 InventoryItemTooltip(tooltipPanel=tooltipPanel, item=self.controller._GetFakePlexItem()) 320 321 def UpdateBalance(self): 322 if self.controller.balance: 323 self.quantityLabel.SetText(FmtAmt(self.controller.balance, fmt='ss')) 324 325 def OnBalanceUpdated(self, *args, **kwargs): 326 self.UpdateBalance() 327 328 329 class PlexDragData(object): 330 __guid__ = None 331 332 def __init__(self, controller): 333 self.typeID = invconst.typePlex 334 self.controller = controller 335 336 @property 337 def item(self): 338 return self.controller._GetFakePlexItem() 339 340 def get_link(self): 341 return evelink.type_link(self.typeID) 342 343 def LoadIcon(self, icon, parent, size): 344 icon.LoadIconByTypeID(self.typeID, size=size) 345 346 def WithdrawPlex(self, invController): 347 self.controller.WithdrawPlex(invController) 348 349 350 def GetPriceForTypeIdFunctor(typeID): 351 352 def f(): 353 store = sm.GetService('vgsService').GetStore() 354 offers = store.SearchOffersByTypeIDs([typeID]) 355 if offers: 356 return get_min_offer_price_in_currency(offers, OFFER_CURRENCY_PLEX) 357 358 return f 359 360 361 def GetPriceForStoreCategoryIdFunctor(categoryID): 362 363 def f(): 364 store = sm.GetService('vgsService').GetStore() 365 categoryID = store.GetCategoryIdByCategoryTag(CATEGORYTAG_GAMETIME) 366 offers = store.SearchOffersByCategoryIDs([categoryID]) 367 if offers: 368 return get_min_offer_price_in_currency(offers, OFFER_CURRENCY_PLEX) 369 370 return f 371 372 373 class PlexVaultActions(FlowContainer): 374 default_name = 'PlexVaultActions' 375 376 def __init__(self, controller, logContext, **kwargs): 377 self.controller = controller 378 self.logContext = logContext 379 self.sellPlexForIskAction = None 380 self.sellPlexForIskDisabledTooltip = None 381 super(PlexVaultActions, self).__init__(centerContent=True, contentSpacing=(16, 16), **kwargs) 382 on_balance_changed.connect(self.OnBalanceUpdated) 383 self.Load() 384 385 def Close(self): 386 on_balance_changed.connect(self.OnBalanceUpdated) 387 super(PlexVaultActions, self).Close() 388 389 def Reload(self): 390 self.Flush() 391 self.Load() 392 393 def Load(self): 394 self.sellPlexForIskAction = PlexAction(parent=self, align=uiconst.NOALIGN, text=localization.GetByLabel('UI/PlexVault/SellPlexForIsk'), texturePath='res:/UI/Texture/classes/PlexVault/BuyISKforPLEX.png', onClick=self.SellPlex, onUpdate=self.UpdatePlexActionHeights) 395 self.sellPlexForIskDisabledTooltip = TooltipDescriptionWrapper(description=localization.GetByLabel('UI/PlexVault/SellPlexForIskDisabledTooltipDescription')) 396 PlexAction(parent=self, align=uiconst.NOALIGN, text=localization.GetByLabel('UI/PlexVault/AddOmegaTime'), texturePath='res:/UI/Texture/classes/PlexVault/UpgradeOmega.png', onClick=self.BuyOmegaTime, onUpdate=self.UpdatePlexActionHeights) 397 PlexAction(parent=self, align=uiconst.NOALIGN, text=localization.GetByLabel('UI/PlexVault/BuyMultipleTraining'), texturePath='res:/UI/Texture/Icons/multiple_training.png', price=GetPriceForTypeIdFunctor(invconst.typeMultiTrainingToken), onClick=self.BuyMultipleTraining, onUpdate=self.UpdatePlexActionHeights) 398 PlexAction(parent=self, align=uiconst.NOALIGN, text=localization.GetByLabel('UI/PlexVault/OpenNewEdenStore'), texturePath='res:/UI/Texture/WindowIcons/NES.png', onClick=self.OpenNewEdenStore, onUpdate=self.UpdatePlexActionHeights) 399 self.buyPlexAction = PlexAction(parent=self, align=uiconst.NOALIGN, text=localization.GetByLabel('UI/PlexVault/BuyPlexForMoney'), texturePath=PLEX_128_GRADIENT_YELLOW, onClick=self.BuyPlex, onUpdate=self.UpdatePlexActionHeights, isHighlighted=True) 400 for action in self.children: 401 action.ResetSize() 402 403 self.OnBalanceUpdated(self.controller.balance) 404 self.UnifyContentSize() 405 406 def OnBalanceUpdated(self, balance, *args, **kwargs): 407 if balance > 0: 408 self.sellPlexForIskAction.Enable() 409 self.sellPlexForIskAction.tooltipPanelClassInfo = None 410 else: 411 self.sellPlexForIskAction.tooltipPanelClassInfo = self.sellPlexForIskDisabledTooltip 412 self.sellPlexForIskAction.Disable() 413 414 def UpdatePlexActionHeights(self): 415 for action in self.children: 416 action.ResetSize() 417 418 self.UnifyContentSize() 419 420 def ShowBuyPlex(self): 421 if self.buyPlexAction.IsVisible(): 422 return 423 self.buyPlexAction.Show() 424 self.buyPlexAction.opacity = 0.0 425 animations.MorphScalar(self.buyPlexAction, 'width', startVal=0, endVal=self.buyPlexAction.default_width, duration=0.1) 426 animations.FadeIn(self.buyPlexAction, duration=0.2, timeOffset=0.1) 427 428 def HideBuyPlex(self, animate = True): 429 if animate: 430 animations.FadeOut(self.buyPlexAction, duration=0.2) 431 animations.MorphScalar(self.buyPlexAction, 'width', startVal=self.buyPlexAction.default_width, endVal=0, duration=0.1, timeOffset=0.2, callback=self.buyPlexAction.Hide) 432 else: 433 self.buyPlexAction.Hide() 434 435 def OpenNewEdenStore(self): 436 uicore.cmd.ToggleAurumStore() 437 438 def BuyOmegaTime(self): 439 sm.GetService('vgsService').OpenStore(categoryTag=CATEGORYTAG_GAMETIME) 440 441 def BuyMultipleTraining(self): 442 sm.GetService('vgsService').OpenStore(typeIds=[invconst.typeSoulboundMultiTrainingToken]) 443 444 def BuyPlex(self): 445 uicore.cmd.CmdBuyPlex(self.logContext) 446 447 def ViewPlexMarketDetails(self): 448 sm.StartService('marketutils').ShowMarketDetails(invconst.typePlex, None) 449 450 def SellPlex(self): 451 self.controller.SellPlex() 452 453 454 def center(text): 455 return u'<center>{}</center>'.format(text) 456 457 458 class PlexAction(Container): 459 default_name = 'PlexAction' 460 default_state = uiconst.UI_NORMAL 461 default_width = 80 462 disabled_color = (1.0, 1.0, 1.0, 0.5) 463 enabled_color = (1.0, 1.0, 1.0, 1.0) 464 default_isHighlighted = False 465 frameColor_enabled = (1.0, 0.65, 0.0, 1.0) 466 frameColor_disabled = (1.0, 1.0, 1.0, 0.5) 467 underlayColor = (1.0, 1.0, 1.0, 0.1) 468 underlayColorHighlighted = (0.87, 0.61, 0.0, 0.2) 469 470 def ApplyAttributes(self, attributes): 471 super(PlexAction, self).ApplyAttributes(attributes) 472 self.action = attributes.onClick 473 self.price = attributes.price 474 self.texturePath = attributes.texturePath 475 self.text = attributes.text 476 self.onUpdate = attributes.onUpdate 477 self.isHighlighted = attributes.get('isHighlighted', self.default_isHighlighted) 478 self.priceTag = None 479 self.actionIcon = None 480 self.actionLabelText = None 481 self.frame = None 482 self.underlay = None 483 self.enabled = True 484 self.Layout() 485 486 def Layout(self): 487 self.CreateFrame() 488 self.CreateUnderlay() 489 self.CreateTopContainer() 490 self.CreateBottomContainer() 491 492 def CreateFrame(self): 493 if self.isHighlighted: 494 self.frame = Frame(name='border_frame', bgParent=self, color=self.frameColor_enabled) 495 496 def CreateUnderlay(self): 497 self.underlay = Fill(bgParent=self, color=self.underlayColorHighlighted if self.isHighlighted else self.underlayColor) 498 499 def CreateTopContainer(self): 500 self.topContainer = ContainerAutoSize(name='topContainer', parent=self, align=uiconst.TOTOP) 501 self.CreateIcon() 502 self.CreateText() 503 504 def CreateIcon(self): 505 iconContainer = Container(parent=self.topContainer, align=uiconst.TOTOP, height=56) 506 self.actionIcon = Sprite(parent=iconContainer, align=uiconst.CENTER, state=uiconst.UI_DISABLED, texturePath=self.texturePath, height=56, width=56) 507 508 def CreateText(self): 509 self.actionLabelText = EveLabelMedium(parent=self.topContainer, align=uiconst.TOTOP, text=center(self.text), padding=(8, 0, 8, 0)) 510 511 def CreateBottomContainer(self): 512 self.bottomContainer = ContainerAutoSize(name='bottomContainer', parent=self, align=uiconst.TOBOTTOM) 513 uthread.new(self.UpdatePrice) 514 515 def UpdatePrice(self): 516 if callable(self.price): 517 price = self.price() 518 else: 519 price = self.price 520 if price: 521 if self.priceTag is None: 522 self._ConstructPriceTag(price) 523 else: 524 self.priceTag.UpdatePrice(price) 525 else: 526 self._RemovePriceTag() 527 if callable(self.onUpdate): 528 self.onUpdate() 529 530 def _ConstructPriceTag(self, price): 531 priceCont = Container(parent=self.bottomContainer, align=uiconst.TOTOP, height=30, padding=(0, 0, 0, 2)) 532 self.priceTag = PriceTagSmall(parent=priceCont, align=uiconst.CENTER, state=uiconst.UI_DISABLED, price=price, currency=OFFER_CURRENCY_PLEX) 533 534 def _RemovePriceTag(self): 535 if self.priceTag: 536 self.priceTag.Close() 537 self.priceTag = None 538 539 def OnClick(self, *args): 540 if self.enabled: 541 PlaySound(uiconst.SOUND_BUTTON_CLICK) 542 self.action() 543 544 def OnMouseEnter(self, *args): 545 if self.enabled: 546 PlaySound(uiconst.SOUND_BUTTON_HOVER) 547 548 def UpdateFrameColor(self): 549 if self.frame: 550 color = self.frameColor_enabled if self.enabled else self.frameColor_disabled 551 self.frame.SetRGBA(*color) 552 553 def Disable(self): 554 if self.enabled: 555 self.UpdateFrameColor() 556 self.actionIcon.color = self.disabled_color 557 self.actionLabelText.color = self.disabled_color 558 self.enabled = False 559 560 def Enable(self): 561 if not self.enabled: 562 self.UpdateFrameColor() 563 self.actionIcon.color = self.enabled_color 564 self.actionLabelText.color = self.enabled_color 565 self.enabled = True 566 567 def ResetSize(self): 568 self.topContainer.EnableAutoSize() 569 self.topContainer.DisableAutoSize() 570 self.bottomContainer.EnableAutoSize() 571 self.bottomContainer.DisableAutoSize() 572 self.height = self.topContainer.height + self.bottomContainer.height