shipSKINRWindow.py (15418B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\cosmetics\ship\shipSKINRWindow.py 2 import math 3 import eveicon 4 import evetypes 5 from carbonui import Align, Density, PickState, ButtonVariant 6 from carbonui.control.button import Button 7 from carbonui.control.dragdrop.dragdata import TypeDragData 8 from carbonui.primitives.container import Container 9 from carbonui.primitives.sprite import Sprite 10 from carbonui.uianimations import animations 11 from cosmetics.client.ships import ship_skin_signals 12 from cosmetics.client.ships.feature_flag import is_ship_skinr_feature_enabled 13 from cosmetics.client.ships.ship_skin_signals import on_skin_sequencing_job_failed 14 from cosmetics.client.ships.skins.errors import SEQUENCING_ERROR_TEXT_BY_CODE, SEQUENCE_FAILURE_REASON_TO_ERROR 15 from cosmetics.client.ships.skins.live_data import current_skin_design 16 from cosmetics.client.ships.qa.menus import is_qa, add_qa_context_menu 17 from cosmetics.common.ships.skins.static_data.slot_configuration import is_skinnable_ship 18 from eve.client.script.ui.control.floatingToggleButtonGroup import FloatingToggleButtonGroup 19 from player_messaging.client.ui_message import message_player 20 from eve.client.script.ui.cosmetics.ship.const import SkinrPage, ANIM_DURATION_LONG, PARENT_PAGE_BY_CHILD_PAGE, CHILD_PAGES_BY_PARENT_PAGE 21 from eve.client.script.ui.cosmetics.ship.pages.store import storeSettings 22 from eve.client.script.ui.cosmetics.ship.pages.store.storePage import StorePage 23 from eve.client.script.ui.cosmetics.ship.pages.collection.collectionPage import CollectionPage 24 from eve.client.script.ui.cosmetics.ship.pages.studio import studioSignals 25 from eve.client.script.ui.cosmetics.ship import skinrSignals 26 from eve.client.script.ui.cosmetics.ship.pages import current_page 27 from eve.client.script.ui.cosmetics.ship.pages.studio.studioPageContainer import StudioPageContainer 28 from eve.client.script.ui.cosmetics.ship.pages.studio.skinrBackgroundContainer import SKINRBackgroundContainer 29 from eve.client.script.ui.shared.mapView.dockPanel import DockablePanel, BUTTON_FULLSCREEN, BUTTON_FLOAT 30 from eve.client.script.ui.view.viewStateConst import ViewState 31 import eve.client.script.ui.shared.pointerTool.pointerToolConst as pConst 32 from localization import GetByLabel 33 from logging import getLogger 34 CAMERA_PITCH = 4 * math.pi / 10 35 logger = getLogger(__name__) 36 37 class ShipSKINRWindow(DockablePanel): 38 default_apply_content_padding = False 39 default_captionLabelPath = 'UI/Personalization/ShipSkins/SKINR/Title' 40 default_descriptionLabelPath = 'UI/Personalization/ShipSkins/SKINR/Description' 41 default_iconNum = 'res:/UI/Texture/WindowIcons/paint_tool.png' 42 default_minSize = (1024, 700) 43 default_windowID = 'ShipSKINRWindow' 44 default_analyticID = 'ship_skinr' 45 dock_options = (BUTTON_FULLSCREEN, BUTTON_FLOAT) 46 panelID = default_windowID 47 viewState = ViewState.ShipSKINR 48 __notifyevents__ = DockablePanel.__notifyevents__ + ['OnHideUI', 'OnShowUI'] 49 50 def __init__(self, page_id = SkinrPage.STUDIO, page_args = None, saved_skin_design_id = None, **kwargs): 51 super(ShipSKINRWindow, self).__init__(**kwargs) 52 self.is_closing = False 53 self.scene_preview_panel = None 54 self.initialize_skin_design(saved_skin_design_id) 55 self.construct_layout() 56 self.connect_signals() 57 self.select_initial_tab(page_id) 58 current_page.set_page_id(page_id, page_args=page_args, animate=False) 59 60 @classmethod 61 def open_external_design(cls, character_id, design_id): 62 if design_id is not None: 63 window = ShipSKINRWindow.Open() 64 if window.IsMinimized(): 65 window.Maximize() 66 window.select_initial_tab(SkinrPage.STUDIO) 67 current_page_id = current_page.get_page_id() 68 if current_page_id is not None and current_page_id == SkinrPage.STUDIO_DESIGNER and current_skin_design.get().saved_skin_design_id == design_id: 69 return 70 can_leave_current_page = current_page.set_page_id(SkinrPage.STUDIO) 71 if can_leave_current_page: 72 current_skin_design.open_existing_saved_design(design_id) 73 current_page.set_page_id(SkinrPage.STUDIO_DESIGNER, page_args=design_id) 74 75 @classmethod 76 def open_external_skin_listing(cls, skin_listing = None): 77 if skin_listing is None: 78 message_player(GetByLabel('UI/Personalization/ShipSkins/SKINR/Studio/ListingErrors/ListingNotFound')) 79 return 80 window = ShipSKINRWindow.Open() 81 if window.IsMinimized(): 82 window.Maximize() 83 current = current_page.get_page_id() 84 if current != SkinrPage.STORE_SKINS: 85 if not current_page.set_page_id(SkinrPage.STORE_SKINS): 86 return 87 window.select_initial_tab(SkinrPage.STORE_SKINS) 88 window.store_page.show_skin(skin_listing) 89 90 @classmethod 91 def open_on_paragon_hub(cls, ship_type_id = None): 92 if ship_type_id: 93 storeSettings.emphasized_ship_type_id.set(ship_type_id) 94 wnd = cls.GetIfOpen() 95 if wnd: 96 current_page.set_page_id(page_id=SkinrPage.STORE_SKINS) 97 wnd.Maximize() 98 else: 99 cls.Open(page_id=SkinrPage.STORE_SKINS) 100 101 @classmethod 102 def Open(cls, *args, **kwds): 103 if not is_ship_skinr_feature_enabled(): 104 message_player(GetByLabel('UI/Personalization/ShipSkins/SKINR/Studio/ShipSKINRUnavailable')) 105 return 106 else: 107 return super(ShipSKINRWindow, cls).Open(*args, **kwds) 108 109 def initialize_skin_design(self, saved_skin_design_id): 110 current_page.reset_history() 111 if saved_skin_design_id: 112 current_skin_design.open_existing_saved_design(saved_skin_design_id) 113 else: 114 current_skin_design.create_blank_design() 115 active_ship_type_id = current_skin_design.get_active_ship_type_id() 116 if not is_skinnable_ship(active_ship_type_id): 117 message_player(GetByLabel('UI/Personalization/ShipSkins/SKINR/Studio/ActiveShipDoesNotSupportSKINs', shipName=evetypes.GetName(active_ship_type_id))) 118 119 def connect_signals(self): 120 if self.scene_preview_panel: 121 self.scene_preview_panel.sceneNavigation.on_drop_data.connect(self.on_scene_preview_panel_drop_data) 122 self.on_size_changed.connect(self._on_size_changed) 123 studioSignals.on_page_opened.connect(self.on_page_opened) 124 on_skin_sequencing_job_failed.connect(self._on_skin_sequencing_job_failed) 125 ship_skin_signals.on_ship_skinr_feature_availability_changed.connect(self.on_ship_skinr_feature_availability_changed) 126 127 def disconnect_signals(self): 128 if self.scene_preview_panel: 129 self.scene_preview_panel.sceneNavigation.on_drop_data.disconnect(self.on_scene_preview_panel_drop_data) 130 self.on_size_changed.disconnect(self._on_size_changed) 131 studioSignals.on_page_opened.disconnect(self.on_page_opened) 132 on_skin_sequencing_job_failed.disconnect(self._on_skin_sequencing_job_failed) 133 ship_skin_signals.on_ship_skinr_feature_availability_changed.disconnect(self.on_ship_skinr_feature_availability_changed) 134 135 def on_ship_skinr_feature_availability_changed(self, *args): 136 if not is_ship_skinr_feature_enabled(): 137 message_player(GetByLabel('UI/Personalization/ShipSkins/SKINR/Studio/ShipSKINRUnavailable')) 138 self.Close() 139 140 def on_page_opened(self, page_id, page_args, last_page_id, animate = True): 141 self.load_page(page_id, page_args) 142 self.update_camera_offset(animate) 143 self.update_camera_yaw_and_pitch(page_id) 144 self.back_btn.display = current_page.is_back_enabled() 145 146 def update_camera_yaw_and_pitch(self, page_id): 147 if self.scene_preview_panel: 148 self.scene_preview_panel.turn_camera(yaw=current_page.get_camera_yaw(), pitch=CAMERA_PITCH, duration=ANIM_DURATION_LONG) 149 150 def _on_size_changed(self, width, height): 151 self.update_camera_offset(animate=False) 152 153 def on_scene_preview_panel_drop_data(self, drag_source, drag_data): 154 if isinstance(drag_data[0], TypeDragData): 155 type_id = drag_data[0].typeID 156 if is_skinnable_ship(type_id): 157 current_skin_design.get().ship_type_id = type_id 158 drag_source.data.GetRootNode().DeselectAll() 159 drag_source.SetSelected() 160 161 def update_camera_offset(self, animate = True): 162 if not self.scene_preview_panel: 163 return 164 offset = self.GetPageModelAnchor(current_page.get_page_id()) 165 if animate: 166 if self.scene_preview_panel.camera_offset is not None: 167 animations.MorphScalar(self.scene_preview_panel, 'camera_offset', self.scene_preview_panel.camera_offset, offset, duration=ANIM_DURATION_LONG) 168 else: 169 self.scene_preview_panel.camera_offset = offset 170 171 def construct_layout(self): 172 self.construct_logo() 173 self.construct_tab_group() 174 self.construct_back_btn() 175 self.construct_pages() 176 self.construct_scene() 177 178 def construct_back_btn(self): 179 self.back_btn = Button(name='back_btn', parent=self.content, align=Align.TOPLEFT, pos=(32, 128, 0, 0), texturePath=eveicon.caret_left, func=self.on_back_btn, label=GetByLabel('UI/Commands/Back'), density=Density.EXPANDED, display=False, pickState=PickState.ON, variant=ButtonVariant.GHOST) 180 181 def on_back_btn(self, *args): 182 current_page.go_back() 183 184 def Close(self, setClosed = False, *args, **kwds): 185 try: 186 self.disconnect_signals() 187 storeSettings.emphasized_ship_type_id.set(0) 188 finally: 189 return super(ShipSKINRWindow, self).Close(setClosed, *args, **kwds) 190 191 def construct_logo(self): 192 Sprite(name='paragon_logo', parent=self.content, align=Align.TOPRIGHT, texturePath='res:/UI/Texture/classes/Cosmetics/Ship/paragon_logo.png', pos=(20, 193 self.toolbarContainer.height + 20, 194 90, 195 71)) 196 197 def construct_tab_group(self): 198 self.toggle_btn_group = FloatingToggleButtonGroup(name='toggle_btn_group', parent=self.content, padTop=self.toolbarContainer.height, padLeft=16, align=Align.TOPLEFT, padding=0, pos=(32, 64, 460, 32), callback=self.on_toggle_btn_group) 199 200 def on_toggle_btn_group(self, page_id, old_panel_id): 201 if not current_page.set_page_id(page_id): 202 self.toggle_btn_group.SetSelected(old_panel_id, animate=False) 203 204 def select_initial_tab(self, page_id): 205 page_id = PARENT_PAGE_BY_CHILD_PAGE.get(page_id, page_id) 206 self.toggle_btn_group.SetSelected(page_id, animate=False) 207 208 def GetPageModelAnchor(self, page_id): 209 if page_id == SkinrPage.STUDIO: 210 return self.studio_page.home_page.GetModelAnchor(self.scene_preview_panel) 211 elif page_id == SkinrPage.COLLECTION or page_id in CHILD_PAGES_BY_PARENT_PAGE[SkinrPage.COLLECTION]: 212 return self.collection_page.GetModelAnchor(self.scene_preview_panel) 213 elif page_id == SkinrPage.STORE or page_id in CHILD_PAGES_BY_PARENT_PAGE[SkinrPage.STORE]: 214 return self.store_page.GetModelAnchor(self.scene_preview_panel) 215 else: 216 return 0 217 218 def load_page(self, page_id, page_args = None, **kwargs): 219 if page_id == SkinrPage.STUDIO or page_id in CHILD_PAGES_BY_PARENT_PAGE[SkinrPage.STUDIO]: 220 self.load_studio_page(page_id, page_args, **kwargs) 221 elif page_id == SkinrPage.COLLECTION or page_id in CHILD_PAGES_BY_PARENT_PAGE[SkinrPage.COLLECTION]: 222 self.load_collection_page(page_id, page_args, **kwargs) 223 elif page_id == SkinrPage.STORE or page_id in CHILD_PAGES_BY_PARENT_PAGE[SkinrPage.STORE]: 224 self.load_store_page(page_id, page_args, **kwargs) 225 226 def load_studio_page(self, page_id, page_args = None, **kwargs): 227 self.store_page.display = self.collection_page.display = False 228 self.studio_page.display = True 229 self.studio_page.load_panel(page_id, page_args) 230 self.toggle_btn_group.SetSelected(SkinrPage.STUDIO) 231 232 def load_store_page(self, page_id, page_args = None, **kwargs): 233 self.collection_page.display = self.studio_page.display = False 234 self.store_page.display = True 235 self.store_page.load_panel(page_id, page_args) 236 self.toggle_btn_group.SetSelected(SkinrPage.STORE) 237 238 def load_collection_page(self, page_id, page_args, **kwargs): 239 self.store_page.display = self.studio_page.display = False 240 self.collection_page.display = True 241 self.collection_page.load_panel(page_id, page_args) 242 self.toggle_btn_group.SetSelected(SkinrPage.COLLECTION) 243 244 def construct_pages(self): 245 self.page_container = Container(name='page_container', parent=self.content, clipChildren=True) 246 self.construct_studio_page(parent=self.page_container) 247 self.construct_store_page(parent=self.page_container) 248 self.construct_collection_page(parent=self.page_container) 249 250 def construct_scene(self): 251 try: 252 self.scene_preview_panel = SKINRBackgroundContainer(name='preview_panel', parent=self.content) 253 except Exception as exc: 254 logger.exception('Failed to construct scene preview panel in SKINR: %s', exc) 255 256 def construct_studio_page(self, parent): 257 self.studio_page = StudioPageContainer(name='studio_page', parent=parent) 258 self.toggle_btn_group.AddButton(label=GetByLabel('UI/Personalization/ShipSkins/SKINR/Studio/Title'), btnID=SkinrPage.STUDIO, uniqueUiName=pConst.UNIQUE_NAME_SKINR_STUDIO) 259 260 def construct_store_page(self, parent): 261 self.store_page = StorePage(name='store_page', parent=parent) 262 self.toggle_btn_group.AddButton(label=GetByLabel('UI/Personalization/ShipSkins/SKINR/Store/Title'), btnID=SkinrPage.STORE, uniqueUiName=pConst.UNIQUE_NAME_SKINR_PARAGON_HUB) 263 264 def construct_collection_page(self, parent): 265 self.collection_page = CollectionPage(name='collection_page', parent=parent) 266 self.toggle_btn_group.AddButton(label=GetByLabel('UI/Personalization/ShipSkins/SKINR/Collection/Title'), btnID=SkinrPage.COLLECTION, uniqueUiName=pConst.UNIQUE_NAME_SKINR_COLLECTION) 267 268 def OnBack(self): 269 current_page.go_back() 270 271 def OnForward(self): 272 current_page.go_forward() 273 274 def GetMenu(self): 275 menu = super(ShipSKINRWindow, self).GetMenu() 276 if is_qa(): 277 add_qa_context_menu(menu) 278 return menu 279 280 def OnHideUI(self): 281 self.page_container.display = False 282 283 def OnShowUI(self): 284 self.page_container.display = True 285 286 def CloseByUser(self, *args): 287 try: 288 if self.is_closing: 289 return 290 self.is_closing = True 291 if current_page.can_leave_current_page(): 292 super(ShipSKINRWindow, self).CloseByUser(*args) 293 else: 294 self.is_closing = False 295 except: 296 super(ShipSKINRWindow, self).CloseByUser(*args) 297 raise 298 299 def _on_skin_sequencing_job_failed(self, _job_id, reason): 300 if reason in SEQUENCE_FAILURE_REASON_TO_ERROR: 301 error = SEQUENCE_FAILURE_REASON_TO_ERROR[reason] 302 if error in SEQUENCING_ERROR_TEXT_BY_CODE: 303 label = SEQUENCING_ERROR_TEXT_BY_CODE[error] 304 message_player(GetByLabel(label))