NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

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