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

componentLicenseEntry.py (15625B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\cosmetics\ship\pages\studio\componentLicenseEntry.py
      2 import blue
      3 import carbonui.text.styles
      4 import gametime
      5 from carbonui.uiconst import OutputMode
      6 import carbonui
      7 import evetypes
      8 from carbon.common.script.sys.serviceConst import ROLE_GML
      9 from carbonui import Align, uiconst, PickState, SpriteEffect
     10 from carbonui.control.contextMenu.menuData import MenuData
     11 from carbonui.primitives.container import Container
     12 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     13 from carbonui.primitives.fill import Fill
     14 from carbonui.primitives.frame import Frame
     15 from carbonui.primitives.layoutGrid import LayoutGrid
     16 from carbonui.primitives.sprite import Sprite
     17 from carbonui.uianimations import animations
     18 from cosmetics.client.shipSkinComponentSvc import get_ship_skin_component_svc
     19 from cosmetics.client.ships.skins.live_data import current_skin_design, current_skin_design_signals
     20 from cosmetics.client.ships.skins.static_data import rarity_icon
     21 from cosmetics.common.ships.skins.static_data.component import projection_type_to_fsd
     22 from cosmetics.common.ships.skins.static_data.component_category import ComponentCategory
     23 from cosmetics.common.ships.skins.static_data.slot_name import SlotID, PATTERN_MATERIAL_SLOT_ID_BY_PATTERN_ID, PATTERN_SLOT_IDS
     24 from eve.client.script.ui import eveThemeColor, eveColor
     25 from player_messaging.client.ui_message import message_player
     26 from eve.client.script.ui.control.tooltips import TooltipPanel
     27 from eve.client.script.ui.cosmetics.ship.controls.rarityIndicator import RarityIndicator
     28 from eveservices.menu import GetMenuService
     29 from localization import GetByLabel
     30 from publicGateway.grpc.exceptions import GenericException
     31 from stackless_response_router.exceptions import TimeoutException
     32 ICON_SIZE = 48
     33 TOOLTIP_ICON_SIZE = 128
     34 PADDING = 14
     35 
     36 def get_anim_time_offset(duration):
     37     seconds = gametime.GetWallclockTimeNow() / float(gametime.SEC)
     38     return duration - seconds % duration
     39 
     40 
     41 brightness_blink_curve = ((0.0, 0.0),
     42  (2 / 7.0, 1.5),
     43  (4 / 7.0, 1.5),
     44  (6 / 7.0, 0.0),
     45  (1.0, 0.0))
     46 
     47 class ComponentEntry(Container):
     48     default_width = ICON_SIZE + PADDING
     49     default_height = ICON_SIZE + PADDING
     50     default_state = uiconst.UI_NORMAL
     51 
     52     def __init__(self, component_data, slot_id, is_selected, limited_license = None, unlimited_license = None, *args, **kwargs):
     53         super(ComponentEntry, self).__init__(*args, **kwargs)
     54         self.limited_license = limited_license
     55         self.unlimited_license = unlimited_license
     56         self.slot_id = slot_id
     57         self._is_selected = is_selected
     58         self.component_data = component_data
     59         self.is_new = False
     60         self.is_animating = False
     61         self.construct_layout()
     62         self.connect_signals()
     63 
     64     def Close(self):
     65         try:
     66             self.disconnect_signals()
     67         finally:
     68             super(ComponentEntry, self).Close()
     69 
     70     def connect_signals(self):
     71         current_skin_design_signals.on_slot_fitting_changed.connect(self.on_slot_fitting_changed)
     72         current_skin_design_signals.on_pattern_blend_mode_changed.connect(self.on_blend_mode_changed)
     73 
     74     def disconnect_signals(self):
     75         current_skin_design_signals.on_slot_fitting_changed.disconnect(self.on_slot_fitting_changed)
     76         current_skin_design_signals.on_pattern_blend_mode_changed.disconnect(self.on_blend_mode_changed)
     77 
     78     def on_blend_mode_changed(self, *args):
     79         self._check_fit_default_pattern_material()
     80 
     81     def construct_layout(self):
     82         self.construct_icon()
     83         self.construct_selection_frame()
     84         self.check_construct_not_owned_frame()
     85         self.update()
     86 
     87     def check_construct_not_owned_frame(self):
     88         if not self.limited_license and not self.unlimited_license:
     89             self.not_owned_frame = Sprite(name='not_owned_frame', parent=self, texturePath='res:/UI/Texture/classes/Cosmetics/Ship/circle_frame_bg.png', color=eveColor.WHITE, opacity=0.2, align=Align.TOALL, pickState=PickState.OFF)
     90 
     91     def construct_icon(self):
     92         if self.is_pattern():
     93             size = ICON_SIZE - 2
     94         else:
     95             size = ICON_SIZE
     96         self.icon = Sprite(name='icon', parent=self, align=Align.CENTER, state=uiconst.UI_DISABLED, texturePath=self.component_data.icon_file_path, textureSecondaryPath=self.icon_mask_texture, spriteEffect=SpriteEffect.MASK, pos=(0,
     97          0,
     98          size,
     99          size))
    100 
    101     def construct_selection_frame(self):
    102         self.selection_frame = Sprite(name='selection_frame', parent=self, texturePath='res:/UI/Texture/Classes/Cosmetics/Ship/circle_frame.png', align=Align.TOALL, pickState=PickState.OFF, glowBrightness=0.0)
    103 
    104     def update(self):
    105         self.is_new = get_ship_skin_component_svc().is_component_new(self.component_data.component_id)
    106         if self.is_selected and self.is_new:
    107             get_ship_skin_component_svc().set_component_is_new_flag(self.component_data.component_id, False)
    108             self.is_new = False
    109         self.selection_frame.display = self.is_selected or self.is_new
    110         if self.is_new:
    111             self.selection_frame.color = eveColor.DUSKY_ORANGE
    112             self.selection_frame.outputMode = uiconst.OUTPUT_COLOR_AND_GLOW
    113         else:
    114             self.selection_frame.color = eveThemeColor.THEME_ACCENT
    115             self.selection_frame.outputMode = self.selection_frame.default_outputMode
    116         if self.is_new:
    117             if not self.is_animating:
    118                 self.start_new_highlight_animation()
    119         else:
    120             self.stop_new_highlight_animation()
    121 
    122     def start_new_highlight_animation(self):
    123         self.is_animating = True
    124         animations.MorphScalar(obj=self.selection_frame, attrName='glowBrightness', duration=2.5, loops=uiconst.ANIM_REPEAT, curveType=brightness_blink_curve, timeOffset=get_anim_time_offset(2.5))
    125 
    126     def on_new_highlight_animation_out_complete(self, *args):
    127         if self.is_new:
    128             self.start_new_highlight_animation()
    129 
    130     def stop_new_highlight_animation(self):
    131         animations.StopAnimation(self.selection_frame, 'glowBrightness')
    132         self.selection_frame.glowBrightness = 0.0
    133         self.is_animating = False
    134 
    135     def on_slot_fitting_changed(self, slot_id, component_instance):
    136         if slot_id != self.slot_id:
    137             return
    138         self.is_selected = component_instance and component_instance.component_id == self.component_data.component_id
    139 
    140     def OnClick(self, *args):
    141         get_ship_skin_component_svc().set_component_is_new_flag(self.component_data.component_id, False)
    142         if self.slot_id in (SlotID.PATTERN_MATERIAL, SlotID.SECONDARY_PATTERN_MATERIAL):
    143             if not self.is_selected:
    144                 self.set_selected()
    145                 current_skin_design.add_to_undo_history()
    146         else:
    147             self.toggle_selected()
    148             current_skin_design.add_to_undo_history()
    149 
    150     def is_pattern(self):
    151         return self.slot_id in PATTERN_SLOT_IDS
    152 
    153     def toggle_selected(self):
    154         if self.is_selected:
    155             self.set_deselected()
    156         else:
    157             self.set_selected()
    158 
    159     def set_selected(self):
    160         current_skin_design.get().fit_slot(self.slot_id, self.component_data.component_id, None)
    161         if self.is_pattern():
    162             self._check_fit_default_pattern_material()
    163 
    164     def set_deselected(self):
    165         current_skin_design.get().fit_slot(self.slot_id, None)
    166 
    167     def _check_fit_default_pattern_material(self):
    168         material_slot_id = PATTERN_MATERIAL_SLOT_ID_BY_PATTERN_ID.get(self.slot_id, None)
    169         if not material_slot_id or current_skin_design.get().get_fitted_component_instance(material_slot_id):
    170             return
    171         if not current_skin_design.get().get_fitted_component_instance(self.slot_id):
    172             return
    173         try:
    174             component_license = get_ship_skin_component_svc().get_random_component_license(material_slot_id)
    175             if component_license:
    176                 current_skin_design.get().fit_slot(material_slot_id, component_license.component_id, component_license)
    177         except (GenericException, TimeoutException):
    178             message_player(GetByLabel('UI/Common/CannotConnectToServer'))
    179 
    180     @property
    181     def is_selected(self):
    182         return self._is_selected
    183 
    184     @is_selected.setter
    185     def is_selected(self, value):
    186         self._is_selected = value
    187         self.update()
    188 
    189     def ConstructTooltipPanel(self):
    190         return ComponentEntryTooltipPanel(self.component_data, self.icon_mask_texture)
    191 
    192     @property
    193     def icon_mask_texture(self):
    194         if self.is_pattern():
    195             return 'res:/UI/Texture/circle_full.png'
    196         else:
    197             return 'res:/UI/Texture/classes/Cosmetics/Ship/pages/studio/nanocoating_mask.png'
    198 
    199     def GetMenu(self):
    200         m = MenuData()
    201         for type_id in self.component_data.component_item_data_by_type_id.keys():
    202             m.AddEntry(evetypes.GetName(type_id), subMenuData=GetMenuService().GetMenuFromItemIDTypeID(itemID=None, typeID=type_id, includeMarketDetails=True))
    203 
    204         if session.role & ROLE_GML:
    205             m.AddEntry('QA:', subMenuData=self.get_qa_menu())
    206         return m
    207 
    208     def get_qa_menu(self):
    209         m = MenuData()
    210         m.AddEntry(text='component_id: {}'.format(self.component_data.component_id), func=lambda *x: blue.pyos.SetClipboardData(str(self.component_data.component_id)))
    211         m.AddEntry(text='icon_path: {}'.format(self.component_data.icon_file_path), func=lambda *x: blue.pyos.SetClipboardData(str(self.component_data.icon_file_path)))
    212         import webbrowser
    213         m.AddEntry(text='Show in FSD editor', func=lambda : webbrowser.open_new('http://localhost:8000/cfsd/projects/cosmetic/ship_skin_design_components/ship_skin_design_components/{}/edit/'.format(self.component_data.component_id)))
    214         for license in (self.limited_license, self.unlimited_license):
    215             if not license:
    216                 continue
    217             m.AddEntry(text='license_type: {}'.format(license.license_type), func=lambda *x: blue.pyos.SetClipboardData(str(license.license_type)))
    218             component_type_id = None
    219             for type_id, data in self.component_data.component_item_data_by_type_id.items():
    220                 if data.license_type == license.license_type:
    221                     component_type_id = type_id
    222                     break
    223 
    224             m.AddEntry(text='type_id: {}'.format(component_type_id), func=lambda *x: blue.pyos.SetClipboardData(str(component_type_id)))
    225 
    226         m.AddEntry(text='Points Value: %s' % self.component_data.points_value)
    227         if self.component_data.projection_type_uv:
    228             u_fmt = projection_type_to_fsd(self.component_data.projection_type_uv[0])
    229             v_fmt = projection_type_to_fsd(self.component_data.projection_type_uv[1])
    230             m.AddEntry('Projection Type U: %s' % u_fmt)
    231             m.AddEntry('Projection Type V: %s' % v_fmt)
    232         return m
    233 
    234 
    235 class TooltipCard(Container):
    236     default_width = 130
    237     default_height = 135
    238 
    239     def __init__(self, component_data, **kw):
    240         super(TooltipCard, self).__init__(**kw)
    241         self.construct_icon(component_data)
    242         self.construct_background()
    243 
    244     def construct_icon(self, component_data):
    245         icon_cont = Container(parent=self, align=Align.CENTERTOP, pos=(0, 12, 94, 94))
    246         if component_data.category == ComponentCategory.PATTERN:
    247             Sprite(parent=icon_cont, align=Align.CENTER, state=uiconst.UI_DISABLED, texturePath=component_data.icon_file_path, pos=(0, 0, 80, 80))
    248             Fill(parent=icon_cont, align=Align.CENTER, state=uiconst.UI_DISABLED, color=eveThemeColor.THEME_TINT, opacity=0.5, pos=(0, 0, 92, 92))
    249         else:
    250             Sprite(parent=icon_cont, align=Align.CENTER, state=uiconst.UI_DISABLED, texturePath=component_data.icon_file_path, textureSecondaryPath='res:/UI/Texture/classes/Cosmetics/Ship/pages/studio/nanocoating_mask.png', spriteEffect=SpriteEffect.MASK, pos=(0, 0, 80, 80))
    251             Sprite(parent=icon_cont, align=Align.CENTER, state=uiconst.UI_DISABLED, texturePath='res:/UI/Texture/circle_full.png', color=eveThemeColor.THEME_TINT, opacity=0.5, pos=(0, 0, 92, 92))
    252 
    253     def construct_background(self):
    254         Sprite(parent=self, align=Align.HORIZONTALLY_CENTERED, width=120, texturePath='res:/UI/Texture/classes/Cosmetics/Ship/Cards/Tooltip/outline.png', color=eveColor.WHITE, opacity=0.2)
    255         Sprite(parent=self, align=Align.HORIZONTALLY_CENTERED, width=130, texturePath='res:/UI/Texture/classes/Cosmetics/Ship/Cards/Tooltip/bg_overlay.png', color=eveThemeColor.THEME_FOCUSDARK, opacity=0.3)
    256         Sprite(parent=self, align=Align.HORIZONTALLY_CENTERED, width=120, texturePath='res:/UI/Texture/classes/Cosmetics/Ship/Cards/Tooltip/bg_fill.png', color=eveColor.BLACK, opacity=0.9)
    257 
    258 
    259 class ComponentEntryTooltipPanel(TooltipPanel):
    260     default_margin = 0
    261     default_cellPadding = 0
    262     default_cellSpacing = (0, 4)
    263 
    264     def __init__(self, component_data, icon_mask_texture, **kw):
    265         super(ComponentEntryTooltipPanel, self).__init__(**kw)
    266         self.columns = 1
    267         self.construct_header(component_data)
    268         TooltipCard(parent=self, component_data=component_data, align=Align.CENTER, pickState=PickState.OFF)
    269         self.SetBackgroundAlpha(0.0)
    270 
    271     def construct_header(self, component_data):
    272         layout_grid = LayoutGrid(parent=self, columns=1, align=Align.CENTERTOP, cellSpacing=(8, 8), margin=(16, 16, 16, 8))
    273         license = get_ship_skin_component_svc().get_default_license_to_use(component_data.component_id, component_data.category)
    274         is_new = get_ship_skin_component_svc().is_component_new(component_data.component_id)
    275         if not license:
    276             carbonui.text.styles.TextBody(parent=layout_grid, text=GetByLabel('UI/Personalization/ShipSkins/SKINR/NotInYourCollection'), color=eveColor.HOT_RED)
    277         elif is_new:
    278             carbonui.text.styles.TextBody(parent=layout_grid, text=GetByLabel('UI/Personalization/ShipSkins/SKINR/Studio/NewInYourCollection'), color=eveColor.DUSKY_ORANGE)
    279         carbonui.text.styles.TextHeader(parent=layout_grid, text=component_data.name, maxWidth=160)
    280         rarity_cont = ContainerAutoSize(parent=layout_grid)
    281         RarityIndicator(parent=rarity_cont, rarity=component_data.rarity, align=Align.CENTERLEFT)
    282         carbonui.text.styles.TextBody(parent=rarity_cont, align=Align.CENTERLEFT, left=40, text=GetByLabel('UI/Personalization/ShipSkins/SKINR/RarityName', rarity=GetByLabel(rarity_icon.get_name(component_data.rarity))), wrapWidth=300)
    283         if is_new:
    284             frame = Frame(bgParent=layout_grid, align=Align.HORIZONTALLY_CENTERED, width=120, texturePath='res:/UI/Texture/classes/Cosmetics/Ship/Cards/Tooltip/frame_textbox.png', color=eveColor.DUSKY_ORANGE, opacity=1.0, outputMode=OutputMode.COLOR_AND_GLOW, glowBrightness=0.0, cornerSize=16)
    285             animations.MorphScalar(obj=frame, attrName='glowBrightness', duration=2.5, curveType=brightness_blink_curve, loops=uiconst.ANIM_REPEAT, timeOffset=get_anim_time_offset(2.5))
    286         else:
    287             Frame(bgParent=layout_grid, align=Align.HORIZONTALLY_CENTERED, width=120, texturePath='res:/UI/Texture/classes/Cosmetics/Ship/Cards/Tooltip/frame_textbox.png', color=eveColor.WHITE, opacity=0.2, cornerSize=16)
    288         Frame(bgParent=layout_grid, texturePath='res:/UI/Texture/classes/Cosmetics/Ship/Cards/Tooltip/bg_textbox.png', color=eveThemeColor.THEME_FOCUSDARK, opacity=0.2, cornerSize=16)
    289         Frame(bgParent=layout_grid, texturePath='res:/UI/Texture/classes/Cosmetics/Ship/Cards/Tooltip/bg_textbox.png', color=eveColor.BLACK, opacity=0.9, cornerSize=16)