shipInfoWindow.py (38418B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\info\shipInfoWindow.py 2 import eveicon 3 import evetypes 4 import localization 5 import uthread 6 import uthread2 7 import trinity 8 from eve.client.script.ui.shared.skins.controller import ShipInfoSkinPanelController 9 from eveservices.menu import GetMenuService 10 import eveui 11 from eveui import CharacterPortrait 12 from carbon.common.script.sys.serviceConst import ROLE_QA 13 from carbonui import uiconst, Align, PickState, TextColor 14 from carbonui.text.styles import TextBody, TextDetail 15 from carbonui.control.dragdrop.dragdata import ShipDragData 16 from carbonui.control.sideNavigation import SideNavigationSplitView, SideNavigation, SideNavigationEntry, SideNavigationEntryInterface 17 from carbonui.primitives.container import Container 18 from carbonui.primitives.containerAutoSize import ContainerAutoSize 19 from carbonui.primitives.fill import Fill 20 from carbonui.primitives.frame import Frame 21 from carbonui.primitives.sprite import Sprite 22 from clientsettings.setting import SessionSettingBool, SessionSettingEnum 23 from carbonui.uianimations import animations 24 from carbonui.window.control.action import WindowMenuAction, WindowActionImportance 25 from eve.client.script.ui import eveColor, eveThemeColor 26 from eve.client.script.ui.control.scenecontainer import SceneContainerBaseNavigation 27 from eve.client.script.ui.services.menuSvcExtras.openFunctions import SimulateFitting 28 from eve.client.script.ui.shared.fittingScreen.tryFit import GetParentShipInfo 29 from eve.client.script.ui.shared.info.baseInfoWindow import BaseInfoWindow 30 from eve.client.script.ui.shared.info.shipInfoConst import GetAnimDuration, TOP_DOWN_NOSE_UP_ALT, get_sound_by_type_id, GetMassBasedSoundOffset, INFO_TABS, FULLY_MINIMIZED, MINIMIZED, EXPANDED, CONTENT_PADDING 31 from eve.client.script.ui.shared.info.shipInfoPanels.panelConst import SHIP_INFO_PANELS, TAB_OVERVIEW, TAB_FITTING, TAB_SKINS 32 from eve.client.script.ui.shared.info.shipInfoPreviewScene import ShipInfoPreviewSceneContainer 33 from inventorycommon.typeHelpers import GetHoloIconPath, GetIconFile 34 from inventorycommon.util import GetSubSystemTypeIDs, IsModularShip, IsSubsystemFlag 35 from inventorycommon.const import flagCargo, flagShipHangar, groupCapsule 36 from inventoryrestrictions import can_view_market_details 37 from carbonui.uicore import uicore 38 from eve.common.script.sys.eveCfg import InShipInSpace 39 from eve.common.script.sys import idCheckers 40 from utillib import KeyVal 41 import shipgroup 42 is_expanded_setting = SessionSettingBool(False) 43 EXPANDED_WIDTH = 640 44 MINIMIZED_ZOOM = 0.1 45 EXPANDED_ZOOM = 0.3 46 MINIMIZED_ZOOM_RANGE = [1.6, 3.5] 47 EXPANDED_ZOOM_RANGE = [1.5, 3.5] 48 MINIMIZED_BG_COLOR = (0, 49 0, 50 0, 51 1) 52 MINIMIZED_BG_OPACITY = 0.9 53 MINIMIZED_POSITION_OVERRIDE = TOP_DOWN_NOSE_UP_ALT 54 LAST_TAB_SETTING = SessionSettingEnum(TAB_OVERVIEW, INFO_TABS) 55 56 class ShipInfoWindowController(object): 57 58 def __init__(self, select_tab, get_ship_length, reset_skin): 59 self._select_tab = select_tab 60 self._get_ship_length = get_ship_length 61 self._skin_controller = None 62 self._type_id = None 63 self._item_id = None 64 self._item = None 65 self._parent_id = None 66 self._abstract_info = None 67 self._owner_id = None 68 self._owner_data = None 69 self._ship_contents = None 70 self._fetching_owner_data = False 71 self._reset_skin = reset_skin 72 73 def set_values(self, type_id, item_id, item, parent_id, abstract_info): 74 self._type_id = type_id 75 self._item_id = item_id 76 self._item = item 77 self._parent_id = parent_id 78 self._abstract_info = abstract_info 79 self._owner_id = self._get_owner_id() 80 self._owner_data = None 81 self._ship_contents = None 82 if self._owner_id and not self.is_owned_by_me: 83 self._fetching_owner_data = True 84 uthread2.start_tasklet(self._update_owner) 85 86 def set_skin_controller(self, skin_controller): 87 self._skin_controller = skin_controller 88 89 def select_tab(self, tab_id): 90 self._select_tab(tab_id) 91 92 def reset_skin(self): 93 self._reset_skin() 94 95 @property 96 def skin_controller(self): 97 return self._skin_controller 98 99 @property 100 def item_id(self): 101 return self._item_id 102 103 @property 104 def item(self): 105 return self._item 106 107 @item.setter 108 def item(self, value): 109 if value: 110 self._item = value 111 112 @property 113 def type_id(self): 114 return self._type_id 115 116 @property 117 def group_id(self): 118 return evetypes.GetGroupID(self.type_id) 119 120 @property 121 def owner_id(self): 122 return self._owner_id 123 124 @property 125 def owner_corporation_id(self): 126 if not self.owner_id: 127 return None 128 if self.is_owned_by_me: 129 return session.corpid 130 owner_data = self.get_owner_data() 131 if owner_data: 132 return owner_data.corpID 133 134 @property 135 def long_axis_length(self): 136 return self._get_ship_length() 137 138 @property 139 def is_assembled(self): 140 return self.item_id == session.shipid or self._item and self._item.singleton 141 142 @property 143 def is_owned_by_me(self): 144 return self.owner_id == session.charid 145 146 @property 147 def is_simulated(self): 148 return self.item_id is not None and isinstance(self.item_id, basestring) 149 150 def get_custom_name(self): 151 if self.owner_id and self.item_id in cfg.evelocations.data: 152 return cfg.evelocations.Get(self.item_id).name 153 154 def get_ship_name(self): 155 return self.get_custom_name() or evetypes.GetName(self.type_id) 156 157 def get_type_name(self): 158 return evetypes.GetName(self.type_id) 159 160 def get_class_name(self): 161 return shipgroup.get_ship_group_name(self.type_id) 162 163 def get_description(self): 164 return evetypes.GetDescription(self.type_id) 165 166 def get_owner_name(self): 167 owner_id = self.owner_id 168 if owner_id: 169 return cfg.eveowners.Get(owner_id).name 170 return '' 171 172 def get_owner_data(self): 173 while self._fetching_owner_data: 174 uthread2.Yield() 175 176 return self._owner_data 177 178 def _get_owner_id(self): 179 if not self.item_id: 180 return 181 if self.item_id == session.shipid: 182 return session.charid 183 if InShipInSpace(): 184 owner_id = sm.GetService('michelle').GetCharIDFromShipID(self.item_id) 185 if owner_id: 186 return owner_id 187 owner_id = None 188 if self._item and self._item.ownerID and self._item.singleton: 189 owner_id = self._item.ownerID 190 elif self._abstract_info: 191 try: 192 owner_id = self._abstract_info.ownerID 193 except: 194 pass 195 196 if owner_id and idCheckers.IsEvePlayerCharacter(owner_id): 197 return owner_id 198 199 def _update_owner(self): 200 self._owner_data = sm.GetService('crimewatchSvc').GetSlimItemDataForCharID(self.owner_id) 201 self._fetching_owner_data = False 202 203 def get_subsystems(self): 204 if not IsModularShip(self.type_id) or not self.item_id: 205 return None 206 if InShipInSpace() and self.item_id != session.shipid: 207 slimItem = sm.GetService('michelle').GetItem(self.item_id) 208 if slimItem and slimItem.modules: 209 return [ type_id for item_id, type_id, flag_id in slimItem.modules if IsSubsystemFlag(flag_id) ] 210 return GetSubSystemTypeIDs(self.item_id, self.type_id) 211 212 def get_ship_contents(self): 213 if self._ship_contents is None or self.item_id == session.shipid: 214 self._ship_contents = self._get_ship_contents() 215 return self._ship_contents 216 217 def _get_ship_contents(self): 218 if self.item_id is None: 219 return [] 220 if session.shipid == self.item_id: 221 shipinfo = sm.GetService('godma').GetItem(self.item_id) 222 if shipinfo is not None and getattr(shipinfo, 'inventory', None) is not None: 223 return shipinfo.inventory.List() 224 if sm.GetService('info').IsItemSimulated(self.item_id): 225 return self._get_simulated_ship_contents() 226 if self.item is None: 227 return [] 228 if not self.item.singleton: 229 return [] 230 if self.item.ownerID == session.charid and self.item.locationID: 231 dockable_location_id = self.item.locationID 232 solar_system_id = None 233 if self.item.flagID in (flagCargo, flagShipHangar): 234 parent_ship_info = GetParentShipInfo(self.item) 235 if parent_ship_info: 236 dockable_location_id, solar_system_id = parent_ship_info 237 inventoryMgr = sm.GetService('invCache').GetInventoryMgr() 238 try: 239 return inventoryMgr.GetContainerContents(self.item.itemID, dockable_location_id, solar_system_id) 240 except AttributeError: 241 pass 242 except RuntimeError as e: 243 if e[0] == 'InvalidLocationID': 244 pass 245 else: 246 raise e 247 248 return [] 249 250 def _get_simulated_ship_contents(self): 251 dogma_location = sm.GetService('clientDogmaIM').GetFittingDogmaLocation() 252 fitted_items = dogma_location.GetFittedItemsToShip() 253 return fitted_items.values() 254 255 def get_fitting_data(self, put_ammo_in_cargo = True): 256 fitting_svc = sm.GetService('fittingSvc') 257 inventory = self.get_ship_contents() 258 fitting = KeyVal() 259 fitting.shipTypeID = self.type_id 260 fitting.fitData = fitting_svc.CreateFittingData(inventory, putModuleAmmoInCargo=put_ammo_in_cargo) 261 fitting.fittingID = None 262 fitting.description = '' 263 shipName = self.get_ship_name() 264 fitting.name = shipName 265 fitting.ownerID = 0 266 return fitting 267 268 def open_simulation(self): 269 fitting_svc = sm.GetService('fittingSvc') 270 fitting = self.get_fitting_data(False) 271 inventory = self.get_ship_contents() 272 charges_to_load = fitting_svc.GetLoadedChargeTypes(inventory) 273 SimulateFitting(fitting, charges_to_load) 274 275 276 class ShipInfoWindow(BaseInfoWindow): 277 __guid__ = 'form.shipinfowindow' 278 __notifyevents__ = [] 279 SIDE_PANEL_WIDTH = 58 280 default_width = 960 281 default_height = 656 282 default_minSize = (325, 450) 283 default_name = 'shipInfoWindow' 284 default_windowID = 'shipInfoWindow' 285 default_iconNum = eveicon.spaceship_command 286 default_scope = uiconst.SCOPE_INGAME 287 default_apply_content_padding = False 288 default_extend_content_into_header = True 289 default_isCompactable = True 290 291 def ApplyAttributes(self, attributes): 292 self._selectedTab = TAB_OVERVIEW 293 self._initialized = False 294 self._current_panel = None 295 self._load_tasklet = None 296 self._live_preview = None 297 self._dynamic_state = 0 298 self._skin_controller = None 299 self._controller = ShipInfoWindowController(select_tab=self.open_tab_by_id, get_ship_length=self._get_ship_length, reset_skin=self._reset_skin) 300 super(ShipInfoWindow, self).ApplyAttributes(attributes) 301 self._dynamic_state = self._get_dynamic_state() 302 self.on_stacked_changed.connect(self._on_stacked_changed_callback) 303 self.on_header_height_changed.connect(self._on_header_height_changed) 304 self._last_tab_setting = LAST_TAB_SETTING 305 306 def Close(self, *args, **kwargs): 307 super(ShipInfoWindow, self).Close(*args, **kwargs) 308 if self._skin_controller: 309 self._skin_controller.Close() 310 311 def _on_header_height_changed(self, *args, **kwargs): 312 self.split_view.padTop = self.sr.headerParent.height 313 314 def OnCompactModeEnabled(self): 315 self.OnResizeUpdate() 316 self._close_live_preview() 317 self._update_preview_display_state() 318 self.split_view.set_force_compact(True) 319 self.side_navigation.set_force_compact(True) 320 321 def OnCompactModeDisabled(self): 322 self.OnResizeUpdate() 323 self._construct_live_preview() 324 self._load_ship() 325 self._update_preview_display_state() 326 self.split_view.set_force_compact(False) 327 self.side_navigation.set_force_compact(False) 328 329 def ConstructLayout(self): 330 self.content.clipChildren = True 331 self.split_view = SideNavigationSplitView(parent=self.content, align=uiconst.TOALL, is_always_expanded_setting=is_expanded_setting, expanded_panel_width=200, padTop=self.sr.headerParent.height, clipChildren=False, force_compact=self.compact) 332 self.side_navigation = ShipInfoSideNavigation(controller=self._controller, parent=self.split_view.panel, is_expanded_func=self.split_view.is_expanded, expand_func=self.split_view.expand_panel, force_compact=self.compact) 333 self.split_view.on_expanded_changed.connect(self.side_navigation.on_expanded_changed) 334 self.mainContent = Container(parent=self.split_view.content, align=Align.TOALL, padding=16) 335 self.previewCont = Container(parent=self.split_view.content, align=Align.TOALL) 336 self.bgFade = Fill(parent=self.content, align=Align.TOALL, state=uiconst.UI_DISABLED, color=MINIMIZED_BG_COLOR, opacity=0, pickState=PickState.OFF, display=not self.compact) 337 self._black_bg = Fill(parent=self.content, align=Align.TOALL, state=uiconst.UI_DISABLED, color=(0, 0, 0, 1), opacity=0.0) 338 self._construct_live_preview() 339 340 def _construct_live_preview(self, forced = False): 341 if self._live_preview or self.compact and not forced: 342 return 343 sceneNavigation = SceneContainerBaseNavigation(name='preview_navigation', parent=self.previewCont, align=Align.TOALL, state=uiconst.UI_NORMAL, pickRadius=0) 344 self._live_preview = ShipInfoPreviewSceneContainer(parent=self.content, align=Align.TOALL, state=uiconst.UI_DISABLED, opacity=0.0) 345 self._live_preview.on_load_complete.connect(self._on_model_load_complete) 346 sceneNavigation.Startup(self._live_preview) 347 self._update_preview_display_state() 348 349 def _close_live_preview(self): 350 if not self._live_preview or self._selectedTab == TAB_SKINS: 351 return 352 self._live_preview.on_load_complete.disconnect(self._on_model_load_complete) 353 self._live_preview.Close() 354 self._live_preview = None 355 self.previewCont.Flush() 356 357 def _ReconstructInfoWindow(self, typeID, itemID = None, rec = None, parentID = None, abstractinfo = None, branchHistory = True, selectTabType = None, params = None): 358 self._initialized = False 359 self._controller.set_values(type_id=typeID, item_id=itemID, item=rec, parent_id=parentID, abstract_info=abstractinfo) 360 if self._skin_controller: 361 self._skin_controller.onChange.disconnect(self._change_skin) 362 self._skin_controller.Close() 363 self._skin_controller = ShipInfoSkinPanelController(itemID=itemID, ownerID=self._controller.owner_id, hullTypeID=typeID) 364 self._skin_controller.onChange.connect(self._change_skin) 365 self._controller.set_skin_controller(self._skin_controller) 366 self.typeID = typeID 367 self.itemID = itemID 368 self.rec = rec 369 self.parentID = parentID 370 self.abstractinfo = abstractinfo 371 self.params = params 372 skin_state = None 373 if params: 374 skin = params.get('skin', None) 375 if skin: 376 skin_state = skin 377 self._load_ship(skin_state) 378 self.groupID = evetypes.GetGroupID(typeID) 379 self.categoryID = evetypes.GetCategoryID(typeID) 380 self.update_window_controls() 381 self._update_caption() 382 visible_tabs = self.get_visible_tabs(typeID, itemID, rec) 383 nav_tabs = [ (tabID, self.get_tab_class_by_type(tabID)) for tabID in visible_tabs ] 384 self.side_navigation.reconstruct(nav_tabs, self._selectedTab) 385 if selectTabType: 386 selectedTabID = selectTabType 387 elif self._current_panel and self._current_panel.is_visible(self.typeID): 388 selectedTabID = self._current_panel.get_tab_type() 389 else: 390 selectedTabID = self._last_tab_setting.get() 391 if selectedTabID not in visible_tabs: 392 selectedTabID = TAB_OVERVIEW 393 self.open_tab_by_id(selectedTabID, params, initialize=True) 394 uthread2.Yield() 395 self._set_dynamic_state(self._get_dynamic_state(), initial=True) 396 self._initialized = True 397 self._do_fade_in() 398 super(ShipInfoWindow, self)._ReconstructInfoWindow(typeID, itemID, rec, parentID, abstractinfo, branchHistory, selectTabType, params) 399 400 def _load_ship(self, skin_state = None): 401 if not self._live_preview: 402 return 403 animations.StopAllAnimations(self._black_bg) 404 self._black_bg.opacity = 1 405 if skin_state is None: 406 skin_state = self._get_skin_state() 407 self._live_preview.preview_ship(self._controller.type_id, subSystems=self._controller.get_subsystems(), skin_state=skin_state, snap=True, skip_animation=False) 408 409 def _on_model_load_complete(self, snap = True, skip_animation = False): 410 if skip_animation or not self._live_preview: 411 return 412 mass = evetypes.GetMass(self.typeID) 413 animDuration = GetAnimDuration(mass) 414 self._live_preview.position_ship(self._get_camera_position(), animDuration, snap, get_sound_by_type_id(self.typeID), GetMassBasedSoundOffset(mass)) 415 self._set_dynamic_state(self._get_dynamic_state(), initial=snap) 416 self._do_fade_in() 417 418 def _update_caption(self): 419 infoObject = u'%s (%s)' % (evetypes.GetName(self.typeID), shipgroup.get_ship_group_name(self.typeID)) 420 caption = localization.GetByLabel('UI/InfoWindow/InfoWindowCaption', infoObject=infoObject) 421 self.SetCaption(caption) 422 423 def GetPanelByTabType(self, tabType): 424 pass 425 426 def GetNeocomGroupLabel(self): 427 return localization.GetByLabel('UI/InfoWindow/ShipInformationNeocomGroup') 428 429 def GetHistoryData(self): 430 return {'typeID': self.typeID, 431 'itemID': self.itemID, 432 'rec': self.rec, 433 'parentID': self.parentID, 434 'abstractinfo': self.abstractinfo, 435 'selectTabType': self.GetSelectedTabIdx()} 436 437 def GetCustomHeaderButtons(self): 438 return [WindowMenuAction(window=self, icon=eveicon.navigate_forward, label=localization.GetByLabel('UI/Control/EveWindow/Next'), callback=self.OnForward, ui_name='ForwardButton', enabled_check=lambda window: window.history.IsForwardEnabled(), importance=WindowActionImportance.content), WindowMenuAction(window=self, icon=eveicon.navigate_back, label=localization.GetByLabel('UI/Control/EveWindow/Previous'), callback=self.OnBack, ui_name='BackButton', enabled_check=lambda window: window.history.IsBackEnabled(), importance=WindowActionImportance.content)] 439 440 def GetMenuMoreOptions(self): 441 menuData = super(ShipInfoWindow, self).GetMenuMoreOptions() 442 if bool(session.role & ROLE_QA): 443 menuData.AddEntry('QA: OPEN OLD WINDOW', self._qa_open_old_window) 444 menuData.extend(GetMenuService().GetMenuFromItemIDTypeID(self.itemID, self.typeID, invItem=self.rec, includeMarketDetails=True).filter([localization.GetByLabel('UI/Commands/ShowInfo'), 'UI/Commands/ShowInfo'])) 445 return menuData 446 447 def GetWindowLinkData(self): 448 if not self._controller.type_id: 449 return [] 450 return ShipDragData(typeID=self._controller.type_id, itemID=self._controller.item_id, ownerID=self._controller.owner_id) 451 452 def OnBack(self, *args): 453 self.UpdateHistoryData(self.GetHistoryData()) 454 infoWndData = self.history.GoBack() 455 if infoWndData: 456 self.ReconstructInfoWindow(branchHistory=False, **infoWndData) 457 458 def OnForward(self, *args): 459 self.UpdateHistoryData(self.GetHistoryData()) 460 infoWndData = self.history.GoForward() 461 if infoWndData: 462 self.ReconstructInfoWindow(branchHistory=False, **infoWndData) 463 464 def get_visible_tabs(self, typeID, itemID = None, rec = None): 465 ret = [] 466 for tabID, panelCls in SHIP_INFO_PANELS.iteritems(): 467 if panelCls.is_visible(typeID, itemID, rec): 468 ret.append(tabID) 469 470 return ret 471 472 def get_tab_class_by_type(self, tabID): 473 if tabID in SHIP_INFO_PANELS: 474 return SHIP_INFO_PANELS[tabID] 475 476 def open_tab_by_id(self, tabID, params = None, initialize = False): 477 panelCls = self.get_tab_class_by_type(tabID) 478 if not panelCls: 479 raise RuntimeError('No class found for tab type {tabID}'.format(tabID=tabID)) 480 if not initialize and not panelCls.is_visible(self.typeID, self.itemID, self.rec): 481 return 482 self._selectedTab = tabID 483 if self._current_panel: 484 self._current_panel.on_reset(initialize) 485 self._last_tab_setting.set(tabID) 486 self.mainContent.Flush() 487 self.side_navigation.set_entry_selected(tabID) 488 self._current_panel = panelCls(parent=self.mainContent, controller=self._controller, params=params, opacity=0) 489 self._set_dynamic_state(self._get_dynamic_state()) 490 if self._dynamic_state == EXPANDED: 491 self._current_panel.show_expanded_view() 492 else: 493 self._current_panel.show_minimized_view(self._dynamic_state == FULLY_MINIMIZED) 494 animations.FadeIn(self._current_panel, duration=0.4) 495 if tabID == TAB_SKINS and not self._live_preview: 496 self._construct_live_preview(True) 497 self._load_ship() 498 self._update_preview_display_state() 499 if self._live_preview and self._live_preview.display: 500 self._live_preview.set_ship_state(tabID) 501 mass = evetypes.GetMass(self.typeID) 502 animDuration = GetAnimDuration(mass) 503 self._live_preview.position_ship(self._get_camera_position(), animDuration, initialize, get_sound_by_type_id(self.typeID), GetMassBasedSoundOffset(mass)) 504 self._update_offset() 505 self._update_zoom(duration=animDuration) 506 507 def _get_skin_state(self): 508 skin_state = self._skin_controller.previewed or self._skin_controller.pending or self._skin_controller.applied 509 return skin_state 510 511 def _change_skin(self): 512 if not self._live_preview: 513 return 514 skin_state = self._get_skin_state() 515 try: 516 if skin_state == self._live_preview.skin_state: 517 return 518 except: 519 pass 520 521 self._live_preview.preview_skin(self.typeID, subSystems=self._controller.get_subsystems(), skin_state=skin_state, skip_repositioning=True, snap=False, skip_animation=True) 522 uthread2.Yield() 523 524 def _reset_skin(self): 525 if not self._live_preview: 526 return 527 self._skin_controller.SetPreviewed(None) 528 self._change_skin() 529 530 def _get_ship_length(self): 531 if not self._live_preview: 532 return 0 533 return self._live_preview.get_bounding_sphere_radius() * 2 534 535 def _get_camera_position(self): 536 if self._current_panel is not None and (self._get_dynamic_state() == EXPANDED or self._selectedTab == TAB_SKINS): 537 return self._current_panel.get_camera_position() 538 return MINIMIZED_POSITION_OVERRIDE 539 540 def _get_dynamic_state(self): 541 _, _, width, _ = self.displayRect 542 if width >= uicore.ScaleDpi(EXPANDED_WIDTH): 543 if self.compact and not self._selectedTab == TAB_SKINS: 544 return MINIMIZED 545 return EXPANDED 546 return MINIMIZED 547 548 def _set_dynamic_state(self, state, initial = False): 549 if self._dynamic_state == state and not initial: 550 return 551 self.mainContent.padding = CONTENT_PADDING[state] 552 is_compact = state == FULLY_MINIMIZED 553 if state == EXPANDED: 554 animations.FadeOut(self.bgFade, duration=0.4) 555 if self._current_panel: 556 self._current_panel.show_expanded_view() 557 elif state == MINIMIZED or is_compact: 558 animations.FadeIn(self.bgFade, endVal=MINIMIZED_BG_OPACITY, duration=0.4) 559 if self._current_panel: 560 self._current_panel.show_minimized_view(is_compact) 561 self.split_view.set_minimized(is_compact) 562 if is_compact: 563 self.hasWindowIcon = False 564 self.on_compact_mode_changed(self) 565 else: 566 self.hasWindowIcon = True 567 self.on_compact_mode_changed(self) 568 self._dynamic_state = state 569 if self._live_preview: 570 mass = evetypes.GetMass(self.typeID) 571 animDuration = GetAnimDuration(mass) 572 self._live_preview.position_ship(self._get_camera_position(), animDuration, initial, get_sound_by_type_id(self.typeID), GetMassBasedSoundOffset(mass)) 573 self._update_offset(initial) 574 self._update_zoom(initial, animDuration) 575 self._update_preview_display_state() 576 577 def OnResizeUpdate(self, *args): 578 state = self._get_dynamic_state() 579 if state != self._dynamic_state: 580 self._set_dynamic_state(state) 581 self._update_offset() 582 583 def _update_preview_display_state(self): 584 display_preview = not self.compact 585 if self.bgFade: 586 self.bgFade.display = display_preview 587 if not self._live_preview: 588 return 589 if self._selectedTab == TAB_SKINS: 590 self.bgFade.display = False 591 self._live_preview.display = True 592 self.previewCont.pickState = PickState.ON 593 else: 594 self._live_preview.display = display_preview 595 self.previewCont.pickState = PickState.ON if display_preview and self._dynamic_state == EXPANDED else PickState.OFF 596 597 def _update_offset(self, initial = False): 598 if self._current_panel is None or not self._live_preview: 599 return 600 centerOffset = 0 601 verticalOffset = 0 602 if self._dynamic_state == EXPANDED: 603 leftIndent = self._current_panel.leftCont.GetAbsoluteSize()[0] / 2 + self.split_view.content.padLeft + self.mainContent.padLeft / 2 + 2 604 previewCenter = self.GetAbsoluteSize()[0] / 2 605 if previewCenter: 606 centerOffset = 1 - float(leftIndent) / previewCenter 607 else: 608 centerOffset = 0 609 elif self._selectedTab == TAB_SKINS: 610 centerOffset = 0 611 else: 612 centerOffset = -1 613 self._live_preview.centerOffset = centerOffset 614 if self._selectedTab == TAB_SKINS and self._dynamic_state != EXPANDED: 615 verticalOffset = -0.6 616 self._live_preview.verticalOffset = verticalOffset 617 618 def _update_zoom(self, initial = False, duration = 0): 619 if self._dynamic_state == EXPANDED: 620 if self._current_panel: 621 target_zoom = self._current_panel.get_zoom() 622 else: 623 target_zoom = EXPANDED_ZOOM 624 elif self._selectedTab == TAB_SKINS: 625 target_zoom = 2 626 else: 627 target_zoom = MINIMIZED_ZOOM 628 if initial: 629 self._live_preview.SetZoom(target_zoom) 630 else: 631 self._live_preview.zoom_to(target_zoom, duration) 632 633 def _on_stacked_changed_callback(self, *args): 634 if self.stacked: 635 self.split_view.padTop = 0 636 else: 637 self.split_view.padTop = 40 638 639 def GetSelectedTabIdx(self): 640 if self._current_panel: 641 return self._current_panel.get_tab_type() 642 return 0 643 644 def _do_fade_in(self): 645 if not self._initialized: 646 return 647 if not self._live_preview or not self._live_preview.loaded: 648 return 649 if self._black_bg.opacity: 650 animations.FadeOut(self._black_bg, duration=0.8, timeOffset=0.1) 651 652 def _qa_open_old_window(self, *args, **kwargs): 653 from eve.client.script.ui.shared.info.infoWindow import InfoWindow 654 import gametime 655 InfoWindow.Open(windowInstanceID=gametime.GetWallclockTime(), typeID=self.typeID, itemID=self.itemID, rec=self.rec, parentID=self.parentID, abstractinfo=self.abstractinfo) 656 657 def OnStartMinimize_(self, *args): 658 if self._live_preview: 659 self._live_preview.Hide() 660 661 def OnStartMaximize_(self, *args): 662 if self._live_preview: 663 self._live_preview.Show() 664 665 666 class ShipInfoSideNavigation(SideNavigation): 667 668 def __init__(self, controller, is_expanded_func, expand_func = None, is_always_expanded_setting = None, **kwargs): 669 super(ShipInfoSideNavigation, self).__init__(is_expanded_func, expand_func, is_always_expanded_setting, **kwargs) 670 self._controller = controller 671 672 def Flush(self): 673 super(ShipInfoSideNavigation, self).Flush() 674 self.bottomControls.Flush() 675 676 def reconstruct(self, tabs, selectedTabID): 677 self.Flush() 678 typeID = self._controller.type_id 679 if can_view_market_details(typeID): 680 self.add_bottom_entry(texturePath=eveicon.market_details, text=localization.GetByLabel('UI/Inventory/ItemActions/ViewTypesMarketDetails'), on_click=self.on_market_button_click) 681 if self._should_show_ship_tree_button(): 682 self.add_bottom_entry(texturePath=eveicon.ship_tree, text=localization.GetByLabel('UI/InfoWindow/ShowInISIS'), on_click=self.on_ship_tree_button_click) 683 if TAB_FITTING in [ tab[0] for tab in tabs ]: 684 if self._controller.is_owned_by_me and self._controller.is_assembled: 685 label = 'UI/Fitting/FittingWindow/SimulateShipFitting' 686 else: 687 label = 'UI/Fitting/FittingWindow/SimulateShip' 688 self.add_bottom_entry(texturePath=eveicon.simulate_fitting, text=localization.GetByLabel(label), on_click=self._on_simulate_button_clicked) 689 self._add_top_entry() 690 for tabID, panelCls in tabs: 691 self.add_entry(entry_id=tabID, text=panelCls.get_name(), icon=panelCls.get_icon(), on_click=self._open_tab) 692 693 def _open_tab(self, tab): 694 self._controller.select_tab(tab.entry_id) 695 696 def _layout_footer(self, main): 697 super(ShipInfoSideNavigation, self)._layout_footer(main) 698 self.bottomControls = ContainerAutoSize(parent=main, align=Align.TOBOTTOM) 699 700 def _construct_background(self): 701 self.panelBackground = Fill(bgParent=self, color=(0, 0, 0), opacity=0) 702 703 def on_expanded_changed(self, expanded, animate = True): 704 super(ShipInfoSideNavigation, self).on_expanded_changed(expanded, animate) 705 duration = 0.2 if animate else 0 706 if not expanded: 707 animations.FadeOut(self.panelBackground, duration=duration) 708 else: 709 animations.FadeIn(self.panelBackground, endVal=0.9, duration=duration) 710 711 def add_bottom_entry(self, texturePath, text, on_click, icon_size = 16): 712 entry = SideNavigationEntry(icon=texturePath, text=text, on_click=on_click, icon_size=icon_size, parent=self.bottomControls, align=Align.TOBOTTOM, icon_color=TextColor.SECONDARY, force_compact=self._force_compact, on_hover=self._on_entry_hover) 713 entry.on_expanded_changed(self.is_expanded_func(), animate=False) 714 self._connect_to_expand(entry) 715 716 def _add_top_entry(self): 717 entry = TopSideNavigationEntry(parent=self._body, controller=self._controller, padBottom=4, on_hover=self._on_entry_hover, force_compact=self._force_compact) 718 entry.on_expanded_changed(self.is_expanded_func(), animate=False) 719 self._connect_to_expand(entry) 720 721 def _on_entry_hover(self, entry): 722 if not self.is_expanded_func() and self.expand_func is not None: 723 self.expand_func(True) 724 725 def _should_show_ship_tree_button(self): 726 return sm.GetService('shipTree').IsInShipTree(self._controller.type_id) 727 728 def on_ship_tree_button_click(self, *args): 729 sm.GetService('shipTreeUI').OpenAndShowShip(self._controller.type_id) 730 731 def on_market_button_click(self, *args): 732 uthread.new(sm.StartService('marketutils').ShowMarketDetails, self._controller.type_id, None) 733 734 def _on_simulate_button_clicked(self, *args, **kwargs): 735 self._controller.open_simulation() 736 737 def set_force_compact(self, force_compact): 738 super(ShipInfoSideNavigation, self).set_force_compact(force_compact) 739 for entry in self.bottomControls.children: 740 if isinstance(entry, SideNavigationEntryInterface): 741 entry.set_force_compact(force_compact) 742 743 def OnMouseEnter(self, *args): 744 super(ShipInfoSideNavigation, self).OnMouseEnter(*args) 745 if not self._force_compact: 746 animations.FadeIn(self.panelBackground, endVal=0.9, duration=0.2) 747 748 def OnMouseExit(self, *args): 749 super(ShipInfoSideNavigation, self).OnMouseExit(*args) 750 animations.FadeOut(self.panelBackground, duration=0.2) 751 752 753 class TopSideNavigationEntry(Container, SideNavigationEntryInterface): 754 default_state = uiconst.UI_NORMAL 755 default_align = Align.TOTOP 756 default_height = 40 757 default_padRight = 10 758 default_bgColor = eveThemeColor.THEME_FOCUSDARK 759 isDragObject = True 760 __notifyevents__ = ['OnSessionChanged'] 761 762 def __init__(self, controller, force_compact = False, on_hover = None, **kwargs): 763 super(TopSideNavigationEntry, self).__init__(**kwargs) 764 self.controller = controller 765 self.character_id = self.controller.owner_id 766 self._force_compact = force_compact 767 self._on_hover = on_hover 768 self._is_interactable = True 769 sm.RegisterNotify(self) 770 type_id = self.controller.type_id 771 text = self.controller.get_owner_name() or self.controller.get_type_name() 772 if self.character_id: 773 subtext = '' 774 else: 775 subtext = self.controller.get_class_name() 776 self._is_interactable = False 777 self.bgFill.opacity = 0 778 content = Container(parent=self, align=Align.TOALL, padding=(4, 2, 4, 2)) 779 icon_container = Container(parent=content, align=Align.CENTERLEFT, width=32, height=32) 780 icon_container.pickState = PickState.OFF 781 if self.character_id: 782 self._construct_owner(self.controller.item_id, icon_container) 783 else: 784 self._consruct_type_icon(type_id, icon_container) 785 self._text_container = Container(parent=content, align=Align.TOALL, padLeft=40, padRight=8, clipChildren=True, opacity=0) 786 text_inner_container = ContainerAutoSize(parent=self._text_container, align=Align.VERTICALLY_CENTERED) 787 self._text = TextBody(parent=text_inner_container, name='character_name_text', align=Align.TOTOP, text=text, maxLines=1, autoFadeSides=16, color=TextColor.SECONDARY) 788 self._subtext = TextDetail(parent=text_inner_container, name='detail_text', align=Align.TOTOP, text=subtext, maxLines=1, autoFadeSides=16, color=TextColor.DISABLED) 789 if self.character_id: 790 uthread2.start_tasklet(self._update_owner_subtext) 791 792 def _update_owner_subtext(self): 793 owner_corporation_id = self.controller.owner_corporation_id 794 if not owner_corporation_id: 795 return 796 corp_info = cfg.eveowners.Get(owner_corporation_id) 797 if corp_info: 798 self._subtext.text = corp_info.name 799 800 def _construct_owner(self, ship_id, icon_container): 801 icon = CharacterPortrait(parent=icon_container, align=Align.CENTER, size=32, character_id=self.character_id, textureSecondaryPath='res:/UI/Texture/circle_full.png', spriteEffect=trinity.TR2_SFX_MODULATE, pickState=PickState.OFF) 802 self.OnClick = icon.OnClick 803 self.GetMenu = icon.GetMenu 804 self.GetDragData = icon.GetDragData 805 if ship_id == session.shipid: 806 Sprite(parent=icon_container, align=Align.CENTER, texturePath='res:/UI/Texture/classes/ShipInfo/circle_outer_34.png', height=34, width=34, color=eveColor.COPPER_OXIDE_GREEN) 807 Frame(bgParent=self, align=Align.TOALL, texturePath='res:/UI/Texture/classes/ShipInfo/portrait_corner_frame_36.png', cornerSize=9, color=TextColor.SUCCESS, outputMode=uiconst.OUTPUT_COLOR_AND_GLOW, glowBrightness=0.3, padding=2) 808 809 def _consruct_type_icon(self, type_id, icon_container): 810 type_icon = GetHoloIconPath(type_id) or GetIconFile(type_id) 811 Sprite(parent=icon_container, align=Align.CENTER, texturePath=type_icon, height=32, width=32, blendMode=trinity.TR2_SBM_ADD, ignoreColorBlindMode=True) 812 Sprite(parent=icon_container, align=Align.CENTER, texturePath='res:/UI/Texture/Shared/windowFrame.png', height=36, width=36, color=TextColor.DISABLED) 813 814 def on_expanded_changed(self, expanded, animate = True): 815 if expanded: 816 self.set_expanded(animate) 817 else: 818 self.set_collapsed(animate) 819 820 def set_expanded(self, animate = True): 821 if animate: 822 eveui.animation.fade_in(self._text_container, duration=0.2) 823 else: 824 self._text_container.opacity = 1.0 825 826 def set_collapsed(self, animate = True): 827 if animate: 828 eveui.animation.fade_out(self._text_container, duration=0.2) 829 else: 830 self._text_container.opacity = 0.0 831 832 def OnMouseEnter(self, *args): 833 super(TopSideNavigationEntry, self).OnMouseEnter(*args) 834 if self._is_interactable: 835 eveui.Sound.button_hover.play() 836 eveui.animation.fade_in(self.bgFill, end_value=0.15, duration=0.05) 837 if self._on_hover: 838 self._on_hover(self) 839 840 def OnMouseExit(self, *args): 841 super(TopSideNavigationEntry, self).OnMouseExit(*args) 842 if self._is_interactable: 843 eveui.animation.fade_out(self.bgFill, duration=0.2) 844 845 def OnSessionChanged(self, _isRemote, _session, change): 846 if not self.character_id or self.character_id != session.charid: 847 return 848 if 'corpid' in change: 849 self._update_owner_subtext() 850 851 def set_force_compact(self, force_compact): 852 self._force_compact = force_compact 853 854 def GetHint(self): 855 if not self._force_compact: 856 return '' 857 title = self._text.text 858 subtitle = self._subtext.text 859 if subtitle: 860 return u'<b>{}</b>\n{}'.format(title, subtitle) 861 else: 862 return title 863 864 def GetTooltipPointer(self): 865 return uiconst.POINT_RIGHT_2 866 867 def GetTooltipDelay(self): 868 if self._force_compact: 869 return 0