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

costInfo.py (14727B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\cosmetics\ship\controls\costInfo.py
      2 import eveformat
      3 import eveicon
      4 import uthread2
      5 from carbonui import Align, PickState, TextColor, uiconst
      6 from carbonui.text.styles import TextHeader, TextBody, TextDetail
      7 from carbonui.control.button import Button, ButtonStyle
      8 from carbonui.primitives.container import Container
      9 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     10 from carbonui.primitives.fill import Fill
     11 from carbonui.primitives.layoutGrid import LayoutGrid
     12 from carbonui.primitives.sprite import Sprite
     13 from cosmetics.client.ships import ship_skin_signals
     14 from cosmetics.client.ships.skins.errors import NoTimeRemainingException
     15 from cosmetics.client.ships.skins.live_data import current_skin_design, current_skin_design_signals
     16 from cosmetics.client.shipSkinSequencingSvc import get_ship_skin_sequencing_svc
     17 from cosmetics.common.ships.skins.util import Currency
     18 from eve.client.script.ui import eveColor
     19 from eve.client.script.ui.control.itemIcon import ItemIcon
     20 from player_messaging.client.ui_message import message_player
     21 from eve.client.script.ui.control.warningIcon import WarningIcon
     22 from eve.client.script.ui.shared.neocom.wallet.buyMissingPlexDialog import BuyMissingPlexDialog
     23 from eve.client.script.ui.shared.neocom.wallet.walletWnd import WalletWindow
     24 from inventorycommon.const import typeLoyaltyPointsHeraldry
     25 from localization import GetByLabel
     26 from plex.client.api.repository import get_repository
     27 from publicGateway.grpc.exceptions import GenericException
     28 from stackless_response_router.exceptions import TimeoutException
     29 
     30 class CostInfo(ContainerAutoSize):
     31     default_display = False
     32     LEFT_WIDTH = 40
     33     SPACING = 4
     34 
     35     def __init__(self, cost = None, currency = None, discount = None, *args, **kwargs):
     36         super(CostInfo, self).__init__(*args, **kwargs)
     37         self._cost = cost
     38         self._discount = discount
     39         self._currency = currency
     40         self.construct_layout()
     41         self.update()
     42 
     43     def construct_layout(self):
     44         self.construct_header()
     45         self.construct_cost()
     46 
     47     def construct_header(self):
     48         header_container = Container(name='header_container', parent=self, align=Align.TOTOP, height=16)
     49         left_container = Container(parent=header_container, align=Align.TOLEFT, width=self.LEFT_WIDTH)
     50         Sprite(parent=left_container, texturePath='res:/UI/Texture/classes/Cosmetics/Ship/overlays/cost_info_corner.png', width=self.LEFT_WIDTH, height=16)
     51         right_container = Container(parent=header_container, align=Align.TOALL, padLeft=self.SPACING)
     52         Fill(parent=right_container, color=eveColor.WHITE, opacity=0.1)
     53         TextDetail(parent=right_container, align=Align.CENTERLEFT, text=self.cost_header_text, color=TextColor.SECONDARY, padLeft=8)
     54 
     55     def construct_cost(self):
     56         cost_container = Container(name='cost_container', parent=self, align=Align.TOTOP, height=32, padTop=self.SPACING)
     57         left_container = Container(parent=cost_container, align=Align.TOLEFT, width=self.LEFT_WIDTH)
     58         Fill(parent=left_container, color=eveColor.WHITE, opacity=0.1)
     59         self.construct_currency_icon(parent=left_container)
     60         self.right_container = Container(name='rightContainer', parent=cost_container, align=Align.TOALL, padLeft=self.SPACING)
     61         Fill(parent=self.right_container, color=eveColor.SMOKE_BLUE, opacity=0.2)
     62         self.layout_grid = LayoutGrid(parent=self.right_container, align=Align.CENTERLEFT, left=8, cellSpacing=8)
     63         self.cost_label = TextHeader(parent=self.layout_grid, align=Align.CENTERLEFT)
     64         self.discount_label = TextBody(parent=self.layout_grid, align=Align.CENTERLEFT, color=eveColor.SUCCESS_GREEN)
     65         warning_icon_container = Container(name='warning_icon_container', parent=self.right_container, align=Align.TOLEFT, width=16, padLeft=8)
     66         self.warning_icon = WarningIcon(name='warning_icon', parent=warning_icon_container, align=Align.CENTER, display=False, top=1)
     67 
     68     def construct_currency_icon(self, parent):
     69         self.currency_icon = Sprite(parent=parent, align=Align.CENTER, state=uiconst.UI_DISABLED, width=16, height=16)
     70 
     71     def update(self):
     72         self.display = self.cost is not None
     73         if self.cost is None:
     74             return
     75         if self.currency == Currency.PLEX:
     76             self.currency_icon.texturePath = eveicon.plex
     77             self.currency_icon.color = eveColor.PLEX_YELLOW
     78             self.cost_label.text = eveformat.number(self.cost, decimal_places=0)
     79             text_padding = 40
     80         elif self.currency == Currency.ISK:
     81             self.currency_icon.texturePath = eveicon.isk
     82             self.currency_icon.color = eveColor.WHITE
     83             self.cost_label.text = eveformat.number(self.cost)
     84             text_padding = 16
     85         self._update_discount_text()
     86         if self.cost:
     87             cost_header_text_width, _ = TextDetail.MeasureTextSize(self.cost_header_text)
     88             cost_amount_text_width, _ = TextHeader.MeasureTextSize(self.cost)
     89             discount_text_width, _ = TextBody.MeasureTextSize(self.discount_label.text)
     90             longest_text_width = max(cost_header_text_width, cost_amount_text_width + discount_text_width)
     91             desired_width = self.LEFT_WIDTH + self.SPACING + longest_text_width + text_padding
     92             self.width = max(self.minWidth, desired_width)
     93 
     94     def _update_discount_text(self):
     95         if self._discount:
     96             self.discount_label.text = GetByLabel('UI/Personalization/ShipSkins/SKINR/Studio/CostWithDiscount', discount_percentage=self._discount)
     97         else:
     98             self.discount_label.text = ''
     99 
    100     @property
    101     def cost_header_text(self):
    102         return GetByLabel('UI/Common/Cost')
    103 
    104     @property
    105     def cost(self):
    106         return self._cost
    107 
    108     @cost.setter
    109     def cost(self, value):
    110         if self._cost == value:
    111             return
    112         self._cost = value
    113         self.update()
    114 
    115     @property
    116     def currency(self):
    117         return self._currency
    118 
    119     @currency.setter
    120     def currency(self, value):
    121         if self._currency == value:
    122             return
    123         self._currency = value
    124         self.update()
    125 
    126     def set_cost(self, cost, discount = None):
    127         self._cost = cost
    128         self._discount = discount
    129         self.update()
    130 
    131 
    132 class SequencingJobCostInfo(CostInfo):
    133 
    134     def __init__(self, sequencing_job = None, *args, **kwargs):
    135         self._sequencing_job = sequencing_job
    136         self._update_thread = None
    137         super(SequencingJobCostInfo, self).__init__(currency=Currency.PLEX, *args, **kwargs)
    138 
    139     def Close(self):
    140         try:
    141             self.kill_update_thread()
    142         finally:
    143             super(SequencingJobCostInfo, self).Close()
    144 
    145     def kill_update_thread(self):
    146         if self._update_thread is not None:
    147             self._update_thread.kill()
    148             self._update_thread = None
    149 
    150     @property
    151     def sequencing_job(self):
    152         return self._sequencing_job
    153 
    154     @sequencing_job.setter
    155     def sequencing_job(self, value):
    156         self._sequencing_job = value
    157         self.update_sequencing_job()
    158 
    159     def update_sequencing_job(self):
    160         if self.sequencing_job:
    161             self.kill_update_thread()
    162             self._update_thread = uthread2.start_tasklet(self.update_sequencing_job_async)
    163         else:
    164             self.display = False
    165 
    166     def update_sequencing_job_async(self):
    167         try:
    168             try:
    169                 plex_cost = get_ship_skin_sequencing_svc().get_early_completion_cost(self.sequencing_job.job_id)
    170             except (GenericException, TimeoutException):
    171                 message_player(GetByLabel('UI/Common/CannotConnectToServer'))
    172                 plex_cost = None
    173 
    174             self.cost = plex_cost
    175             self.display = plex_cost is not None
    176         except NoTimeRemainingException:
    177             self.display = False
    178 
    179 
    180 class StudioCostInfo(CostInfo):
    181 
    182     def __init__(self, *args, **kwargs):
    183         super(StudioCostInfo, self).__init__(currency=Currency.PLEX, *args, **kwargs)
    184         self._update_thread = None
    185         self.connect_signals()
    186         self.update_cost_label()
    187 
    188     def Close(self):
    189         try:
    190             self.kill_update_thread()
    191             self.disconnect_signals()
    192         finally:
    193             super(StudioCostInfo, self).Close()
    194 
    195     def kill_update_thread(self):
    196         if self._update_thread:
    197             self._update_thread.kill()
    198             self._update_thread = None
    199 
    200     def connect_signals(self):
    201         current_skin_design_signals.on_design_reset.connect(self.on_design_reset)
    202         current_skin_design_signals.on_existing_design_loaded.connect(self.on_existing_design_loaded)
    203         current_skin_design_signals.on_ship_type_id_changed.connect(self.on_ship_type_id_changed)
    204         current_skin_design_signals.on_slot_fitting_changed.connect(self.on_slot_fitting_changed)
    205         ship_skin_signals.on_skin_sequencing_cache_invalidated.connect(self.on_skin_sequencing_cache_invalidated)
    206 
    207     def disconnect_signals(self):
    208         current_skin_design_signals.on_design_reset.disconnect(self.on_design_reset)
    209         current_skin_design_signals.on_existing_design_loaded.disconnect(self.on_existing_design_loaded)
    210         current_skin_design_signals.on_ship_type_id_changed.disconnect(self.on_ship_type_id_changed)
    211         current_skin_design_signals.on_slot_fitting_changed.disconnect(self.on_slot_fitting_changed)
    212         ship_skin_signals.on_skin_sequencing_cache_invalidated.disconnect(self.on_skin_sequencing_cache_invalidated)
    213 
    214     def update_cost_label(self):
    215         self.kill_update_thread()
    216         self._update_thread = uthread2.start_tasklet(self.update_cost_label_async)
    217 
    218     def update_cost_label_async(self):
    219         try:
    220             plex_cost, discount = get_ship_skin_sequencing_svc().get_sequencing_plex_price(design=current_skin_design.get(), nb_runs=1)
    221         except (GenericException, TimeoutException):
    222             message_player(GetByLabel('UI/Common/CannotConnectToServer'))
    223             plex_cost = None
    224             discount = None
    225 
    226         self.set_cost(plex_cost, discount)
    227         self.display = plex_cost is not None
    228 
    229     def on_design_reset(self, *args):
    230         self.update_cost_label()
    231 
    232     def on_existing_design_loaded(self, *args):
    233         self.update_cost_label()
    234 
    235     def on_ship_type_id_changed(self, *args):
    236         self.update_cost_label()
    237 
    238     def on_slot_fitting_changed(self, *args):
    239         self.update_cost_label()
    240 
    241     def on_skin_sequencing_cache_invalidated(self, *args):
    242         self.update_cost_label()
    243 
    244     @property
    245     def cost_header_text(self):
    246         return GetByLabel('UI/Personalization/ShipSkins/SKINR/Studio/CostPreviewDescription')
    247 
    248 
    249 class SequencingPanelCostInfo(CostInfo):
    250     default_state = uiconst.UI_NORMAL
    251 
    252     def update(self):
    253         super(SequencingPanelCostInfo, self).update()
    254         self.cost_label.rgba = eveColor.DANGER_RED if self.insufficient_balance else TextColor.HIGHLIGHT
    255         self.warning_icon.display = self.insufficient_balance
    256         self.layout_grid.left = 32 if self.insufficient_balance else 8
    257 
    258     @property
    259     def cost_header_text(self):
    260         return GetByLabel('UI/Personalization/ShipSkins/SKINR/Studio/TotalPLEXCost')
    261 
    262     @property
    263     def plex_balance(self):
    264         return get_repository().get_balance()
    265 
    266     @property
    267     def insufficient_balance(self):
    268         return self.cost > self.plex_balance
    269 
    270     def LoadTooltipPanel(self, tooltipPanel, *args):
    271         tooltipPanel.LoadStandardSpacing()
    272         tooltipPanel.columns = 1
    273         tooltipPanel.pickState = PickState.ON
    274         tooltipPanel.cellSpacing = (8, 16)
    275         if self.insufficient_balance:
    276             TextBody(parent=tooltipPanel, text=GetByLabel('UI/Personalization/ShipSkins/SKINR/Studio/InsufficientPLEX', plex_balance=int(self.plex_balance) or 0), maxWidth=220, align=Align.CENTERLEFT)
    277             Button(parent=tooltipPanel, label=GetByLabel('UI/Wallet/BuyMore'), func=self.on_buy_more_plex_button, style=ButtonStyle.MONETIZATION, align=Align.TOTOP)
    278         else:
    279             TextBody(parent=tooltipPanel, text=GetByLabel('UI/Personalization/ShipSkins/SKINR/Studio/PLEXBalance', plex_balance=int(self.plex_balance) or 0), maxWidth=220, align=Align.CENTERLEFT)
    280 
    281     def on_buy_more_plex_button(self, *args):
    282         buy_missing_plex_dialog = BuyMissingPlexDialog(required_amount=self.cost)
    283         buy_missing_plex_dialog.ShowModal()
    284 
    285     def GetTooltipPointer(self):
    286         return uiconst.POINT_RIGHT_2
    287 
    288 
    289 class BuyersFeeCostInfo(CostInfo):
    290     default_display = False
    291 
    292     def __init__(self, cost, listing, *args, **kwargs):
    293         self.listing = listing
    294         self._buyer_fee_amount = None
    295         super(BuyersFeeCostInfo, self).__init__(cost, *args, **kwargs)
    296 
    297     def construct_header(self):
    298         pass
    299 
    300     def construct_layout(self):
    301         super(BuyersFeeCostInfo, self).construct_layout()
    302         self.right_container.hint = GetByLabel('UI/Personalization/ShipSkins/SKINR/BuyersFeeHint')
    303 
    304     def construct_currency_icon(self, parent):
    305         self.currency_icon = ItemIcon(name='currency_icon', parent=parent, align=uiconst.CENTER, width=20, height=20, typeID=typeLoyaltyPointsHeraldry)
    306 
    307     def update(self):
    308         self.display = self.buyer_fee_amount is not None
    309         if self.buyer_fee_amount is None:
    310             return
    311         self.cost_label.text = eveformat.number(self.buyer_fee_amount)
    312         evermark_balance = sm.GetService('loyaltyPointsWalletSvc').GetCharacterEvermarkBalance()
    313         if self.listing.seller_id == session.charid:
    314             show_warning = False
    315         else:
    316             show_warning = evermark_balance < self.buyer_fee_amount
    317         if show_warning:
    318             self.cost_label.color = TextColor.DANGER
    319             self.warning_icon.display = True
    320             self.state = uiconst.UI_NORMAL
    321             self.hint = GetByLabel('UI/Personalization/ShipSkins/SKINR/Studio/ListingErrors/InsufficientFunds')
    322         else:
    323             self.cost_label.color = TextColor.NORMAL
    324             self.warning_icon.display = False
    325             self.state = uiconst.UI_PICKCHILDREN
    326             self.hint = None
    327         self.layout_grid.left = 32 if show_warning else 8
    328         additional_padding = 40 if show_warning else 16
    329         cost_amount_text_width, _ = TextHeader.MeasureTextSize(self.cost_label.text)
    330         desired_width = self.LEFT_WIDTH + self.SPACING + cost_amount_text_width + additional_padding
    331         self.width = max(self.minWidth, desired_width)
    332 
    333     @property
    334     def buyer_fee_amount(self):
    335         return self._buyer_fee_amount
    336 
    337     @buyer_fee_amount.setter
    338     def buyer_fee_amount(self, value):
    339         self._buyer_fee_amount = value
    340         self.update()